-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhack_assembler.c
133 lines (114 loc) · 4.16 KB
/
hack_assembler.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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include "hack_assembler.h"
#include "compiler/compiler.h"
#include <stdlib.h>
// This file implements the "frontend" of the compiler
// Parses the command line arguments and then starts the proper functions
int main(int argc, char **argv) {
// Parse options
bool force = false;
char *source_filename = NULL;
char *output_filename = NULL;
parse_options(argc, argv, &force, &source_filename, &output_filename);
// Try to open source file
FILE *assembly_file = fopen(source_filename, "r");
if (assembly_file == NULL)
error("FILE", "\"%s\" doesn't exist\n", source_filename);
// Open the compiled file
FILE *output_file;
open_compiled_file(assembly_file, source_filename, &output_filename, force,
&output_file);
// Finally start compiling
const bool status = compile_to_file(assembly_file, output_file);
cleanup(assembly_file, output_file, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL);
if (status == true) {
printf("Finished compiling file, output file in %s\n", output_filename);
exit(EXIT_SUCCESS);
}
exit(EXIT_FAILURE);
}
// Opens/Creates compiled file on the write_to variable
// Update output_filename with the actual filename of the file
void open_compiled_file(FILE *assembly_file, const char *source_filename,
char **output_filename, const bool force,
FILE **write_to) {
if (*output_filename == NULL) {
// Copy into a new string source filename
// Reason: We used to output_filename = source_filename
// but it will modify source too
size_t length = strlen(source_filename);
size_t allocation_size = length + 2;
*output_filename = (char *)malloc(allocation_size);
if (*output_filename == NULL) {
cleanup(assembly_file, NULL, NULL, *output_filename, NULL, NULL, NULL,
NULL, NULL, NULL);
error("MEMORY ",
"Failed to allocate %zu bytes for hack_save_file string\n",
allocation_size);
}
*output_filename = strcpy(*output_filename, source_filename);
// Remove .asm from the end of the file if it exists
if (4 < length) {
// Get last 4 characters of hack_save_file (first arg, asm filename)
char to_compare[5];
strncpy(to_compare, *output_filename + length - 4, 4);
to_compare[4] = '\0';
if (strcmp(to_compare, ".asm") == 0) {
// Remove the last 4 characters (.asm)
(*output_filename)[length - 4] = '\0';
}
}
// Add .hack to the filename
strcat(*output_filename, ".hack");
}
// If file already exists and we allow overwriting
if (access(*output_filename, F_OK) != -1 && force == false) {
cleanup(assembly_file, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL);
error("FILE ",
"%s already exists, use the --force flag to overwrite file",
*output_filename);
}
// Create compiled code file
*write_to = fopen(*output_filename, "w");
if (*write_to == NULL) {
cleanup(assembly_file, *write_to, NULL, *output_filename, NULL, NULL, NULL,
NULL, NULL, NULL);
error("FILE ",
"Failed to create file %s maybe a directory doesn't exist...",
*output_filename);
}
}
// Parse options from cmd line args
// Set force, source_filename and output_filename accordingly
void parse_options(int argc, char **argv, bool *force, char **source_filename,
char **output_filename) {
// Options that our compiler takes
struct option long_options[] = {{"force", no_argument, 0, 'f'},
{"input", required_argument, 0, 'i'},
{"output", required_argument, 0, 'o'},
{0, 0, 0, 0}};
// Get options
int opt;
while ((opt = getopt_long(argc, argv, "fi:o:", long_options, NULL)) != -1) {
switch (opt) {
case 'f':
*force = true;
break;
case 'i':
*source_filename = optarg;
break;
case 'o':
*output_filename = optarg;
break;
case '?':
usage(argv[0]);
exit(EXIT_FAILURE);
}
}
// Source filename is required
if (*source_filename == NULL) {
usage(argv[0]);
exit(EXIT_FAILURE);
}
}