From b759589e846cb22ff4fe68f062ca5190e15677d7 Mon Sep 17 00:00:00 2001 From: Garritt McCune Date: Tue, 24 Jun 2025 23:48:26 -0500 Subject: [PATCH] Lots of changes and too much dragging my feet on this. But I think this is going in the right direction now. --- Makefile | 2 +- examples/strlen.asm | 37 +++++++++++++ includes/array.h | 6 ++- includes/ast.h | 4 -- includes/keywords.h | 8 +-- includes/opcodes.h | 11 ++-- includes/parser.h | 17 ++++++ includes/token.h | 8 +++ src/array.c | 7 +++ src/ast.c | 0 src/keywords.c | 21 +++++--- src/main.c | 10 +++- src/opcodes.c | 49 +++++++++++------- src/parser.c | 123 ++++++++++++++++++++++++++++++++++++++++++++ src/token.c | 34 ++++++++++++ src/tokenizer.c | 34 +++++++++--- 16 files changed, 320 insertions(+), 51 deletions(-) create mode 100644 examples/strlen.asm delete mode 100644 includes/ast.h create mode 100644 includes/parser.h delete mode 100644 src/ast.c create mode 100644 src/parser.c diff --git a/Makefile b/Makefile index 5e72a44..0b1f34c 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ clean: rm -rf $(BINDIR)/* $(OBJDIR)/* test: - $(BIN) misc/another_test.asm + $(BIN) examples/strlen.asm disass: objdump -S --disassemble $(OBJDIR)/$(FILE).o > $(OBJDIR)/$(FILE).s \ No newline at end of file diff --git a/examples/strlen.asm b/examples/strlen.asm new file mode 100644 index 0000000..577b213 --- /dev/null +++ b/examples/strlen.asm @@ -0,0 +1,37 @@ +namespace string 67; my string namespace here + +word FRAMEBUFFER 0x00200500 + +asciiz Msg "Hello World!" +; fn effectively is an "Append to Namespace" command, ie string + "." + _start +fn _start: + mov FRAMEBUFFER, r32 ; imm, r + mov msg, r1 ; imm, r + call strlen ; result into r2 + mov 0, r4 ; counter + loop: + mov byte [r1], r3 ; read char into r3 + cmp r3, 0 ; NUL byte? + je end + mov byte r3, [r32] ; Write char to frame buffer + inc r32 ; Next space in framebuffer + inc r4 ; inc counter + inc r1 ; inc pointer to msg + jmp loop + end: ;At the moment this just writes Msg to the framebuffer. + ret + +; Clobbers r2, r3 +; Params: r1 - string pointer +; Returns: r2, string length +fn strlen: + mov 0, r2 ; Set the length to zero + loop: + mov byte [r1], r3 ; mov char into r3 + cmp r3, 0 ; NUL byte? + je end + inc r1 ; next char + inc r2 ; length++ + jmp loop + end: + ret \ No newline at end of file diff --git a/includes/array.h b/includes/array.h index 57d37a2..92060f6 100644 --- a/includes/array.h +++ b/includes/array.h @@ -2,15 +2,17 @@ #define ARRAY_H #include +#include typedef struct _array { - int Capacity; - int Size; + size_t Capacity; + size_t Size; void** Items; } Array; Array* ArrayCreate(void); bool ArrayAdd(Array* array, void* item); void* ArrayPeek(Array* array); +void* ArrayIndex(Array* array, size_t index); #endif \ No newline at end of file diff --git a/includes/ast.h b/includes/ast.h deleted file mode 100644 index 157ddd3..0000000 --- a/includes/ast.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef AST_H -#define AST_H - -#endif \ No newline at end of file diff --git a/includes/keywords.h b/includes/keywords.h index bf3bfd5..04870e6 100644 --- a/includes/keywords.h +++ b/includes/keywords.h @@ -2,10 +2,10 @@ #define KEYWORDS_H typedef enum { - FN, ORG, NAMESPACE, DB, CONST -} Keyword; + FUNCTION, NAMESPACE, ASCIIZ, ASCII, WORD, SHORT, BYTE +} Keywords; -int IsKeyword(const char* text, Keyword* keyword); -void GetKeywordText(Keyword keyword, char buffer[16]); +int IsKeyword(const char* text, Keywords* keyword); +void GetKeywordText(Keywords keyword, char buffer[16]); #endif \ No newline at end of file diff --git a/includes/opcodes.h b/includes/opcodes.h index 46dfe97..52fc0a1 100644 --- a/includes/opcodes.h +++ b/includes/opcodes.h @@ -6,17 +6,18 @@ #include typedef enum { - R1 = 0, R2, R3, R4, R5, R6, R7, R8 = 7 + R1 = 1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13, R14, R15, R16, R17, R18, R19, + R20, R21, R22, R23, R24, R25, R26, R27, R28, R29, R30, R31, R32, RBP, RSP, RIP } Registers; typedef enum { 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; +} Mnemonics; -int IsOpcode(const char*, Mnemonic*); +int IsOpcode(const char*, Mnemonics*); int IsRegister(const char*, Registers*); -void GetMnemonicText(Mnemonic mnemonic, char buffer[12]); -void GetRegisterText(Registers reg, char buffer[4]); +void GetMnemonicText(Mnemonics mnemonic, char buffer[12]); +void GetRegisterText(Registers reg, char buffer[5]); #endif \ No newline at end of file diff --git a/includes/parser.h b/includes/parser.h new file mode 100644 index 0000000..c391eb0 --- /dev/null +++ b/includes/parser.h @@ -0,0 +1,17 @@ +#ifndef PARSER_H +#define PARSER_H + +#include +#include +#include "dictionary.h" +#include "opcodes.h" +#include "token.h" +#include "array.h" +#include "keywords.h" + +typedef struct _instruction Instruction; +typedef Array Instructions; + +Instructions* ParseTokens(Array* tokens); + +#endif \ No newline at end of file diff --git a/includes/token.h b/includes/token.h index 4787ea8..984bf2b 100644 --- a/includes/token.h +++ b/includes/token.h @@ -5,12 +5,17 @@ #include #include #include +#include "opcodes.h" +#include "keywords.h" typedef enum { Empty, String, Number, Symbol, + Register, + Mnemonic, + Keyword, LineEnd = '\n', Colon = ':', Comma = ',', @@ -32,6 +37,9 @@ typedef struct _token { char Operator[8]; char* String; int Number; + Mnemonics Mnemonic; + Registers Register; + Keywords Keyword; } Value; int LineNumber; int ColumnNumber; diff --git a/src/array.c b/src/array.c index 2bcdb26..2ec4bc3 100644 --- a/src/array.c +++ b/src/array.c @@ -33,4 +33,11 @@ void* ArrayPeek(struct _array* array) { if (array->Size == 0 || array->Capacity == 0) return NULL; return array->Items[array->Size - 1]; +} + +void* ArrayIndex(Array* array, size_t index) { + if (!array) return NULL; + if (index >= array->Size) return NULL; + + return array->Items[index]; } \ No newline at end of file diff --git a/src/ast.c b/src/ast.c deleted file mode 100644 index e69de29..0000000 diff --git a/src/keywords.c b/src/keywords.c index 6c8a389..751f6ee 100644 --- a/src/keywords.c +++ b/src/keywords.c @@ -1,22 +1,27 @@ #include "../includes/keywords.h" #include -#define KEYWORD_COUNT 5 +#define KEYWORD_COUNT 7 struct _keyword { char* Name; - Keyword Word; + Keywords Word; }; struct _keyword keywords[KEYWORD_COUNT] = { - { "fn", FN }, - { "org", ORG }, + { "fn", FUNCTION }, + //{ "org", ORG }, { "namespace", NAMESPACE }, - { "db", DB }, - { "cosnt", CONST } + { "asciiz", ASCIIZ }, + { "ascii", ASCII }, + { "word", WORD }, + { "short", SHORT }, + { "byte", BYTE } + //{ "db", DB }, + //{ "cosnt", CONST } }; -int IsKeyword(const char* text, Keyword* keyword) { +int IsKeyword(const char* text, Keywords* keyword) { if (!text) return 0; for(unsigned long i = 0; i < KEYWORD_COUNT; i++) { @@ -30,7 +35,7 @@ int IsKeyword(const char* text, Keyword* keyword) { return 0; } -void GetKeywordText(Keyword keyword, char buffer[16]) { +void GetKeywordText(Keywords keyword, char buffer[16]) { if (!buffer) return; memset(buffer, '\0', 16); diff --git a/src/main.c b/src/main.c index b9e271b..e96fabf 100644 --- a/src/main.c +++ b/src/main.c @@ -1,6 +1,8 @@ #include #include "../includes/futil.h" #include "../includes/tokenizer.h" +#include "../includes/opcodes.h" +#include "../includes/parser.h" int main(int argc, char** argv) { char* file; @@ -23,14 +25,15 @@ int main(int argc, char** argv) { Dictionary* variables = DictionaryCreate(); Array* tokens = Tokenize(file, &variables); - + if (tokens->Size == 0) { printf("No tokens\n"); return 0; } - +/* char* buffer; + char type[32]; for(int i = 0; i < tokens->Size; i++) { Token* token = tokens->Items[i]; @@ -41,6 +44,7 @@ int main(int argc, char** argv) { continue; } + //StringifyTokenType(token->Type, type); buffer = TokenStringify(token); if (buffer) { @@ -51,4 +55,6 @@ int main(int argc, char** argv) { } printf("\n"); +*/ + (void) ParseTokens(tokens); } \ No newline at end of file diff --git a/src/opcodes.c b/src/opcodes.c index 1170796..97f51e3 100644 --- a/src/opcodes.c +++ b/src/opcodes.c @@ -3,14 +3,14 @@ #include #include -#define OPCODE_COUNT 34 +#define OPCODE_COUNT 29 struct _instruction { char* Name; - Mnemonic Mnemonic; + Mnemonics Mnemonic; }; -struct _instruction instructions[OPCODE_COUNT] = { +struct _instruction Instructions[OPCODE_COUNT] = { { "add", ADD }, { "sub", SUB }, { "mul", MUL }, @@ -42,32 +42,32 @@ struct _instruction instructions[OPCODE_COUNT] = { { "pop", POP } }; -void GetMnemonicText(Mnemonic mnemonic, char buffer[12]) { +void GetMnemonicText(Mnemonics mnemonic, char buffer[12]) { memset(buffer, '\0', 12); for(int i = 0; i < OPCODE_COUNT; i++) { - if (instructions[i].Mnemonic == mnemonic) { - strncpy(buffer, instructions[i].Name, 11); + if (Instructions[i].Mnemonic == mnemonic) { + strncpy(buffer, Instructions[i].Name, 11); break; } } } -void GetRegisterText(Registers reg, char buffer[4]) { - memset(buffer, '\0', 4); +void GetRegisterText(Registers reg, char buffer[5]) { + memset(buffer, '\0', 5); - if (reg < R1 || reg > R8) return; + if (reg < R1 || reg > R32) return; buffer[0] = 'r'; buffer[1] = reg + 49; } -int IsOpcode(const char* text, Mnemonic* opcode) { +int IsOpcode(const char* text, Mnemonics* opcode) { if (!text) return 0; - for(unsigned long i = 0; i < sizeof(instructions) / sizeof(struct _instruction); i++) { - if (strcmp(instructions[i].Name, text) == 0) { - if (opcode) *opcode = instructions[i].Mnemonic; + for(unsigned long i = 0; i < OPCODE_COUNT; i++) { + if (strcmp(Instructions[i].Name, text) == 0) { + if (opcode) *opcode = Instructions[i].Mnemonic; return 1; } } @@ -79,14 +79,27 @@ int IsRegister(const char* text, Registers* reg) { if (!text) return 0; int length = strlen(text); - Registers r = R8; + Registers r; - if (length != 2) return 0; + if (length < 2 || length > 3) return 0; if (text[0] != 'r') return 0; - if (!isdigit(text[1])) return 0; - - r = text[1] - 0x31; + if (length == 2) { + if (!isdigit(text[1])) return 0; + + r = text[1] - 0x30; + } + else if (strcmp(text, "rbp") == 0) + r = RBP; + else if (strcmp(text, "rsp") == 0) + r = RSP; + else if (strcmp(text, "rip") == 0) + r = RIP; + else { + r = (text[1] - 0x30) * 10; + if (!isdigit(text[2])) return 0; + r += text[2] - 0x30; + } if (reg) *reg = r; diff --git a/src/parser.c b/src/parser.c new file mode 100644 index 0000000..48fe7f7 --- /dev/null +++ b/src/parser.c @@ -0,0 +1,123 @@ +#include "../includes/parser.h" + +#define KEYWORD_COUNT 7 + +static Array* Tokens; + +struct _instruction { + char* Name; + bool IsDirective; + union { + Mnemonics Mnemonic; + Keywords Keyword; + } Value; +}; + +typedef struct parameter { + bool IsRegister; + Registers Register; + unsigned char Width; + uint32_t Offset; +} Parameter; + +size_t ParserIndex = 0; + +Token* ParserAdvance(void); +void ParserIgnoreLine(void); +bool ParserAtEnd(void); +Parameter* ParserExpectParameter(void); +void ParserHandleKeyword(Keywords keyword); +Token* ParserExpect(TokenType type); +Token* ParserWant(TokenType type); +void ParserExpectLineEnd(void); + +Instructions* ParseTokens(Array* tokens) { + Tokens = tokens; + Keywords keyword; + + while(!ParserAtEnd()) { + Token* token = ParserAdvance(); + + switch(token->Type) { + case Keyword: + ParserHandleKeyword(token->Value.Keyword); + break; + default: + break; + } + } +} + +void ParserHandleKeyword(Keywords keyword) { + Token* namespace = NULL; + + switch(keyword) { + case NAMESPACE: + namespace = ParserExpect(Symbol); + + ParserExpectLineEnd(); + + printf("Namespace `%s` seen\n", namespace->Value.String); + break; + default: + break; + } +} + +Token* ParserExpect(TokenType type) { + if (ParserAtEnd()) return NULL; + + Token* token = ParserAdvance(); + + if (!token || token->Type != type) return NULL; + + return token; +} + +Token* ParserWant(TokenType type) { + if (ParserAtEnd()) return NULL; + + Token* token = ParserAdvance(); + + if (!token || token->Type != type) return NULL; + + return token; +} + +void ParserExpectLineEnd(void) { + if (ParserAtEnd()) return; + + Token* token = ParserAdvance(); + + if (token->Type != LineEnd && token->Type != FileEnd) { + //Error / sync + printf("Expected end of line on line %d.\n", token->LineNumber); + + ParserIgnoreLine(); + } + + return; +} + +void ParserIgnoreLine(void) { + while(!ParserAtEnd()) { + Token* token = ParserAdvance(); + + if (token->Type == LineEnd || token->Type == FileEnd) + break; + } +} + +Token* ParserAdvance() { + if (ParserAtEnd()) return (Token*) ArrayPeek(Tokens); + if (ParserIndex == Tokens->Size) return (Token*) ArrayPeek(Tokens); + + Token* next = ArrayIndex(Tokens, ParserIndex); + ParserIndex++; + + return next; +} + +bool ParserAtEnd() { + return ParserIndex >= Tokens->Size; +} \ No newline at end of file diff --git a/src/token.c b/src/token.c index 1331e05..5cf231f 100644 --- a/src/token.c +++ b/src/token.c @@ -14,9 +14,34 @@ struct _token* TokenCreate(TokenType type, int lineNumber, int columnNumber, boo char* TokenStringify(const struct _token* token) { if (!token) return false; + char word[32]; char* buffer = NULL; switch(token->Type) { + case Register: + GetRegisterText(token->Value.Register, word); + + buffer = calloc(sizeof(word), sizeof(char)); + + strncpy(buffer, word, sizeof(word)); + + break; + case Mnemonic: + GetMnemonicText(token->Value.Mnemonic, word); + + buffer = calloc(sizeof(word), sizeof(char)); + + strncpy(buffer, word, sizeof(word)); + + break; + case Keyword: + GetKeywordText(token->Value.Keyword, word); + + buffer = calloc(sizeof(word), sizeof(char)); + + strncpy(buffer, word, sizeof(word)); + + break; case String: case Symbol: buffer = calloc(strlen(token->Value.String) + 1, sizeof(char)); @@ -64,6 +89,15 @@ int StringifyTokenType(TokenType type, char buffer[32]) { case Empty: strncpy(buffer, "", 8); break; + case Register: + strncpy(buffer, "", 8); + break; + case Mnemonic: + strncpy(buffer, "", 8); + break; + case Keyword: + strncpy(buffer, "", 8); + break; case String: strncpy(buffer, "", 8); break; diff --git a/src/tokenizer.c b/src/tokenizer.c index 372f0cc..9420dcf 100644 --- a/src/tokenizer.c +++ b/src/tokenizer.c @@ -1,14 +1,12 @@ #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; +static Array* Tokens; const char* SourceCode; size_t SourceCodeLength = 0; @@ -174,15 +172,37 @@ void TokenizerExpectWord() { wordLength++; } - if (wordLength > 0) { - Token* token = TokenCreate(Symbol, SourceLineNumber, SourceColumnNumber, false); + if (wordLength == 0) return; + + Token* token; + Mnemonics mnemonic; + Registers reg; + Keywords keyword; + + if (IsOpcode(word, &mnemonic)) { + token = TokenCreate(Mnemonic, SourceLineNumber, SourceColumnNumber, true); + + token->Value.Mnemonic = mnemonic; + } + else if (IsRegister(word, ®)) { + token = TokenCreate(Register, SourceLineNumber, SourceColumnNumber, true); + + token->Value.Register = reg; + } + else if (IsKeyword(word, &keyword)) { + token = TokenCreate(Keyword, SourceLineNumber, SourceColumnNumber, true); + + token->Value.Keyword = keyword; + } + else { + token = TokenCreate(Symbol, SourceLineNumber, SourceColumnNumber, false); token->Value.String = calloc(wordLength + 1, sizeof(char)); strncpy(token->Value.String, word, wordLength); - - ArrayAdd(Tokens, token); } + + ArrayAdd(Tokens, token); } void TokenizerExpectString(void) {