all repos — nand2tetris @ 044076b7d21c865c7c6a63e8339be2a6067bd3fe

my nand2tetris progress

projects/07/src/vmtranslator.c

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "codewriter.h"
#include "parser.h"
#include "util.h"

#define _DEBUG

char  *file_line;
size_t file_line_no;

// translate: iterate over lines in in_file, translate VM instructions to
// assembly, write to out_file
bool translate(FILE *in_file, FILE *out_file)
{
	char *line, in_line[MAX_LINE_LEN];
	struct vm_instruction_t vm_instr;
	size_t i, line_len;

	write_vm_init(out_file);
	for (i = 0; i < MAX_STATIC_SYMBOLS; ++i)
		static_symbol_map[i] = -1;

	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 {
				vm_instr.line = line;
				vm_instr.line_len = line_len;
				if (!parse_line(&vm_instr))
					return false;
				if (!write_instruction(&vm_instr, out_file))
					return false;
				cleanup_vm_instr(&vm_instr);
			}
		}
	}

	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, out_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)) // TODO check if stdout
		die("failed to close assembly output file\n");

	return 0;
}