-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmain.placeheld.c
196 lines (172 loc) · 6.09 KB
/
main.placeheld.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
#include <stdio.h>
#include "token.h"
#include "decl.h"
#include "scope.h"
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#include <errno.h>
typedef enum yytokentype token_t;
extern FILE *yyin;
extern int yylex();
extern char *yytext;
extern int last_int_literal;
extern char last_char_literal;
extern char *last_string_literal;
extern struct decl *ast;
extern int yyparse();
char *indent_space(int indents);
int scan_file(char *filename, bool verbose);
int parse_file(char *filename);
void print_ast(struct decl *ast);
int resolve_ast(struct decl *ast, bool verbose);
void process_cl_args(int argc, char** argv, bool* stages, char** to_compile);
/* stages */
int SCAN = 0,
PARSE = 1,
PPRINT = 2,
RESOLVE = 3;
void usage(int return_code, char *called_as){
printf(
"usage: %s [options]\n"
"\n"
"Options:\n"
" -scan <file> Scans <file> and outputs tokens encountered\n"
" -parse <file> Scans <file> quietly and reports whether parse was successful\n"
" -print <file> Scans and parses <file> quietly and outputs a nicely formatted version of the bminor program <file>\n"
" -resolve <file> Scans, parses, and builds AST for program <file> quietly, then resolves all variable references\n"
, called_as);
exit(return_code);
}
int main(int argc, char **argv){
// default values
bool stages[] = {false, false, false, false, false};
char *to_compile = "";
bool run_all = true;
/* process CL args */
process_cl_args(argc, argv, stages, &to_compile);
for(int i = 0; i < 4; i++) run_all = run_all && !stages[i];
/* scan */
if (scan_file(to_compile, stages[SCAN])){
puts("Scan unsuccessful");
return EXIT_FAILURE;
}
else if (stages[SCAN])
puts("Scan successful");
/* parse */
if (stages[PARSE] || stages[PPRINT] || stages[RESOLVE]) {
if (parse_file(to_compile)) {
puts("Parse unsuccessful");
return EXIT_FAILURE;
}
else if (stages[PARSE])
puts("Parse successful");
}
/* print */
if (stages[PPRINT]) { print_ast(ast); puts(""); }
/* resolve */
// if resolve or typecheck or...
if (stages[RESOLVE]){
int err_count = resolve_ast(ast, stages[RESOLVE]);
puts("");
if(err_count){
printf("Encountered %d name resolution error%s\n", err_count, err_count == 1 ? "" : "s");
puts("Name resolution unsuccessful");
return EXIT_FAILURE;
}
else if(stages[RESOLVE]){
puts("Name resolution successful");
}
}
return EXIT_SUCCESS;
}
void process_cl_args(int argc, char **argv, bool *stages, char **to_compile){
for (int i = 1; i < argc; i++){
if (!strcmp("-scan", argv[i])){
stages[SCAN] = true;
}
else if (!strcmp("-parse", argv[i])){
stages[PARSE] = true;
}
else if (!strcmp("-print", argv[i])){
stages[PPRINT] = true;
}
else if (!strcmp("-resolve", argv[i])){
stages[RESOLVE] = true;
}
else if ( !strcmp("-help", argv[i]) || !strcmp("-h", argv[i]) ){
usage(EXIT_SUCCESS, argv[0]);
}
else {
// if we've already assigned the file to compile
if (**to_compile) usage(EXIT_FAILURE, argv[0]);
// shouldn't need to worry about data pointed to going out of scope here since this isn't being assigned to something on the stack
else *to_compile = argv[i];
}
}
}
void print_ast(struct decl *ast){ decl_print_list(ast, 0, ";", "\n"); }
int resolve_ast(struct decl *ast, bool verbose){
struct scope *sc = scope_enter(NULL);
int err_count = decl_resolve(ast, sc, false, verbose);
scope_exit(sc);
return err_count;
}
int parse_file(char *filename){
yyin = fopen(filename, "r");
if(!yyin) {
printf("[ERROR|file] Could not open %s! %s\n", filename, strerror(errno));
return 1;
}
// 0 for success, 1 for failure
int to_return = yyparse();
fclose(yyin);
return to_return;
}
int scan_file(char *filename, bool verbose){
/* Runs the flex-generated scanner on the file with name given by 'filename'
- returns 1 on failure, 0 on success */
/* An array of strings, where token_strs[<token>] = "<token name as str>", where <token> is a value of the enum token_t and <token name as str> is the symbolic name given to <token> in the enum token_t. Substituted by the Makefile via sed, ensuring the array is up to date with token.h */
char* token_strs[] = <token_str_arr_placeholder>;
yyin = fopen(filename, "r");
token_t t = TOKEN_EOF;
if(!yyin) {
printf("[ERROR|file] Could not open %s! %s\n", filename, strerror(errno));
return 1;
}
do {
t = yylex();
int t_str_idx = t - TOKEN_EOF;
if (verbose) {
switch(t){
case SCAN_ERR:
fprintf(stdout, "[ERROR|scan] Invalid token: %s\n", yytext);
break;
case INTERNAL_ERR:
fprintf(stdout, "[ERROR|internal] Internal error: %s (sorry!)\n", strerror(errno));
break;
case IDENT:
printf("%s %s\n", token_strs[t_str_idx], yytext);
break;
case STR_LIT:
printf("%s %s\n", token_strs[t_str_idx], last_string_literal);
break;
case INT_LIT:
printf("%s %d\n", token_strs[t_str_idx], last_int_literal);
break;
case CHAR_LIT:
printf("%s %c\n", token_strs[t_str_idx], last_char_literal);
break;
default:
printf("%s\n", token_strs[t_str_idx]);
break;
}
}
if( t == STR_LIT ) free(last_string_literal);
} while( !(t == TOKEN_EOF || t == SCAN_ERR || t == INTERNAL_ERR) );
fclose(yyin);
return t != TOKEN_EOF;
}
void indent(int indents){
for(int i = 0; i < indents; i++) fputs("\t", stdout);
}