From e7350a254fb147a4a6e766403c176e119bfe9ef4 Mon Sep 17 00:00:00 2001 From: Maxwell Jeffress Date: Fri, 17 Jul 2026 12:31:29 +1000 Subject: [PATCH] refactor some things to fix things (maybe) --- src/assembler/assemble.c | 181 +++++++++++++++++++++++---------------- 1 file changed, 108 insertions(+), 73 deletions(-) diff --git a/src/assembler/assemble.c b/src/assembler/assemble.c index 217e3c1..cbc18e0 100644 --- a/src/assembler/assemble.c +++ b/src/assembler/assemble.c @@ -42,6 +42,104 @@ InstructionOpcode stringToInstructionOpcode(const char* string) { exit(1); } +static void processBufferedToken( + char* buf, + size_t bufSize, + Instruction* instruction, + bool* processingInstWord, + uint8_t* processingArgNum +) { + if (*processingInstWord) { + instruction->opcode = stringToInstructionOpcode(buf); + *processingInstWord = false; + return; + } + + if (*processingArgNum >= 3) { + fprintf(stderr, "expecting new line after instruction args, got %s\n", buf); + exit(1); + } + + OperandType type = INSTRUCTION_OPERAND_TYPES[instruction->opcode][*processingArgNum]; + switch (type) { + case OP_NONE: { + fprintf(stderr, "expecting new line after instruction args, got %s\n", buf); + exit(1); + } + case OP_REG: { + if (bufSize > 1) { + fprintf(stderr, "expecting register identifier, got %s\n", buf); + exit(1); + } + switch (buf[0]) { + case 'a': + case 'A': + instruction->operands[*processingArgNum] = REG_A; + break; + case 'b': + case 'B': + instruction->operands[*processingArgNum] = REG_B; + break; + case 'c': + case 'C': + instruction->operands[*processingArgNum] = REG_C; + break; + case 'x': + case 'X': + instruction->operands[*processingArgNum] = REG_X; + break; + case 'y': + case 'Y': + instruction->operands[*processingArgNum] = REG_Y; + break; + case 'z': + case 'Z': + instruction->operands[*processingArgNum] = REG_Z; + break; + case 'r': + case 'R': + instruction->operands[*processingArgNum] = REG_R; + break; + case 'f': + case 'F': + instruction->operands[*processingArgNum] = REG_F; + break; + + default: { + fprintf(stderr, "expecting register identifier, got %s\n", buf); + exit(1); + } + } + break; + } + case OP_IMM4: { + char* endptr; + long value = strtol(buf, &endptr, 0); + if (endptr == (char*)buf) { + fprintf(stderr, "couldn't convert %s to a number\n", buf); + exit(1); + } + if (value < 0 || value > 0xF) { + fprintf(stderr, "%s is out of range for a 4-bit immediate\n", buf); + exit(1); + } + instruction->operands[*processingArgNum] = (Register)value; + break; + } + case OP_IMM16: { + char* endptr; + instruction->immediate = strtol(buf, &endptr, 0); + instruction->hasImm16 = true; + if (endptr == (char*)buf) { + fprintf(stderr, "couldn't convert %s to a number\n", buf); + exit(1); + } + break; + } + } + (*processingArgNum)++; +} + /** * Essentially a lexer for the assembly language. * @param [input] The text to create a program from. NOT the file name @@ -72,80 +170,8 @@ Program createProgramFromText(const char* input) { break; } - if (processingInstWord) { - instruction.opcode = stringToInstructionOpcode(buf); - processingInstWord = false; - } else { - if (processingArgNum >= 3) { - fprintf(stderr, "expecting new line after instruction args, got %s\n", buf); - exit(1); - } - OperandType type = INSTRUCTION_OPERAND_TYPES[instruction.opcode][processingArgNum]; - switch (type) { - case OP_NONE: { - fprintf(stderr, "expecting new line after instruction args, got %s\n", buf); - exit(1); - } - case OP_REG: { - if (bufSize > 1) { - fprintf(stderr, "expecting register identifier, got %s\n", buf); - exit(1); - } - switch (buf[0]) { - case 'a': - case 'A': - instruction.operands[processingArgNum] = REG_A; - break; - case 'b': - case 'B': - instruction.operands[processingArgNum] = REG_B; - break; - case 'c': - case 'C': - instruction.operands[processingArgNum] = REG_C; - break; - case 'x': - case 'X': - instruction.operands[processingArgNum] = REG_X; - break; - case 'y': - case 'Y': - instruction.operands[processingArgNum] = REG_Y; - break; - case 'z': - case 'Z': - instruction.operands[processingArgNum] = REG_Z; - break; - case 'r': - case 'R': - instruction.operands[processingArgNum] = REG_R; - break; - case 'f': - case 'F': - instruction.operands[processingArgNum] = REG_F; - break; + processBufferedToken(buf, bufSize, &instruction, &processingInstWord, &processingArgNum); - default: { - fprintf(stderr, "expecting register identifier, got %s\n", buf); - exit(1); - } - } - break; - } - case OP_IMM16: { - char* endptr; - instruction.immediate = strtol(buf, &endptr, 0); - instruction.hasImm16 = true; - if (endptr == (char*)buf) { - fprintf(stderr, "couldn't convert %s to a number\n", buf); - exit(1); - } - break; - } - } - processingArgNum++; - } - buf[0] = '\0'; bufSize = 0; break; @@ -155,6 +181,9 @@ Program createProgramFromText(const char* input) { // Ignore extra new lines break; } + if (bufSize > 0) { + processBufferedToken(buf, bufSize, &instruction, &processingInstWord, &processingArgNum); + } addInstructionToProgram(&program, instruction); instruction = (Instruction){}; processingInstWord = true; @@ -198,6 +227,12 @@ Program createProgramFromText(const char* input) { current++; if (current >= programLen) { + if (!(processingInstWord && bufSize == 0)) { + if (bufSize > 0) { + processBufferedToken(buf, bufSize, &instruction, &processingInstWord, &processingArgNum); + } + addInstructionToProgram(&program, instruction); + } break; } }