diff options
Diffstat (limited to 'src/bytecode/main.c')
-rw-r--r-- | src/bytecode/main.c | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/src/bytecode/main.c b/src/bytecode/main.c new file mode 100644 index 0000000..78fdfd3 --- /dev/null +++ b/src/bytecode/main.c | |||
@@ -0,0 +1,197 @@ | |||
1 | #include <assert.h> | ||
2 | #include <getopt.h> | ||
3 | #include <stdio.h> | ||
4 | #include <stdlib.h> | ||
5 | #include <string.h> | ||
6 | |||
7 | #include "types.h" | ||
8 | #include "darray.h" | ||
9 | #include "ops.h" | ||
10 | #include "debug.h" | ||
11 | #include "errors.c" | ||
12 | #include "lexer.c" | ||
13 | #include "read_line.c" | ||
14 | #include "string_view.c" | ||
15 | |||
16 | void | ||
17 | init(void) { | ||
18 | // STUB | ||
19 | } | ||
20 | |||
21 | void | ||
22 | process_source(const StringView *source) { | ||
23 | Token *tokens = tokenize(source); | ||
24 | if (errors_n != 0) { | ||
25 | array_free(tokens); | ||
26 | return; | ||
27 | } | ||
28 | |||
29 | // Test chunks and debugging utilities. | ||
30 | u8 *chunk = NULL; | ||
31 | array_init(chunk, 0); | ||
32 | array_push(chunk, OP_RETURN); | ||
33 | array_push(chunk, OP_RETURN); | ||
34 | array_push(chunk, OP_RETURN); | ||
35 | array_push(chunk, OP_RETURN); | ||
36 | disassemble_chunk(chunk, "test chunk"); | ||
37 | |||
38 | array_free(chunk); | ||
39 | array_free(tokens); | ||
40 | } | ||
41 | |||
42 | #define REPL_PROMPT "bdl> " | ||
43 | |||
44 | void | ||
45 | run_repl(void) { | ||
46 | printf("BDL REPL (Press Ctrl-D or Ctrl-C to exit)\n"); | ||
47 | while (true) { | ||
48 | printf(REPL_PROMPT); | ||
49 | StringView sv = read_line(); | ||
50 | if (sv.start == NULL) { | ||
51 | return; | ||
52 | } | ||
53 | process_source(&sv); | ||
54 | |||
55 | // Check if there were any errors. | ||
56 | if (errors_n != 0 && !supress_errors) { | ||
57 | for (size_t i = 0; i < errors_n; i++) { | ||
58 | Error err = errors[i]; | ||
59 | for (size_t j = 0; j < err.col + sizeof(REPL_PROMPT) - 2; j++) { | ||
60 | putchar(' '); | ||
61 | } | ||
62 | printf("|\n"); | ||
63 | for (size_t j = 0; j < err.col + sizeof(REPL_PROMPT) - 2; j++) { | ||
64 | putchar(' '); | ||
65 | } | ||
66 | printf("%s\n", error_msgs[err.value]); | ||
67 | } | ||
68 | errors_n = 0; | ||
69 | continue; | ||
70 | } | ||
71 | } | ||
72 | } | ||
73 | |||
74 | void | ||
75 | run_file(char *file_name) { | ||
76 | FILE *file = fopen(file_name, "r"); | ||
77 | if (!file) { | ||
78 | fprintf(stderr, "error: couldn't open input file: %s\n", file_name); | ||
79 | exit(EXIT_FAILURE); | ||
80 | } | ||
81 | |||
82 | // Read entire file into memory. | ||
83 | fseek(file, 0, SEEK_END); | ||
84 | size_t file_size = ftell(file); | ||
85 | fseek(file, 0, SEEK_SET); | ||
86 | |||
87 | char *source = malloc(file_size + 1); | ||
88 | fread(source, 1, file_size, file); | ||
89 | source[file_size] = 0; | ||
90 | |||
91 | StringView sv = (StringView){ | ||
92 | .start = source, | ||
93 | .n = file_size, | ||
94 | }; | ||
95 | |||
96 | process_source(&sv); | ||
97 | |||
98 | // Check if there were any errors. | ||
99 | if (errors_n != 0 && !supress_errors) { | ||
100 | for (size_t i = 0; i < errors_n; i++) { | ||
101 | Error err = errors[i]; | ||
102 | fprintf(stderr, "%s", file_name); | ||
103 | if (err.line != 0) { | ||
104 | fprintf(stderr, ":%ld:%ld", err.line, err.col); | ||
105 | } | ||
106 | fprintf(stderr, ": %s\n", error_msgs[err.value]); | ||
107 | } | ||
108 | errors_n = 0; | ||
109 | } | ||
110 | |||
111 | free(source); | ||
112 | fclose(file); | ||
113 | } | ||
114 | |||
115 | #define STDIN_BUF_CAP 16 | ||
116 | |||
117 | void | ||
118 | run_stdin(void) { | ||
119 | size_t buf_size = 0; | ||
120 | char *source = NULL; | ||
121 | array_init(source, STDIN_BUF_CAP); | ||
122 | |||
123 | char c; | ||
124 | while ((c = getchar()) != EOF) { | ||
125 | array_push(source, c); | ||
126 | buf_size++; | ||
127 | } | ||
128 | |||
129 | StringView sv = (StringView){ | ||
130 | .start = source, | ||
131 | .n = buf_size, | ||
132 | }; | ||
133 | |||
134 | process_source(&sv); | ||
135 | |||
136 | // Check if there were any errors. | ||
137 | if (errors_n != 0 && !supress_errors) { | ||
138 | for (size_t i = 0; i < errors_n; i++) { | ||
139 | Error err = errors[i]; | ||
140 | fprintf(stderr, "stdin"); | ||
141 | if (err.line != 0) { | ||
142 | fprintf(stderr, ":%ld:%ld", err.line, err.col); | ||
143 | } | ||
144 | fprintf(stderr, ": %s\n", error_msgs[err.value]); | ||
145 | } | ||
146 | errors_n = 0; | ||
147 | } | ||
148 | |||
149 | array_free(source); | ||
150 | } | ||
151 | |||
152 | #ifndef BIN_NAME | ||
153 | #define BIN_NAME "bdl" | ||
154 | #endif | ||
155 | |||
156 | void | ||
157 | print_usage(void) { | ||
158 | printf("Usage: %s [options] <filename filename ...>\n", BIN_NAME); | ||
159 | printf("\n"); | ||
160 | printf("\t-i\tInteractive mode (REPL).\n"); | ||
161 | printf("\n"); | ||
162 | } | ||
163 | |||
164 | int | ||
165 | main(int argc, char *argv[]) { | ||
166 | init(); | ||
167 | |||
168 | int option; | ||
169 | while ((option = getopt(argc, argv, "i")) != -1) { | ||
170 | switch (option) { | ||
171 | case 'i': { | ||
172 | // Interactive mode. | ||
173 | run_repl(); | ||
174 | return EXIT_SUCCESS; | ||
175 | } break; | ||
176 | default: { | ||
177 | print_usage(); | ||
178 | return EXIT_FAILURE; | ||
179 | } break; | ||
180 | } | ||
181 | } | ||
182 | |||
183 | // Run from stdin. | ||
184 | if (optind == argc) { | ||
185 | run_stdin(); | ||
186 | return EXIT_SUCCESS; | ||
187 | } | ||
188 | |||
189 | // Run from file. | ||
190 | while (optind < argc) { | ||
191 | char *file_name = argv[optind]; | ||
192 | run_file(file_name); | ||
193 | optind++; | ||
194 | } | ||
195 | |||
196 | return EXIT_SUCCESS; | ||
197 | } | ||