all repos — nand2tetris @ 12d25839d7f116d96cc707c24a1ac01332797f7b

my nand2tetris progress

Parse C-type comp field, improve error logging
x1phosura x1phosura@x1phosura.zone
Sun, 25 Dec 2022 02:14:12 -0800
commit

12d25839d7f116d96cc707c24a1ac01332797f7b

parent

d779bea5b6dad359f8817257386a56f2fa13bc0d

1 files changed, 132 insertions(+), 16 deletions(-)

jump to
M projects/06/assembler1/assembler1.cprojects/06/assembler1/assembler1.c

@@ -6,11 +6,15 @@ #include <string.h>

#include "../bindump.h" -#define DEBUG(...) printf(__VA_ARGS__) +//#define DEBUG(...) printf(__VA_ARGS__) +#define DEBUG(...) #define die(err_msg) perror(err_msg); exit(-1) #define alert(...) fprintf(stderr, __VA_ARGS__) #define MAX_LINE_LEN 256 + +char *g_asm_line; // copy of currently-read line for easy reference +size_t g_asm_line_number; // current line number static uint32_t myatoi(const char *a_field_str)

@@ -76,6 +80,8 @@ */

static bool parse_c_type_dest(const char *dest_line, uint8_t *dest) { size_t len; + char *err_dest_fmt = "syntax error: destination format incorrect\n"; + DEBUG("dest_line: %s\n", dest_line); for (len = 0; dest_line[len] != '='; ++len) {} // read until '='

@@ -84,7 +90,8 @@ if (dest_line[0] == 'A' && dest_line[1] == 'D' &&

dest_line[2] == 'M') { *dest = 0x7; } else { - alert("syntax error: destination format incorrect\n"); + alert("%s", err_dest_fmt); + alert("%lu | %s\n", g_asm_line_number, g_asm_line); return false; } } else if (len == 2) {

@@ -95,7 +102,8 @@ *dest = 0x5;

} else if (dest_line[0] == 'A' && dest_line[1] == 'D') { *dest = 0x6; } else { - alert("syntax error: destination format incorrect\n"); + alert("%s", err_dest_fmt); + alert("%lu | %s\n", g_asm_line_number, g_asm_line); return false; } } else if (len == 1) {

@@ -110,7 +118,8 @@ case 'A':

*dest = 0x4; break; default: - alert("syntax error: destination format incorrect\n"); + alert("%s", err_dest_fmt); + alert("%lu | %s\n", g_asm_line_number, g_asm_line); return false; } } else {

@@ -122,13 +131,115 @@ return true;

} /* returns comp bits 0b0acccccc + * TODO: refactor (especially the error cases, which are too repetitive) */ static bool parse_c_type_comp(const char *comp_line, uint8_t *comp) { size_t len; DEBUG("comp_line: %s\n", comp_line); - *comp = 0x53; // STUB: 0b01010011 + for (len = 0; comp_line[len] == '0' || comp_line[len] == '1' || + comp_line[len] == '-' || comp_line[len] == 'D' || + comp_line[len] == 'A' || comp_line[len] == 'M' || + comp_line[len] == '!' || comp_line[len] == '+' || + comp_line[len] == '&' || comp_line[len] == '|'; ++len) {} + if (len == 1) { // 0 1 D A M + switch (comp_line[0]) { + case '0': *comp = 0x2a; break; // 0 101010 + case '1': *comp = 0x3f; break; // 0 111111 + case 'D': *comp = 0x0c; break; // 0 001100 + case 'A': *comp = 0x30; break; // 0 110000 + case 'M': *comp = 0x70; break; // 1 110000 + default: + alert("syntax error: comp field incorrect value\n"); + return false; + } + } else if (len == 2) { // -1 !D !A !M -D -A -M + if (comp_line[0] == '-') { + switch (comp_line[1]) { + case '1': *comp = 0x3a; break; // 0 111010 + case 'D': *comp = 0x0f; break; // 0 001111 + case 'A': *comp = 0x33; break; // 0 110011 + case 'M': *comp = 0x73; break; // 1 110011 + default: + alert("syntax error: comp field incorrect value\n"); + return false; + } + } else if (comp_line[0] == '!') { + switch (comp_line[1]) { + case 'D': *comp = 0x0d; break; // 0 001101 + case 'A': *comp = 0x31; break; // 0 110001 + case 'M': *comp = 0x71; break; // 1 110001 + default: + alert("syntax error: comp field incorrect value\n"); + return false; + } + } else { + alert("syntax error: comp field incorrect value\n"); + return false; + } + } else if (len == 3) { + if (comp_line[0] == 'D') { + if (comp_line[2] == '1') { // D+1 D-1 + if (comp_line[1] == '+') { + *comp = 0x1f; // 0 011111 + } else if (comp_line[1] == '-') { + *comp = 0x0e; // 0 001110 + } else { + alert("syntax error: comp field " + "incorrect value\n"); + return false; + } + } else { // D+A D+M D-A D-M D&A D&M D|A D|M + if (comp_line[2] == 'M') { + *comp = 0x40; // _1_ 000000 + } else if (comp_line[2] == 'A') { + *comp = 0x00; // _0_ 000000 + } else { + alert("syntax error: comp field " + "incorrect value\n"); + return false; + } + + switch (comp_line[1]) { + case '+': *comp |= 0x02; break; // 000010 + case '-': *comp |= 0x13; break; // 010011 + case '&': *comp |= 0x00; break; // 000000 + case '|': *comp |= 0x15; break; // 010101 + default: + alert("syntax error: comp field " + "incorrect value\n"); + return false; + } + } + } else { + // A+1 M+1 A-1 M-1 A-D M-D + if (comp_line[0] == 'M') { + *comp = 0x40; // _1_ 000000 + } else if (comp_line[0] == 'A') { + *comp = 0x00; // _0_ 000000 + } else { + alert("syntax error: comp field incorrect value\n"); + return false; + } + + if (comp_line[1] == '+' && comp_line[2] == '1') { + *comp |= 0x37; // 1 110111 + } else if (comp_line[1] == '-' && comp_line[2] == '1') { + *comp |= 0x32; // 1 110010 + } else if (comp_line[1] == '-' && comp_line[2] == 'D') { + *comp |= 0x07; // 1 000111 + } else { + alert("syntax error: comp field incorrect value\n"); + return false; + } + } + } else { + alert("syntax error: comp field incorrect length %lu\n", len); + return false; + } + + //*comp = 0x53; // STUB: 0b01010011 return true; }

@@ -206,6 +317,7 @@ }

/* Instruction format: 0b111accccccdddjjj * Assumes line begins with actual instruction (prepended whitespace stripped) + * TODO: eventually just replace all wasteful c-instruction parsing w/ strcmp() */ static bool parse_c_type(const char *line, uint16_t *instruction) {

@@ -230,8 +342,8 @@ dest_start = &line[0]; // start of line

// this 'i+1' might be dangerous! comp_start = &line[i+1]; // after "[dest]=" } else { - alert("syntax error: destination field" - " incorrect length\n"); + alert("syntax error: jump field incorrect " + "length\n"); return false; } } else if (c == ';') {

@@ -349,44 +461,48 @@ char *usage_msg = "Usage: assembler1 [path/to/file.asm]\n";

int main(int argc, char *argv[]) { + DEBUG("DEBUG 1 2 3...\n"); + bool result = false; uint16_t instruction; char in_line[MAX_LINE_LEN]; - size_t in_line_len, i, count; + size_t in_line_len, i, file_line; char *in_file_path; FILE *fp; if (argc != 2) { // requires 1 argument - die(usage_msg); + alert(usage_msg); exit(-1); } in_file_path = argv[1]; fp = fopen(in_file_path, "r"); if (fp == NULL) { - die("failed to open file for reading\n"); + alert("failed to open file for reading\n"); exit(-1); } - count = 1; - while (fgets(in_line, MAX_LINE_LEN, fp) != NULL) { + file_line = 1; + while (fgets(in_line, MAX_LINE_LEN, fp) != NULL) { // parse loop in_line_len = strlen(in_line); for (i = 0; i < in_line_len; ++i) { // remove newlines - if (in_line[i] == '\n') { + if (in_line[i] == '\n') { // TODO handle DOS '\r\n' in_line[i] = '\0'; break; } } - DEBUG("%lu|%s\n", count, in_line); + DEBUG("%lu|%s | ", file_line, in_line); + g_asm_line = in_line; + g_asm_line_number = file_line; result = parse_line(in_line, in_line_len, &instruction); if (result) { - DEBUG("instruction: 0x%x | ", instruction); + DEBUG("instruction: 0x%x | ", instruction); bindump_word16(instruction); // output instruction as binary putchar('\n'); } - ++count; + ++file_line; } return 0;