all repos — nand2tetris @ aba8a91d9655ef4ca547d4d1eaa7dec05441bdf2

my nand2tetris progress

Add reading assembly from file
x1phosura x1phosura@x1phosura.zone
Mon, 19 Dec 2022 18:28:26 -0800
commit

aba8a91d9655ef4ca547d4d1eaa7dec05441bdf2

parent

aedf3d1b6e094f46428741a07e656f69bc738f7a

1 files changed, 40 insertions(+), 34 deletions(-)

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

@@ -7,9 +7,10 @@

#include "../bindump.h" #define DEBUG(...) printf(__VA_ARGS__) +#define die(err_msg) perror(err_msg); exit(-1) +#define alert(...) fprintf(stderr, __VA_ARGS__) -#define die(err_msg, exit_val) perror(err_msg); exit(exit_val) -#define alert(...) fprintf(stderr, __VA_ARGS__) +#define MAX_LINE_LEN 256 uint32_t myatoi(const char *a_field_str)

@@ -35,12 +36,12 @@ alert("error: A-type instruction doesn't start with @\n");

return false; } - if (line[1] == '\n') { + if (line[1] == '\0') { alert("error: A-type instruction empty after @\n"); return false; } - for (i = 1; (c = line[i]) != '\n' && a < 6; ++i) { + for (i = 1; (c = line[i]) != '\0' && a < 6; ++i) { if ('0' <= c && c <= '9') { if (a > 4) { alert("error: @<number> too long\n");

@@ -72,6 +73,8 @@ }

bool parse_c_type(const char *line, uint16_t *instruction) { + // Note: could do 'jump' fields via lookup tables once + // they're extracted from the line *instruction = 0x8888; // STUB, TODO implement return true; }

@@ -84,7 +87,7 @@ bool ret;

char c; size_t i = 0; - while ((c = line[i]) != '\n') { + while ((c = line[i]) != '\0') { if (c == ' ' || c == '\t') ; // skip any whitespace at start of line else if (c == '@') {

@@ -143,46 +146,49 @@ // comment not found, so attempting to parse instruction

return parse_next_instruction(line, instruction); } -const char *test_lines[] = {"// this is a comment\n", // line 1 - "@12345\n", // line 2 - "\n", // line 3 - "M+1\n", // line 4 - "@98 // test comment\n", // line 5 - "// this is another comment\n", // line 6 - "/ this is a broken comment\n", // line 7 - "D=M;JNE\n", // line 8 - " @1337// immediate comment \n", // line 9 - "\t@44441337 // number too long \n", // line 10 - " \t @1 // 1\n", // line 11 - "\t @2 // 2\n", // line 12 - "\t @3\n", // line 13 - "\t @4\n", // line 14 - " \t@5 // 3\n", // line 15 - " @6 // 4\n", // line 16 - "\t @7\n", // line 17 - " @0x1337 // invalid char in num\n"}; // line 18 -size_t num_test_lines = (sizeof(test_lines) / sizeof(test_lines[0])); + +char *usage_msg = "Usage: assembler1 [path/to/file.asm]\n"; -int main() +int main(int argc, char *argv[]) { - // TODO: read file by lines, parse instructions bool result = false; uint16_t instruction; - size_t test_line_len; + char in_line[MAX_LINE_LEN]; + size_t in_line_len, i, count; + char *in_file_path; + FILE *fp; + + if (argc != 2) { // requires 1 argument + die(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"); + exit(-1); + } + + count = 1; + while (fgets(in_line, MAX_LINE_LEN, fp) != NULL) { + in_line_len = strlen(in_line); - // New organization allows code to eventually work with lines fetched - // from a 'fgets()' loop or something + for (i = 0; i < in_line_len; ++i) { // remove newlines + if (in_line[i] == '\n') { + in_line[i] = '\0'; + break; + } + } - // for testing - for (size_t i = 0; i < num_test_lines; ++i) { - DEBUG("%lu|%s", i+1, test_lines[i]); - test_line_len = strlen(test_lines[i]); - result = parse_line(test_lines[i], test_line_len, &instruction); + DEBUG("%lu|%s\n", count, in_line); + result = parse_line(in_line, in_line_len, &instruction); if (result) { DEBUG("instruction: 0x%x | ", instruction); bindump_word16(instruction); // output instruction as binary putchar('\n'); } + ++count; } return 0;