From e92f097afeef15735eb93c7a28a18087c65288a0 Mon Sep 17 00:00:00 2001 From: SpookyDervish <78246495+SpookyDervish@users.noreply.github.com> Date: Sun, 21 Dec 2025 09:44:16 +1100 Subject: [PATCH] starting work on assembler --- README.md | 3 +- fib.sasm | 6 ++ fib.vmbl | Bin 1536 -> 1536 bytes sasm | Bin 0 -> 17208 bytes src/asm/assembler.c | 17 ++++++ src/asm/assembler.h | 8 +++ src/asm/instructions.h | 18 ++++++ src/asm/sasm.c | 27 +++++++++ src/asm/tokenize.c | 135 +++++++++++++++++++++++++++++++++++++++-- src/asm/tokenize.h | 25 ++++++++ src/file_utils.c | 46 ++++++++++++++ src/file_utils.h | 9 +++ src/main.c | 26 ++++---- src/vmbl.c | 18 ++++-- src/vmbl.h | 6 +- vmbl | Bin 21720 -> 21592 bytes 16 files changed, 315 insertions(+), 29 deletions(-) create mode 100644 fib.sasm create mode 100644 sasm create mode 100644 src/asm/assembler.c create mode 100644 src/asm/assembler.h create mode 100644 src/asm/instructions.h create mode 100644 src/asm/sasm.c create mode 100644 src/file_utils.c create mode 100644 src/file_utils.h diff --git a/README.md b/README.md index 9e8570a..0764826 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,8 @@ But uhh that's the name of the VM itself, the name of the programming language I made is Sylt, named after the German island. -To compile for Linux: `gcc src/main.c src/vmbl.c src/exception.c src/asm/tokenize.c -o VMBL -O3` +To compile the VM for Linux: `gcc src/main.c src/vmbl.c src/exception.c src/file_utils.c -o vmbl -O3` +To compile SASM for Linux: `gcc src/asm/sasm.c src/asm/tokenize.c src/file_utils.c src/asm/assembler.c -o sasm -O3` ## Syntax ### Example "Hello, World!" Program diff --git a/fib.sasm b/fib.sasm new file mode 100644 index 0000000..e2f3af6 --- /dev/null +++ b/fib.sasm @@ -0,0 +1,6 @@ +push 0 +push 1 +dup 1 +dup 1 +add +jump 2 \ No newline at end of file diff --git a/fib.vmbl b/fib.vmbl index d8dfbeb3ef45c8eb735a2c9dc8c4de154d54d6f2..ba32b6d307919b4e7f4c3055c3df705fc1f11469 100644 GIT binary patch delta 19 bcmZqRY2cY~kd>wD*xUMz7xh^u3UC7eO{)iy delta 19 bcmZqRY2cY~koCy3tBmyS6yOE`Qt1cK diff --git a/sasm b/sasm new file mode 100644 index 0000000000000000000000000000000000000000..8a90e9f347f28b39cab5278b17b8fc0a7063c950 GIT binary patch literal 17208 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 + +void assemble(Tokenizer *tokenizer) { + Token token = getCurrentToken(tokenizer); + while (token.type != TOKEN_EOF) + { + //printf("%s: %s - line %d\n", tokenTypeAsCStr(token.type), token.value, token.line); + + + //free(token.value); + token = getCurrentToken(tokenizer); + + + } + free(token.value); +} \ No newline at end of file diff --git a/src/asm/assembler.h b/src/asm/assembler.h new file mode 100644 index 0000000..8c0b172 --- /dev/null +++ b/src/asm/assembler.h @@ -0,0 +1,8 @@ +#ifndef ASSEMBLER_H +#define ASSEMBLER_H + +#include "tokenize.h" + +void assemble(Tokenizer *tokenizer); + +#endif // !ASSEMBLER_H diff --git a/src/asm/instructions.h b/src/asm/instructions.h new file mode 100644 index 0000000..b3f3729 --- /dev/null +++ b/src/asm/instructions.h @@ -0,0 +1,18 @@ +#ifndef INSTRUCTIONS_H +#define INSTRUCTIONS_H + +#define MAX_ARGS 3 + +typedef enum +{ + ARG_TYPE_INT +} ArgType; + +typedef struct +{ + char *mnemonic, + uint8_t argCount, + ArgType args[MAX_ARGS] +} InstructionInfo; + +#endif // !INSTRUCTIONS_H diff --git a/src/asm/sasm.c b/src/asm/sasm.c new file mode 100644 index 0000000..6d72405 --- /dev/null +++ b/src/asm/sasm.c @@ -0,0 +1,27 @@ +#include +#include +#include "tokenize.h" +#include "../file_utils.h" +#include "assembler.h" + +int main(int argc, char *argv[]) { + if (argc < 3) { + printf("Usage: sasm \n"); + return 0; + } + + char *buffer = readStringFromFile(argv[1]); + + //printf("%s\n", buffer); + Tokenizer tokenizer = { + .source = buffer, + .column = 1, + .line = 1, + .pos = 0 + }; + + assemble(&tokenizer); + free(buffer); + + return 0; +} \ No newline at end of file diff --git a/src/asm/tokenize.c b/src/asm/tokenize.c index b27750a..27040ce 100644 --- a/src/asm/tokenize.c +++ b/src/asm/tokenize.c @@ -1,24 +1,86 @@ #include "tokenize.h" #include #include +#include +#include +/* +Returns a string buffer containing the name that was parsed. +* IMPORTANT: remember to free the buffer when you're done with it! +*/ char *parseName(Tokenizer *tokenizer) { char *ptr = tokenizer->source; + // loop over the string until we hit something that isn't a name int i = 0; while (isName(*ptr++)) { i++; + tokenizer->column++; + tokenizer->pos++; + } - printf("%d\n", i); - return "hi"; + char *buffer = (char*)malloc(sizeof(char) * (i + 1)); // add 1 byte for null terminator + + if (buffer == NULL) { + fprintf(stderr, "SASM: failed to allocate memory\n"); + exit(1); + } + + buffer = strncpy(buffer, tokenizer->source, i); + + tokenizer->source += i; + + return buffer; } +char *parseNumber(Tokenizer *tokenizer) { + int i = 0; + char *ptr = tokenizer->source; + + while (*ptr) + { + if (*ptr == '\n') { + //tokenizer->column = 1; + tokenizer->pos++; + //tokenizer->line++; + break; + } + + if (isspace(*ptr)) + break; + + i++; + tokenizer->column++; + tokenizer->pos++; + *ptr++; + } + + char *buffer = (char*)malloc(sizeof(char) * (i + 1)); // add 1 byte for null terminator + if (buffer == NULL) { + fprintf(stderr, "SASM: failed to allocate memory\n"); + exit(1); + } + + buffer = strncpy(buffer, tokenizer->source, i); + + tokenizer->source += i; + + return buffer; +} + +void parseWhitespace(Tokenizer *tokenizer) { + tokenizer->pos++; + tokenizer->column++; + *tokenizer->source++; + return; +} + bool isNumber(char character) { - return isalnum(character) || character == '.'; + return isdigit(character) || character == '.'; } bool isName(char character) { @@ -26,17 +88,72 @@ bool isName(char character) { } Token getCurrentToken(Tokenizer *tokenizer) { - Token token = (Token){}; + Token token = (Token){ + .line = tokenizer->line, + }; + + if (!*tokenizer->source) { + token.type = TOKEN_EOF; + return token; + } + + switch (*tokenizer->source) { + + case ' ': + parseWhitespace(tokenizer); + return getCurrentToken(tokenizer); + break; + case '\t': + parseWhitespace(tokenizer); + return getCurrentToken(tokenizer); + break; + case '\n': + tokenizer->column = 1; + tokenizer->line++; + tokenizer->pos++; + *tokenizer->source++; + return getCurrentToken(tokenizer); + break; + case '\r': + tokenizer->pos++; + *tokenizer->source++; + return getCurrentToken(tokenizer); + break; + default: - if (isName(*tokenizer->source)) { + if (isalpha(*tokenizer->source)) { char *tokenValue = parseName(tokenizer); + token.value = tokenValue; + + // check if the token is in the list of instruction names + token.type = TOKEN_NAME; // by default the token is a name until we find an instruction + for (int i = 0; i < sizeof(INSTRUCTION_NAMES)/sizeof(INSTRUCTION_NAMES[0]); i++) { + + // if we found an instruction with the same name as the token + if (strcmp(INSTRUCTION_NAMES[i], tokenValue) == 0) { + token.type = TOKEN_INSTRUCTION; + break; + } + + } + } else if (isdigit(*tokenizer->source)) { + char *tokenValue = parseNumber(tokenizer); + token.value = tokenValue; + + // TODO: floating point numbers + token.type = TOKEN_INT_LITERAL; + } else { + fprintf(stderr, "Invalid token `%c` on line %d, column %d\n", *tokenizer->source, tokenizer->line, tokenizer->column); + exit(1); } break; } + + return token; } char* tokenTypeAsCStr(TokenType type) { @@ -49,6 +166,14 @@ char* tokenTypeAsCStr(TokenType type) { case TOKEN_INT_LITERAL: return "INT_LITERAL"; break; + + case TOKEN_EOF: + return ""; + break; + + case TOKEN_NAME: + return "NAME"; + break; default: break; diff --git a/src/asm/tokenize.h b/src/asm/tokenize.h index b2e17ce..1b88c85 100644 --- a/src/asm/tokenize.h +++ b/src/asm/tokenize.h @@ -3,9 +3,30 @@ #include +static char *INSTRUCTION_NAMES[] = { + "push", + "drop", + "add", + "sub", + "mul", + "div", + "eq", + "neq", + "gt", + "gte", + "lt", + "lte", + "dup", + "jc", + "halt", + "jump" +}; + typedef enum { + TOKEN_EOF, // just used when looping over the tokens list TOKEN_INSTRUCTION, + TOKEN_NAME, TOKEN_INT_LITERAL, } TokenType; @@ -13,6 +34,7 @@ typedef struct { TokenType type; char* value; + unsigned int line; } Token; typedef struct @@ -25,9 +47,12 @@ typedef struct bool isNumber(char character); bool isName(char character); + Token getCurrentToken(Tokenizer *tokenizer); char* tokenTypeAsCStr(TokenType type); char *parseName(Tokenizer *tokenizer); +char *parseNumber(Tokenizer *tokenizer); +void parseWhitespace(Tokenizer *tokenizer); #endif // !TOKENIZE_H diff --git a/src/file_utils.c b/src/file_utils.c new file mode 100644 index 0000000..a97c623 --- /dev/null +++ b/src/file_utils.c @@ -0,0 +1,46 @@ +#include "file_utils.h" + +char *readStringFromFile(char* file_path) { + FILE *inputFile = fopen(file_path, "r"); + if (inputFile == NULL) { + perror("SASM: failed to open file"); + exit(1); + } + if (fseek(inputFile, 0, SEEK_END)) { + perror("SASM: failed to seek to end of file"); + fclose(inputFile); + exit(1); + } + long file_size = ftell(inputFile); + if (file_size == -1) { + perror("SASM: error getting file size"); + fclose(inputFile); + exit(1); + } + + if (fseek(inputFile, 0, SEEK_SET) != 0) { + perror("SASM: failed to seek to start of file"); + fclose(inputFile); + exit(1); + } + + char *buffer = (char*)malloc(file_size + 1); + if (buffer == NULL) { + printf("SASM: failed to allocate memory"); + fclose(inputFile); + exit(1); + } + + size_t bytesRead = fread(buffer, 1, file_size, inputFile); + if (bytesRead != file_size) { + perror("SASM: error reading file"); + free(buffer); + fclose(inputFile); + exit(1); + } + fclose(inputFile); + + buffer[file_size+1] = '\0'; + + return buffer; +} \ No newline at end of file diff --git a/src/file_utils.h b/src/file_utils.h new file mode 100644 index 0000000..3fcc83b --- /dev/null +++ b/src/file_utils.h @@ -0,0 +1,9 @@ +#ifndef FILE_UTILS_H +#define FILE_UTILS_H + +#include +#include + +char *readStringFromFile(char* file_path); + +#endif // !FILE_UTILS_H \ No newline at end of file diff --git a/src/main.c b/src/main.c index ab015f4..8d07278 100644 --- a/src/main.c +++ b/src/main.c @@ -5,24 +5,20 @@ #define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])); VMBL_Instruction program[] = { - MAKE_INST_PUSH(124), - MAKE_INST_PUSH(2), - MAKE_INST_DIV, - MAKE_INST_HALT + MAKE_INST_PUSH(0), + MAKE_INST_PUSH(1), + MAKE_INST_DUP(1), + MAKE_INST_DUP(1), + MAKE_INST_ADD, + MAKE_INST_JMP(2) }; int main() { - //VMBL_State vmblState = {}; - - //VMBL_LoadExecutable(&vmblState, program, sizeof(program)); - //VMBL_StartVM(&vmblState); - - Tokenizer tokenizer = { - "push 1224\npush 2\ndiv\nhalt" - }; - Token token = getCurrentToken(&tokenizer); - - printf("%s\n", tokenTypeAsCStr(token.type)); + VMBL_State vmblState = {}; + VMBL_LoadExecutable(&vmblState, program, sizeof(program)); + //VMBL_SaveExecutable("fib.vmbl", program, sizeof(program)); + VMBL_StartVM(&vmblState); + return 0; } \ No newline at end of file diff --git a/src/vmbl.c b/src/vmbl.c index 529b319..c7fe64b 100644 --- a/src/vmbl.c +++ b/src/vmbl.c @@ -1,4 +1,5 @@ #include "vmbl.h" +#include "file_utils.h" #include #include #include @@ -93,6 +94,9 @@ VMBL_Exception VBML_ExecuteInstruction(VMBL_State *vmblState, VMBL_Instruction i break; + case INSTRUCTION_NOP: + break; + default: return (VMBL_Exception) { EXCEPTION_INVALID_OPCODE }; break; @@ -126,7 +130,7 @@ void VMBL_StartVM(VMBL_State *vmblState) { VMBL_Instruction instruction = vmblState->program[vmblState->ip++]; - printf("%s 0x%lx, 0x%lx, 0x%lx\n", instructionTypeToCStr(instruction.type), instruction.opperands[0], instruction.opperands[1], instruction.opperands[2]); + //printf("%s 0x%lx, 0x%lx, 0x%lx\n", instructionTypeToCStr(instruction.type), instruction.opperands[0], instruction.opperands[1], instruction.opperands[2]); VMBL_Exception exception = VBML_ExecuteInstruction(vmblState, instruction); @@ -156,8 +160,8 @@ void VMBL_LoadExecutable(VMBL_State *vmblState, VMBL_Instruction *program, size_ vmblState->programSize = programSize; } -void VMBL_LoadExecutableFromFile(VMBL_State *vmblState, const char* filePath) { - FILE *file = fopen(filePath, "rb"); +void VMBL_LoadExecutableFromFile(VMBL_State *vmblState, char* filePath) { + /*FILE *file = fopen(filePath, "rb"); if (file == NULL) { perror("VMBL: Failed to open file"); @@ -170,11 +174,13 @@ void VMBL_LoadExecutableFromFile(VMBL_State *vmblState, const char* filePath) { size_t programSize = size / sizeof(vmblState->program[0]); VMBL_Instruction program[programSize]; - fread(program, sizeof(program[0]), programSize, file); + fread(program, sizeof(program[0]), programSize, file);*/ - VMBL_LoadExecutable(vmblState, program, programSize); + VMBL_Instruction *program = (VMBL_Instruction*)readStringFromFile(filePath); - fclose(file); + VMBL_LoadExecutable(vmblState, program, sizeof(program)); + + //fclose(file); } diff --git a/src/vmbl.h b/src/vmbl.h index a7d489a..445b2a2 100644 --- a/src/vmbl.h +++ b/src/vmbl.h @@ -14,6 +14,8 @@ typedef int64_t Word; typedef enum { + INSTRUCTION_NOP, + // stack operations INSTRUCTION_PUSH, INSTRUCTION_ADD, @@ -34,7 +36,7 @@ typedef enum INSTRUCTION_LESS_THAN, INSTRUCTION_LESS_THAN_EQUAL, INSTRUCTION_GREATER_THAN, - INSTRUCTION_GREATER_THAN_EQUAL, + INSTRUCTION_GREATER_THAN_EQUAL } InstructionType; typedef struct @@ -77,7 +79,7 @@ void VMBL_Dump(VMBL_State vmblState, VMBL_Exception exception); void VMBL_StartVM(VMBL_State *vmblState); void VMBL_LoadExecutable(VMBL_State *vmblState, VMBL_Instruction *program, size_t programSize); -void VMBL_LoadExecutableFromFile(VMBL_State *vmblState, const char* filePath); +void VMBL_LoadExecutableFromFile(VMBL_State *vmblState, char* filePath); void VMBL_SaveExecutable(const char* filePath, VMBL_Instruction *program, size_t programSize); char *instructionTypeToCStr(InstructionType type); diff --git a/vmbl b/vmbl index b4a7aff5174a7e61dd2a6baa7d58421ab7831548..2f8d27ec74a605e24dd29ea5c9f27fee42c35def 100644 GIT binary patch literal 21592 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 Su2bpXew`t4iABMJvi}3Mcb%&M literal 21720 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 IaG>me0H@*eumAu6