From 42fab467f1847cce32a3d3524384c7fdf0a9641e Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Thu, 16 Jul 2026 13:29:53 +1000 Subject: [PATCH] more assembler stuff --- meson.build | 3 +- src/assembler/assemble.c | 163 ++++++++++++++++++++++++++++++++++++++- src/assembler/assemble.h | 14 ++++ tests/add.asm | 2 + 4 files changed, 180 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 23328d7..fb0eeb3 100644 --- a/meson.build +++ b/meson.build @@ -9,7 +9,8 @@ sources = files( ) asmSources = files( - 'src/assembler/main.c' + 'src/assembler/main.c', + 'src/assembler/assemble.c' ) args = ['-Wall', '-Wextra'] diff --git a/src/assembler/assemble.c b/src/assembler/assemble.c index 99d58e5..90bb02e 100644 --- a/src/assembler/assemble.c +++ b/src/assembler/assemble.c @@ -1,9 +1,170 @@ #include "assemble.h" #include +#include +#include +#include #include "../instruction.h" -void assemble(const char* input, const char* outputFileName) { +// Table of strings to instructions +struct _stringToInstructionOpcodeTable {char* str; InstructionOpcode opcode;} stringToInstructionOpcodeTable[] = { + {"mov", INST_MOV}, + {"mvi", INST_MVI}, + {"add", INST_ADD}, + {"sub", INST_SUB}, + {"load", INST_LOAD}, + {"store", INST_STORE}, + {"and", INST_AND}, + {"or", INST_OR}, + {"xor", INST_XOR}, + {"shf", INST_SHF}, + {"jmp", INST_JMP}, + {"jiz", INST_JIZ}, + {"call", INST_CALL}, + {"ret", INST_RET}, + {"sys", INST_SYS}, + {"hlt", INST_HLT}, +}; +InstructionOpcode stringToInstructionOpcode(const char* string) { + for (size_t i = 0; i < sizeof(stringToInstructionOpcodeTable) / sizeof(struct _stringToInstructionOpcodeTable)); i++) { + if (strcmp(stringToInstructionOpcodeTable[i].str, string) == 0) { + return stringToInstructionOpcodeTable[i].opcode; + } + } + + fprintf(stderr, "Invalid instruction string %s\n", string); + exit(1); +} + +Program newProgram(void) { + Program program = { + .at = malloc(sizeof(Instruction) * 16), + .len = 0, + .capacity = 16 + }; + + if (program.at == NULL) { + fprintf(stderr, "malloc failed while creating new program\n"); + exit(1); + } + return program; +} + +void addInstructionToProgram(Program* program, Instruction inst) { + if (program->at == NULL) { + fprintf(stderr, "unexpected NULL value when adding instruction to program\n"); + exit(1); + } + + if (program->len + 1 >= program->capacity) { + Instruction* tmp = malloc(sizeof(Instruction) * program->capacity * 2); + if (tmp == NULL) { + fprintf(stderr, "malloc failed while expanding program\n"); + exit(1); + } + program->at = tmp; + program->capacity *= 2; + } + + program->at[program->len] = inst; + program->len++; +} + +void freeProgram(Program* program) { + if (program->at != NULL) { + free(program->at); + } + program->capacity = 0; + program->len = 0; +} + +/** + * Essentially a lexer for the assembly language. + * @param [input] The text to create a program from. NOT the file name + * @return A new program, with all instructions from the input + */ +Program createProgramFromText(const char* input) { + Program program = newProgram(); + + char buf[16] = {'\0'}; + size_t bufSize = 0; + size_t programLen = strlen(input); + size_t current = 0; + + bool processingInstWord = true; + uint8_t processingArgNum = 0; + + Instruction currentInst = {}; + + for (;;) { + // scan through until we hit a space, colon or new line + char c = input[current]; + switch (c) { + case ' ': { + if (bufSize == 0) { + // Ignore extra spaces + break; + } + + if (processingInstWord) { + currentInst.opcode = stringToInstructionOpcode(buf); + } else { + if (processingArgNum >= 3) { + fprintf(stderr, "expecting new line after instruction args, got %s\n", buf); + exit(1); + } + OperandType type = INSTRUCTION_OPERAND_TYPES[currentInst.opcode][processingArgNum]; + if (type == OP_NONE) { + fprintf(stderr, "expecting new line after instruction args, got %s\n", buf); + exit(1); + } + } + + buf[0] = '\0'; + bufSize = 0; + break; + } + case '\n': { + if (processingInstWord && bufSize == 0) { + // Ignore extra new lines + break; + } + break; + } + case ':': { + if (!processingInstWord) { + fprintf(stderr, "label must be first word on a new line"); + exit(1); + } + break; + } + case '\t': { + // Ignore tabs + break; + } + case '\r': { + // Ignore Windows specific formatting + break; + } + default: { + buf[bufSize] = c; + buf[bufSize + 1] = '\0'; + bufSize++; + break; + } + } + + current++; + if (current >= programLen) { + break; + } + } + + return program; +} + +void assemble(const char* input, const char* outputFileName) { + Program program = createProgramFromText(input); } diff --git a/src/assembler/assemble.h b/src/assembler/assemble.h index cee9c2a..a17c380 100644 --- a/src/assembler/assemble.h +++ b/src/assembler/assemble.h @@ -1,3 +1,17 @@ #pragma once +#include "../instruction.h" + +typedef struct { + Instruction* at; + size_t len; + size_t capacity; +} Program; + +Program newProgram(void); +void addInstructionToProgram(Program* program, Instruction inst); +void freeProgram(Program* program); + +Program createProgramFromText(const char* input); + void assemble(const char* input, const char* outputFileName); diff --git a/tests/add.asm b/tests/add.asm index c0ee31a..8f6a875 100644 --- a/tests/add.asm +++ b/tests/add.asm @@ -1,3 +1,5 @@ +dingus: + mvi a 2 mvi b 2