Add proj. 7 files, code structure, and line reader
x1phosura x1phosura@x1phosura.zone
Mon, 08 May 2023 02:08:42 -0700
11 files changed,
345 insertions(+),
1 deletions(-)
jump to
M
.gitignore
→
.gitignore
@@ -5,5 +5,5 @@ *.out
# ignore prokect 05 machine code files, project 06 test files, build artifacts projects/05/*.hack -projects/06/bin/* +projects/*/bin/*
A
projects/07/Makefile
@@ -0,0 +1,15 @@
+# nand2tetris chapter 6 VM translator makefile +# for debugging this makefile: `make -d` +CFLAGS = -std=c99 -Wall -Wextra + +all: bin/vmtranslator + +# TODO: clean up, make more Makefile-idiomatic + +bin/vmtranslator: src/vmtranslator.c + $(CC) $(CFLAGS) -o $@ $< + +clean: + rm -vf bin/* + +.PHONY: clean
A
projects/07/src/codewriter.h
@@ -0,0 +1,27 @@
+#ifndef _CODEWRITER_H +#define _CODEWRITER_H + +// 'parser.h' roughly corresponds to the 'Parser' module specified in +// nand2tetris, with a few liberties taken. + +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "parser.h" + +#define DBGLOG printf +//#define DBGLOG(...) +#define MAX_LINE_LEN 256 // TODO need to be redefined here? (remove me) + + +bool write_instruction(struct vm_instruction_t *vm_instr, FILE *fp) +{ + // TODO implement + // STUB! + return true; +} + +#endif // _CODEWRITER_H
A
projects/07/src/parser.h
@@ -0,0 +1,62 @@
+#ifndef _PARSER_H +#define _PARSER_H + +// 'parser.h' roughly corresponds to the 'Parser' module specified in +// nand2tetris, with a few liberties taken. + +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define DBGLOG printf +//#define DBGLOG(...) +#define MAX_LINE_LEN 256 // TODO need to be redefined here? (remove me) + +enum vm_command_t { + C_ARITHMETIC, + C_PUSH, + C_POP, + C_LABEL, + C_GOTO, + C_IF, + C_FUNCTION, + C_RETURN, + C_CALL +}; + +struct vm_instruction_t { + enum vm_command_t cmd; + char *arg1; + uint16_t arg2; + const char *original_vm_line; +}; + + +bool parse_command_type(struct vm_instruction_t *vm_instr) { + return true; // STUB TODO implement +} + +bool parse_arg1(struct vm_instruction_t *vm_instr) { + return true; // STUB TODO implement +} + +bool parse_arg2(struct vm_instruction_t *vm_instr) { + return true; // STUB TODO implement +} + +bool parse_line(const char *line, struct vm_instruction_t *vm_instr) +{ + vm_instr->original_vm_line = line; + DBGLOG("// %s\n", vm_instr->original_vm_line); + if (!parse_command_type(vm_instr)) + return false; + if (!parse_arg1(vm_instr)) + return false; + if (!parse_arg2(vm_instr)) + return false; + return true; +} + +#endif // _PARSER_H
A
projects/07/src/vmtranslator.c
@@ -0,0 +1,113 @@
+#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "parser.h" +#include "codewriter.h" + +#define _DEBUG + +#ifdef _DEBUG +#define DBGLOG printf +#else +#define DBGLOG(...) +#endif + +#define err(...) (fprintf(stderr, __VA_ARGS__), \ + fprintf(stderr, "%lu | %s\n", file_line_no, file_line), false) +#define die(...) do { fprintf(stderr, __VA_ARGS__); exit(-1); } while (0) + +#define is_symbol_char(c) (('0' <= c && c <= '9') || ('A' <= c && c <= 'Z') \ + || ('a' <= c && c <= 'z') || c == '_' || c == '.' \ + || c == '$' || c == ':') +#define is_whitespace(c) ((c == ' ' || c == '\t' || c == '\n' || c == '\r')) +#define is_number(c) (('0' <= c && c <= '9')) + +#define MAX_LINE_LEN 256 // TODO: in/excludes NULL terminator? +#define MAX_SYMBOL_LEN MAX_LINE_LEN - 2 + 1 // + 1 for NULL terminator + +char *file_line; // reference to currently-read line (for convenience) +size_t file_line_no; // line number, regardless of line content + + +static size_t skip_whitespace(const char *line, size_t n) +{ + size_t i; + for (i = 0; is_whitespace(line[i]) && i < n; ++i); + return i; +} + +bool translate(FILE *in_file) +{ + char *line, in_line[MAX_LINE_LEN], *translated; + struct vm_instruction_t vm_instr; + size_t i, line_len; + + file_line_no = 0; + //instruction_offset = 0; // TODO: unnecessary? + while (fgets(in_line, MAX_LINE_LEN, in_file) != NULL) { // parse loop + ++file_line_no; + file_line = in_line; + line = &in_line[skip_whitespace(in_line, MAX_LINE_LEN)]; + + line_len = 0; + for (i = 0; line[i] != '\0'; ++i) { + if (line[i] == '\n' || line[i] == '\r') { + line[i] = '\0'; // remove newlines + break; + } + ++line_len; // get line length + } + + if (line_len == 0) // "empty" line + continue; + if (line_len > 1) { + if (line[0] == '/' && line[1] == '/') { // if comment + continue; + } else { + // parser will error specifically (TODO remove me) + if (!parse_line(line, &vm_instr)) + return false; + if (!write_instruction(&vm_instr, in_file)) + return false; + } + } + } + + return true; +} + + +char *usage_msg = "Usage: vmtranslator [input/file.vm] [translated/output]\n" + " vmtranslator [input/file.vm] # output to STDOUT\n"; + +int main(int argc, char *argv[]) +{ + FILE *in_file, *out_file; + if (argc == 2) { + out_file = stdout; + } else if (argc == 3) { + out_file = fopen(argv[2], "wb"); + if (out_file == NULL) + die("failed to open %s for writing\n", argv[2]); + } else { + die(usage_msg); + } + + in_file = fopen(argv[1], "r"); // read input file + if (in_file == NULL) + die("failed to open %s for reading\n", argv[1]); + + if(!translate(in_file)) // first pass + die("failed to translate VM code in file\n"); + + if (fclose(in_file)) + die("failed to close VM file\n"); + if (fclose(out_file)) + die("failed to close assembly output file\n"); + + return 0; +} +
A
projects/07/test/MemoryAccess/BasicTest/BasicTest.vm
@@ -0,0 +1,31 @@
+// This file is part of www.nand2tetris.org +// and the book "The Elements of Computing Systems" +// by Nisan and Schocken, MIT Press. +// File name: projects/07/MemoryAccess/BasicTest/BasicTest.vm + +// Executes pop and push commands using the virtual memory segments. +push constant 10 +pop local 0 +push constant 21 +push constant 22 +pop argument 2 +pop argument 1 +push constant 36 +pop this 6 +push constant 42 +push constant 45 +pop that 5 +pop that 2 +push constant 510 +pop temp 6 +push local 0 +push that 5 +add +push argument 1 +sub +push this 6 +push this 6 +add +sub +push temp 6 +add
A
projects/07/test/MemoryAccess/PointerTest/PointerTest.vm
@@ -0,0 +1,22 @@
+// This file is part of www.nand2tetris.org +// and the book "The Elements of Computing Systems" +// by Nisan and Schocken, MIT Press. +// File name: projects/07/MemoryAccess/PointerTest/PointerTest.vm + +// Executes pop and push commands using the +// pointer, this, and that segments. +push constant 3030 +pop pointer 0 +push constant 3040 +pop pointer 1 +push constant 32 +pop this 2 +push constant 46 +pop that 6 +push pointer 0 +push pointer 1 +add +push this 2 +sub +push that 6 +add
A
projects/07/test/MemoryAccess/StaticTest/StaticTest.vm
@@ -0,0 +1,17 @@
+// This file is part of www.nand2tetris.org +// and the book "The Elements of Computing Systems" +// by Nisan and Schocken, MIT Press. +// File name: projects/07/MemoryAccess/StaticTest/StaticTest.vm + +// Executes pop and push commands using the static segment. +push constant 111 +push constant 333 +push constant 888 +pop static 8 +pop static 3 +pop static 1 +push static 3 +push static 1 +sub +push static 8 +add
A
projects/07/test/StackArithmetic/SimpleAdd/SimpleAdd.vm
@@ -0,0 +1,9 @@
+// This file is part of www.nand2tetris.org +// and the book "The Elements of Computing Systems" +// by Nisan and Schocken, MIT Press. +// File name: projects/07/StackArithmetic/SimpleAdd/SimpleAdd.vm + +// Pushes and adds two constants. +push constant 7 +push constant 8 +add
A
projects/07/test/StackArithmetic/StackTest/StackTest.vm
@@ -0,0 +1,45 @@
+// This file is part of www.nand2tetris.org +// and the book "The Elements of Computing Systems" +// by Nisan and Schocken, MIT Press. +// File name: projects/07/StackArithmetic/StackTest/StackTest.vm + +// Executes a sequence of arithmetic and logical operations +// on the stack. +push constant 17 +push constant 17 +eq +push constant 17 +push constant 16 +eq +push constant 16 +push constant 17 +eq +push constant 892 +push constant 891 +lt +push constant 891 +push constant 892 +lt +push constant 891 +push constant 891 +lt +push constant 32767 +push constant 32766 +gt +push constant 32766 +push constant 32767 +gt +push constant 32766 +push constant 32766 +gt +push constant 57 +push constant 31 +push constant 53 +add +push constant 112 +sub +neg +and +push constant 82 +or +not