diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5e72a44 --- /dev/null +++ b/Makefile @@ -0,0 +1,41 @@ +CC = gcc +CFLAGS=-g -Wall -DDEBUG -Wpedantic -Wextra -Wunused-result -std=c99 -pedantic-errors +SRCDIR=src +OBJDIR=obj +SRCS=$(wildcard $(SRCDIR)/*.c) +# Substitute all .c with .o from SRCS +OBJS=$(patsubst $(SRCDIR)/%.c, $(OBJDIR)/%.o, $(SRCS)) + +BINDIR=bin +BIN=$(BINDIR)/assm + +all: $(BIN) + +release: CFLAGS=-Wall -Wpedantic -std=c99 -pedantic-errors -O2 +release: clean +release: $(BIN) + +$(BIN): $(OBJS) $(BINDIR) + $(CC) $(CFLAGS) $(OBJS) -o $@ + +$(OBJDIR)/%.o: $(SRCDIR)/%.c $(OBJDIR) + $(CC) $(CFLAGS) -c $< -o $@ + +$(BINDIR): + mkdir $@ + +$(OBJDIR): + mkdir $@ + +.PHONY: clean +.PHONY: test +.PHONY: disass + +clean: + rm -rf $(BINDIR)/* $(OBJDIR)/* + +test: + $(BIN) misc/another_test.asm + +disass: + objdump -S --disassemble $(OBJDIR)/$(FILE).o > $(OBJDIR)/$(FILE).s \ No newline at end of file diff --git a/includes/array.h b/includes/array.h new file mode 100644 index 0000000..eeacbd2 --- /dev/null +++ b/includes/array.h @@ -0,0 +1,13 @@ +#ifndef ARRAY_H +#define ARRAY_H + +typedef struct _array { + int Capacity; + int Size; + void** Items; +} Array; + +Array* ArrayCreate(void); +int ArrayAdd(Array* array, void* item); + +#endif \ No newline at end of file diff --git a/includes/opcodes.h b/includes/opcodes.h index f3b9b05..46dfe97 100644 --- a/includes/opcodes.h +++ b/includes/opcodes.h @@ -10,13 +10,13 @@ typedef enum { } Registers; typedef enum { - ADD = 0x01, SUB, MUL, DIV, MOV, AND, OR, XOR, NOT, SHL, SHR, NOP, CMP, JMP, JG, JL, - OUTB, INB, HLT, ENI, INT, LIVT, PUSHA, POPA, CALL, RET, PUSH, POP + ADD = 0x01, SUB, MUL, DIV, MOV, AND, OR, XOR, NOT, SHL, SHR, NOP, CMP, JMP, JZ, JG, JL, + OUTB, INB, HLT, CLI, ENI, INT, LIVT, PUSHA, POPA, CALL, RET, PUSH, POP } Mnemonic; int IsOpcode(const char*, Mnemonic*); int IsRegister(const char*, Registers*); void GetMnemonicText(Mnemonic mnemonic, char buffer[12]); -void GetRegisterText(Registers reg, char buffer[3]); +void GetRegisterText(Registers reg, char buffer[4]); #endif \ No newline at end of file diff --git a/includes/token.h b/includes/token.h index 0c2af4b..7a24cd1 100644 --- a/includes/token.h +++ b/includes/token.h @@ -1,11 +1,17 @@ #ifndef TOKEN_H #define TOKEN_H -enum TokenType { +#include +#include +#include +#include + +typedef enum { Empty, String, Number, Symbol, + LineEnd = '\n', Plus = '+', Minus = '-', Star = '*', @@ -13,23 +19,25 @@ enum TokenType { Carot = '^', OpenParen = '(', CloseParen = ')', + OpenBracket = '[', + CloseBracket = ']', FileEnd -}; +} TokenType; typedef struct _token { TokenType Type; - char* Name; union { + char Operator[8]; char* String; int Number; } Value; int LineNumber; int ColumnNumber; - int Index; - int Length; - int Resolved; + bool Resolved; } Token; -Token* TokenCreate(char* name, TokenType type, int lineNumber, int columnNumber, int index, int length, int resolved); +Token* TokenCreate(TokenType type, int lineNumber, int columnNumber, bool resolved); +char* TokenStringify(const Token* token, bool valueOnly); +int StringifyTokenType(TokenType type, char buffer[32]); #endif \ No newline at end of file diff --git a/includes/tokenizer.h b/includes/tokenizer.h new file mode 100644 index 0000000..0d16edb --- /dev/null +++ b/includes/tokenizer.h @@ -0,0 +1,10 @@ +#ifndef TOKENIZER_H +#define TOKENIZER_H + +#include "array.h" +#include "dictionary.h" +#include "token.h" + +Array* Tokenize(const char* text, Dictionary** variables); + +#endif \ No newline at end of file diff --git a/src/array.c b/src/array.c new file mode 100644 index 0000000..446f5a3 --- /dev/null +++ b/src/array.c @@ -0,0 +1,28 @@ +#include "../includes/array.h" +#include + +#define ARRAY_DEFAULT_CAPACITY 32 + +struct _array* ArrayCreate(void) { + struct _array* array = calloc(1, sizeof(Array)); + + array->Items = calloc(ARRAY_DEFAULT_CAPACITY, sizeof(void*)); + array->Capacity = ARRAY_DEFAULT_CAPACITY; + + return array; +} + +int ArrayAdd(struct _array* array, void* item) { + if (!array) return 0; + + if (array->Size == array->Capacity) { + array->Items = realloc(array->Items, array->Capacity * 2 * sizeof(void*)); + + array->Capacity *= 2; + } + + array->Items[array->Size] = item; + array->Size++; + + return 1; +} \ No newline at end of file diff --git a/src/dictionary.c b/src/dictionary.c index 0c8f940..047d0db 100644 --- a/src/dictionary.c +++ b/src/dictionary.c @@ -32,8 +32,10 @@ KeyValPair* KeyValPairCreate(const char* key, void* value) { int DictionaryAdd(struct _dictionary* dict, const char* key, void* value) { if (!dict) return 0; - if (dict->Size = dict->Capacity) { + if (dict->Size == dict->Capacity) { dict->Pairs = realloc(dict->Pairs, sizeof(KeyValPair*) * dict->Capacity * 2); + + dict->Capacity *= 2; } dict->Pairs[dict->Size] = KeyValPairCreate(key, value); diff --git a/src/main.c b/src/main.c index 07d2934..8110720 100644 --- a/src/main.c +++ b/src/main.c @@ -1,10 +1,13 @@ #include #include "../includes/futil.h" +#include "../includes/tokenizer.h" int main(int argc, char** argv) { char* file; size_t count; + //gcc -o test src/main.c src/futil.c src/dictionary.c src/tokenizer.c src/token.c src/array.c -g + if (argc <= 1) { printf("Usage: assm \n"); @@ -17,5 +20,20 @@ int main(int argc, char** argv) { return 1; } - printf(file); + Dictionary* variables = DictionaryCreate(); + + Array* tokens = Tokenize(file, &variables); + + if (tokens->Size == 0) { + printf("No tokens\n"); + + return 0; + } + else printf("Found %d tokens.", tokens->Size); + + for(int i = 0; i < tokens->Size; i++) { + Token* token = tokens->Items[i]; + + printf(TokenStringify(token, false)); + } } \ No newline at end of file diff --git a/src/token.c b/src/token.c new file mode 100644 index 0000000..4d2a35a --- /dev/null +++ b/src/token.c @@ -0,0 +1,85 @@ +#include "../includes/token.h" + +struct _token* TokenCreate(TokenType type, int lineNumber, int columnNumber, bool resolved) { + struct _token* token = calloc(1, sizeof(Token)); + + token->Type = type; + token->LineNumber = lineNumber; + token->ColumnNumber = columnNumber; + token->Resolved = resolved; + + return token; +} + +char* TokenStringify(const struct _token* token, bool valueOnly) { + if (!token) return NULL; + char type[32]; + char number[32]; + + int length = StringifyTokenType(token->Type, type); + + char* result = calloc(512, sizeof(char)); + #ifdef DEBUG + + #endif + + switch(token->Type) { + case Empty: + snprintf(result, length + 1, "%s ", type); + break; + case String: + snprintf(result, 511, "%s \"%s\" ", type, token->Value.String); + break; + case Number: + snprintf(number, 32, "%d", token->Value.Number); + snprintf(result, 511, "%s %s", type, number); + break; + case Symbol: + snprintf(result, 511, "%s %s", type, token->Value.String); + break; + case LineEnd: + snprintf(result, 511, "%s\n", type); + break; + case FileEnd: + snprintf(result, length + 1, "%s ", type); + break; + default: + //snprintf(buffer, length, "<%c>", type); + break; + } + + return result; +} + +int StringifyTokenType(TokenType type, char buffer[32]) { + if (!buffer) return 0; + + memset(buffer, '\0', 32); + + switch(type) { + case Empty: + strncpy(buffer, "", 8); + break; + case String: + strncpy(buffer, "", 8); + break; + case Number: + strncpy(buffer, "", 8); + break; + case Symbol: + strncpy(buffer, "", 8); + break; + case LineEnd: + strncpy(buffer, "", 8); + break; + case FileEnd: + strncpy(buffer, "", 8); + break; + default: + snprintf(buffer, 8, "<%c >", type); + + break; + } + + return 8; +} \ No newline at end of file diff --git a/src/tokenizer.c b/src/tokenizer.c new file mode 100644 index 0000000..cbd0e9c --- /dev/null +++ b/src/tokenizer.c @@ -0,0 +1,134 @@ +#include "../includes/tokenizer.h" +#include "../includes/keywords.h" +#include "../includes/string_builder.h" +#include +#include +#include + +#define MAXWORDLENGTH 1024 + +//char Word[MAXWORDLENGTH] = { 0 }; +Array* Tokens; + +const char* SourceCode; +size_t SourceCodeLength = 0; +size_t SourceCodeIndex = 0; +int SourceLineNumber = 0; +int SourceColumnNumber = 0; + +bool TryPeekTokenizer(char* c); +bool TryPopTokenizer(char* c); +bool TokenizerAtEnd(void); +char AdvanceTokenizer(void); +bool BackTokenzier(void); +char TokenizerLookAhead(void); + +void TokenizerExpectWord(void); +void TokenizerIgnoreLine(void); + +Array* Tokenize(const char* sourceCode, Dictionary** variables) { + Tokens = ArrayCreate(); + + SourceCodeLength = strlen(sourceCode) - 1; + SourceCode = sourceCode; + + while(!TokenizerAtEnd()) { + char c; + + if (!TryPeekTokenizer(&c)) break; + + if (isalpha(c)) { + TokenizerExpectWord(); + + continue; + } + + if (c == ';') { + TokenizerIgnoreLine(); + + continue; + } + + AdvanceTokenizer(); + } + + ArrayAdd(Tokens, TokenCreate(FileEnd, SourceLineNumber + 1, 0, true)); + + return Tokens; +} + +void TokenizerExpectWord() { + char word[256] = { 0 }; + int wordLength = 0; + char c; + + while(TryPopTokenizer(&c)) { + if (isspace(c)) { + break; + } + + if (ispunct(c)) { + BackTokenzier(); + + break; + } + + if (wordLength == 255) break; //Sync, error etc here at some point. + + word[wordLength] = c; + wordLength++; + } + + if (wordLength > 0) { + Token* token = TokenCreate(Symbol, SourceLineNumber, SourceColumnNumber, false); + + token->Value.String = calloc(wordLength + 1, sizeof(char)); + + strncpy(token->Value.String, word, wordLength); + + ArrayAdd(Tokens, token); + } +} + +void TokenizerIgnoreLine(void) { + char c; + + while(TryPopTokenizer(&c)) { + if (c == '\n') break; + } +} + +bool TryPeekTokenizer(char* c) { + *c = SourceCode[SourceCodeIndex]; + + return *c != '\0'; +} + +bool TryPopTokenizer(char* c) { + *c = AdvanceTokenizer(); + + return *c != '\0'; +} + +char AdvanceTokenizer() { + if (TokenizerAtEnd()) return '\0'; + if (SourceCodeIndex + 1 > SourceCodeLength) return '\0'; + + char c = SourceCode[SourceCodeIndex]; + + SourceCodeIndex++; + + return c; +} + +bool BackTokenzier(void) { + if (SourceCodeIndex == 0) return false; + + SourceCodeIndex--; + + return true; +} + +bool TokenizerAtEnd() { + return SourceCodeLength == SourceCodeIndex; +} \ No newline at end of file