diff options
author | Bad Diode <bd@badd10de.dev> | 2021-10-22 09:59:31 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2021-10-22 09:59:31 +0200 |
commit | eeff5e273f22aa28e81ab080e9ffdce85ac394b8 (patch) | |
tree | 71d11c76be7c0bb649099bb55e6181f9b7c6c8a8 /src/bootstrap/main.c | |
parent | 5bd694fc7071bfb76b9f65c89d253b2b4e18cf63 (diff) | |
download | bdl-eeff5e273f22aa28e81ab080e9ffdce85ac394b8.tar.gz bdl-eeff5e273f22aa28e81ab080e9ffdce85ac394b8.zip |
Prepare skeleton for bytecode interpreter
Diffstat (limited to 'src/bootstrap/main.c')
-rwxr-xr-x | src/bootstrap/main.c | 288 |
1 files changed, 0 insertions, 288 deletions
diff --git a/src/bootstrap/main.c b/src/bootstrap/main.c deleted file mode 100755 index a5888fd..0000000 --- a/src/bootstrap/main.c +++ /dev/null | |||
@@ -1,288 +0,0 @@ | |||
1 | #include <assert.h> | ||
2 | #include <getopt.h> | ||
3 | #include <stdbool.h> | ||
4 | #include <stdint.h> | ||
5 | #include <stdio.h> | ||
6 | #include <stdlib.h> | ||
7 | #include <string.h> | ||
8 | |||
9 | #include "darray.h" | ||
10 | #include "hashtable.h" | ||
11 | |||
12 | #include "singletons.c" | ||
13 | |||
14 | #include "environment.c" | ||
15 | #include "errors.c" | ||
16 | #include "gc.c" | ||
17 | #include "lexer.c" | ||
18 | #include "objects.c" | ||
19 | #include "parser.c" | ||
20 | #include "primitives.c" | ||
21 | #include "read_line.c" | ||
22 | #include "string_view.c" | ||
23 | |||
24 | void | ||
25 | init(void) { | ||
26 | // Initialize garbage collector. | ||
27 | gc_init(); | ||
28 | |||
29 | // Initialize singletons. | ||
30 | obj_nil = alloc_object(OBJ_TYPE_NIL); | ||
31 | obj_true = alloc_object(OBJ_TYPE_BOOL); | ||
32 | obj_false = alloc_object(OBJ_TYPE_BOOL); | ||
33 | obj_err = alloc_object(OBJ_TYPE_ERR); | ||
34 | obj_quote = make_symbol((StringView){"quote", 5}); | ||
35 | proc_if = alloc_object(OBJ_TYPE_ERR); | ||
36 | push_root(obj_nil); | ||
37 | push_root(obj_true); | ||
38 | push_root(obj_false); | ||
39 | push_root(obj_err); | ||
40 | push_root(obj_quote); | ||
41 | push_root(proc_if); | ||
42 | |||
43 | // Global environment. | ||
44 | global_env = env_create(NULL); | ||
45 | // TODO: make sure we create symbols and strings only once (interning | ||
46 | // strings?) | ||
47 | push_active_env(global_env); | ||
48 | |||
49 | // Primitive symbols. | ||
50 | MAKE_ENV_VAR(global_env, "else", obj_true); | ||
51 | MAKE_ENV_VAR(global_env, "nil", obj_nil); | ||
52 | MAKE_ENV_VAR(global_env, "if", proc_if); | ||
53 | |||
54 | // Primitive procedures. | ||
55 | MAKE_ENV_PROC(global_env, "eval", proc_eval); | ||
56 | MAKE_ENV_PROC(global_env, "quote", proc_quote); | ||
57 | MAKE_ENV_PROC(global_env, "car", proc_car); | ||
58 | MAKE_ENV_PROC(global_env, "cdr", proc_cdr); | ||
59 | MAKE_ENV_PROC(global_env, "cons", proc_cons); | ||
60 | MAKE_ENV_PROC(global_env, "list", proc_list); | ||
61 | MAKE_ENV_PROC(global_env, "+", proc_sum); | ||
62 | MAKE_ENV_PROC(global_env, "-", proc_sub); | ||
63 | MAKE_ENV_PROC(global_env, "*", proc_mul); | ||
64 | MAKE_ENV_PROC(global_env, "/", proc_div); | ||
65 | MAKE_ENV_PROC(global_env, "%", proc_mod); | ||
66 | MAKE_ENV_PROC(global_env, "print", proc_print); | ||
67 | MAKE_ENV_PROC(global_env, "display", proc_display); | ||
68 | MAKE_ENV_PROC(global_env, "newline", proc_newline); | ||
69 | MAKE_ENV_PROC(global_env, "boolean?", proc_is_boolean); | ||
70 | MAKE_ENV_PROC(global_env, "nil?", proc_is_nil); | ||
71 | MAKE_ENV_PROC(global_env, "symbol?", proc_is_symbol); | ||
72 | MAKE_ENV_PROC(global_env, "string?", proc_is_string); | ||
73 | MAKE_ENV_PROC(global_env, "fixnum?", proc_is_fixnum); | ||
74 | MAKE_ENV_PROC(global_env, "pair?", proc_is_pair); | ||
75 | MAKE_ENV_PROC(global_env, "procedure?", proc_is_procedure); | ||
76 | MAKE_ENV_PROC(global_env, "error?", proc_is_error); | ||
77 | MAKE_ENV_PROC(global_env, "not", proc_not); | ||
78 | MAKE_ENV_PROC(global_env, "and", proc_and); | ||
79 | MAKE_ENV_PROC(global_env, "or", proc_or); | ||
80 | MAKE_ENV_PROC(global_env, "cond", proc_cond); | ||
81 | MAKE_ENV_PROC(global_env, "<", proc_num_less_than); | ||
82 | MAKE_ENV_PROC(global_env, "<=", proc_num_lesseq_than); | ||
83 | MAKE_ENV_PROC(global_env, ">", proc_num_greater_than); | ||
84 | MAKE_ENV_PROC(global_env, ">=", proc_num_greatereq_than); | ||
85 | MAKE_ENV_PROC(global_env, "=", proc_num_equal); | ||
86 | MAKE_ENV_PROC(global_env, "eq?", proc_equal); | ||
87 | MAKE_ENV_PROC(global_env, "def", proc_define); | ||
88 | MAKE_ENV_PROC(global_env, "set!", proc_set); | ||
89 | MAKE_ENV_PROC(global_env, "lambda", proc_lambda); | ||
90 | MAKE_ENV_PROC(global_env, "fun", proc_fun); | ||
91 | |||
92 | // Runtime procedures. | ||
93 | MAKE_ENV_PROC(global_env, "supress-errors", proc_supress_errors); | ||
94 | } | ||
95 | |||
96 | void | ||
97 | process_source(const StringView *source) { | ||
98 | Token *tokens = tokenize(source); | ||
99 | if (errors_n != 0) { | ||
100 | if (tokens != NULL) { | ||
101 | array_free(tokens); | ||
102 | } | ||
103 | return; | ||
104 | } | ||
105 | |||
106 | Visitor visitor = (Visitor){ | ||
107 | .tokens = tokens, | ||
108 | .current = 0, | ||
109 | }; | ||
110 | while (has_next_token(&visitor) && peek_token(&visitor).type != TOKEN_EOF) { | ||
111 | // Check the root node stack size before parsing | ||
112 | size_t root_stack_size = array_size(gc.roots); | ||
113 | Object *root = parse_tree(&visitor); | ||
114 | array_head(gc.roots)->size = root_stack_size; | ||
115 | if (root == obj_err || errors_n != 0) { | ||
116 | break; | ||
117 | } | ||
118 | push_root(root); | ||
119 | |||
120 | Object *result = eval(global_env, root); | ||
121 | if (result != obj_nil) { | ||
122 | display(result); | ||
123 | printf("\n"); | ||
124 | } | ||
125 | pop_root(); | ||
126 | } | ||
127 | |||
128 | if (tokens != NULL) { | ||
129 | array_free(tokens); | ||
130 | } | ||
131 | } | ||
132 | |||
133 | #define REPL_PROMPT "bdl> " | ||
134 | |||
135 | void | ||
136 | run_repl(void) { | ||
137 | printf("BDL REPL (Press Ctrl-D or Ctrl-C to exit)\n"); | ||
138 | while (true) { | ||
139 | printf(REPL_PROMPT); | ||
140 | StringView sv = read_line(); | ||
141 | if (sv.start == NULL) { | ||
142 | return; | ||
143 | } | ||
144 | process_source(&sv); | ||
145 | |||
146 | // Check if there were any errors. | ||
147 | if (errors_n != 0 && !supress_errors) { | ||
148 | for (size_t i = 0; i < errors_n; i++) { | ||
149 | Error err = errors[i]; | ||
150 | for (size_t j = 0; j < err.col + sizeof(REPL_PROMPT) - 2; j++) { | ||
151 | putchar(' '); | ||
152 | } | ||
153 | printf("|\n"); | ||
154 | for (size_t j = 0; j < err.col + sizeof(REPL_PROMPT) - 2; j++) { | ||
155 | putchar(' '); | ||
156 | } | ||
157 | printf("%s\n", error_msgs[err.value]); | ||
158 | } | ||
159 | errors_n = 0; | ||
160 | continue; | ||
161 | } | ||
162 | } | ||
163 | } | ||
164 | |||
165 | void | ||
166 | run_file(char *file_name) { | ||
167 | FILE *file = fopen(file_name, "r"); | ||
168 | if (!file) { | ||
169 | fprintf(stderr, "error: couldn't open input file: %s\n", file_name); | ||
170 | exit(EXIT_FAILURE); | ||
171 | } | ||
172 | |||
173 | // Read entire file into memory. | ||
174 | fseek(file, 0, SEEK_END); | ||
175 | size_t file_size = ftell(file); | ||
176 | fseek(file, 0, SEEK_SET); | ||
177 | |||
178 | char *source = malloc(file_size + 1); | ||
179 | fread(source, 1, file_size, file); | ||
180 | source[file_size] = 0; | ||
181 | |||
182 | StringView sv = (StringView){ | ||
183 | .start = source, | ||
184 | .n = file_size, | ||
185 | }; | ||
186 | |||
187 | process_source(&sv); | ||
188 | |||
189 | // Check if there were any errors. | ||
190 | if (errors_n != 0 && !supress_errors) { | ||
191 | for (size_t i = 0; i < errors_n; i++) { | ||
192 | Error err = errors[i]; | ||
193 | fprintf(stderr, "%s", file_name); | ||
194 | if (err.line != 0) { | ||
195 | fprintf(stderr, ":%ld:%ld", err.line, err.col); | ||
196 | } | ||
197 | fprintf(stderr, ": %s\n", error_msgs[err.value]); | ||
198 | } | ||
199 | errors_n = 0; | ||
200 | } | ||
201 | |||
202 | free(source); | ||
203 | fclose(file); | ||
204 | } | ||
205 | |||
206 | #define STDIN_BUF_CAP 16 | ||
207 | |||
208 | void | ||
209 | run_stdin(void) { | ||
210 | size_t buf_size = 0; | ||
211 | char *source = NULL; | ||
212 | array_init(source, STDIN_BUF_CAP); | ||
213 | |||
214 | char c; | ||
215 | while ((c = getchar()) != EOF) { | ||
216 | array_push(source, c); | ||
217 | buf_size++; | ||
218 | } | ||
219 | |||
220 | StringView sv = (StringView){ | ||
221 | .start = source, | ||
222 | .n = buf_size, | ||
223 | }; | ||
224 | |||
225 | process_source(&sv); | ||
226 | |||
227 | // Check if there were any errors. | ||
228 | if (errors_n != 0 && !supress_errors) { | ||
229 | for (size_t i = 0; i < errors_n; i++) { | ||
230 | Error err = errors[i]; | ||
231 | fprintf(stderr, "stdin"); | ||
232 | if (err.line != 0) { | ||
233 | fprintf(stderr, ":%ld:%ld", err.line, err.col); | ||
234 | } | ||
235 | fprintf(stderr, ": %s\n", error_msgs[err.value]); | ||
236 | } | ||
237 | errors_n = 0; | ||
238 | } | ||
239 | |||
240 | array_free(source); | ||
241 | } | ||
242 | |||
243 | #ifndef BIN_NAME | ||
244 | #define BIN_NAME "bdl" | ||
245 | #endif | ||
246 | |||
247 | void | ||
248 | print_usage(void) { | ||
249 | printf("Usage: %s [options] <filename filename ...>\n", BIN_NAME); | ||
250 | printf("\n"); | ||
251 | printf("\t-i\tInteractive mode (REPL).\n"); | ||
252 | printf("\n"); | ||
253 | } | ||
254 | |||
255 | int | ||
256 | main(int argc, char *argv[]) { | ||
257 | init(); | ||
258 | |||
259 | int option; | ||
260 | while ((option = getopt(argc, argv, "i")) != -1) { | ||
261 | switch (option) { | ||
262 | case 'i': { | ||
263 | // Interactive mode. | ||
264 | run_repl(); | ||
265 | return EXIT_SUCCESS; | ||
266 | } break; | ||
267 | default: { | ||
268 | print_usage(); | ||
269 | return EXIT_FAILURE; | ||
270 | } break; | ||
271 | } | ||
272 | } | ||
273 | |||
274 | // Run from stdin. | ||
275 | if (optind == argc) { | ||
276 | run_stdin(); | ||
277 | return EXIT_SUCCESS; | ||
278 | } | ||
279 | |||
280 | // Run from file. | ||
281 | while (optind < argc) { | ||
282 | char *file_name = argv[optind]; | ||
283 | run_file(file_name); | ||
284 | optind++; | ||
285 | } | ||
286 | |||
287 | return EXIT_SUCCESS; | ||
288 | } | ||