1 | // ================================================================ |
---|
2 | /* */ |
---|
3 | // File : aisc.c |
---|
4 | // Purpose : ARB integrated source compiler |
---|
5 | /* */ |
---|
6 | // Institute of Microbiology (Technical University Munich) |
---|
7 | // http://www.arb-home.de |
---|
8 | /* */ |
---|
9 | // ================================================================ |
---|
10 | |
---|
11 | #include "aisc_interpreter.h" |
---|
12 | #include <cctype> |
---|
13 | #include <list> |
---|
14 | #include <string> |
---|
15 | |
---|
16 | using namespace std; |
---|
17 | |
---|
18 | // AISC_MKPT_PROMOTE:#ifndef AISC_DEF_H |
---|
19 | // AISC_MKPT_PROMOTE:#include "aisc_def.h" |
---|
20 | // AISC_MKPT_PROMOTE:#endif |
---|
21 | |
---|
22 | char *read_aisc_file(const char *path, const Location *loc) { |
---|
23 | char *buffer = 0; |
---|
24 | FILE *input = fopen(path, "rt"); |
---|
25 | |
---|
26 | if (!input) { |
---|
27 | printf_error(loc, "file '%s' not found", path); |
---|
28 | } |
---|
29 | else { |
---|
30 | if (fseek(input, 0, 2)==-1) { |
---|
31 | printf_error(loc, "file '%s' not seekable", path); |
---|
32 | } |
---|
33 | else { |
---|
34 | int data_size = (int)ftell(input); |
---|
35 | |
---|
36 | if (data_size == 0) { |
---|
37 | Location fileLoc(0, path); |
---|
38 | print_error(&fileLoc, "file is empty"); |
---|
39 | } |
---|
40 | else { |
---|
41 | data_size++; |
---|
42 | rewind(input); |
---|
43 | buffer = (char *)malloc(data_size+1); |
---|
44 | data_size = fread(buffer, 1, data_size, input); |
---|
45 | buffer[data_size] = 0; |
---|
46 | } |
---|
47 | } |
---|
48 | fclose(input); |
---|
49 | } |
---|
50 | return buffer; |
---|
51 | } |
---|
52 | |
---|
53 | inline int max(int i, int j) { return i<j ? j : i; } |
---|
54 | |
---|
55 | void LineQueue::alignInto(LineQueue& dest) { |
---|
56 | int offset = 0; |
---|
57 | int len[count]; |
---|
58 | |
---|
59 | for (int i = 0; i<count; ++i) len[i] = strlen(queue[i]); |
---|
60 | |
---|
61 | while (1) { |
---|
62 | int max_mark_pos = -1; |
---|
63 | int mark_pos[count]; |
---|
64 | for (int i = 0; i<count; ++i) { |
---|
65 | char *line = queue[i]; |
---|
66 | char *mark = len[i]>offset ? strchr(line+offset, ALIGN_MARKER) : NULL; |
---|
67 | mark_pos[i] = mark ? mark-line : -1; |
---|
68 | max_mark_pos = max(max_mark_pos, mark_pos[i]); |
---|
69 | } |
---|
70 | if (max_mark_pos == -1) break; |
---|
71 | |
---|
72 | for (int i = 0; i<count; ++i) { |
---|
73 | if (mark_pos[i] >= 0) { |
---|
74 | int insert = max_mark_pos-mark_pos[i]; |
---|
75 | aisc_assert(insert >= 0); |
---|
76 | if (insert >= 0) { |
---|
77 | int new_len = len[i]+insert; |
---|
78 | char *new_line = (char*)malloc(new_len+1); |
---|
79 | |
---|
80 | memcpy(new_line, queue[i], mark_pos[i]); |
---|
81 | memset(new_line+mark_pos[i], ' ', insert); |
---|
82 | strcpy(new_line+max_mark_pos, queue[i]+mark_pos[i]+1); |
---|
83 | |
---|
84 | len[i] = new_len; |
---|
85 | freeset(queue[i], new_line); |
---|
86 | } |
---|
87 | } |
---|
88 | } |
---|
89 | |
---|
90 | offset = max_mark_pos; |
---|
91 | } |
---|
92 | |
---|
93 | for (int i = 0; i<count; ++i) { |
---|
94 | dest.add(queue[i]); |
---|
95 | queue[i] = NULL; |
---|
96 | } |
---|
97 | count = 0; |
---|
98 | } |
---|
99 | |
---|
100 | struct queued_line { |
---|
101 | string line; |
---|
102 | int indentation; |
---|
103 | queued_line(const char *line_, int indent) : line(line_), indentation(indent) { } |
---|
104 | }; |
---|
105 | |
---|
106 | typedef list<queued_line> PrintQueue; |
---|
107 | |
---|
108 | class PrintMaybe : virtual Noncopyable { |
---|
109 | Output& out; |
---|
110 | const Location& started_at; |
---|
111 | bool printed_sth; |
---|
112 | PrintMaybe *next; |
---|
113 | PrintQueue queue; |
---|
114 | |
---|
115 | public: |
---|
116 | PrintMaybe(PrintMaybe *head, Output& out_, const Location& loc) |
---|
117 | : out(out_), |
---|
118 | started_at(loc), |
---|
119 | printed_sth(false), |
---|
120 | next(head) |
---|
121 | { |
---|
122 | } |
---|
123 | ~PrintMaybe() { |
---|
124 | } |
---|
125 | |
---|
126 | void add(const char *line) { |
---|
127 | if (printed_sth) { |
---|
128 | out.write(line); |
---|
129 | } |
---|
130 | else { |
---|
131 | queue.push_back(queued_line(line, out.get_formatter().get_indent())); |
---|
132 | } |
---|
133 | } |
---|
134 | void spool() { |
---|
135 | aisc_assert(!printed_sth); |
---|
136 | printed_sth = true; |
---|
137 | if (!queue.empty()) { |
---|
138 | Formatter& formatter = out.get_formatter(); |
---|
139 | int old_indent = formatter.get_indent(); |
---|
140 | for (PrintQueue::iterator i = queue.begin(); i != queue.end(); ++i) { |
---|
141 | queued_line& ql = *i; |
---|
142 | formatter.set_indent(ql.indentation); |
---|
143 | out.write(ql.line.c_str()); |
---|
144 | } |
---|
145 | formatter.set_indent(old_indent); |
---|
146 | queue.clear(); |
---|
147 | } |
---|
148 | } |
---|
149 | |
---|
150 | void will_print() { |
---|
151 | if (next) next->will_print(); |
---|
152 | if (!printed_sth) { |
---|
153 | spool(); |
---|
154 | } |
---|
155 | } |
---|
156 | |
---|
157 | void not_destroyed_error() { |
---|
158 | print_error(&started_at, "PMSTART without matching PMEND"); |
---|
159 | if (next) next->not_destroyed_error(); |
---|
160 | } |
---|
161 | |
---|
162 | static void pop(PrintMaybe*& head) { |
---|
163 | PrintMaybe *next = head->next; |
---|
164 | head->next = NULL; |
---|
165 | delete head; |
---|
166 | head = next; |
---|
167 | } |
---|
168 | }; |
---|
169 | |
---|
170 | void Output::setup() { |
---|
171 | fp = NULL; |
---|
172 | id = NULL; |
---|
173 | name = NULL; |
---|
174 | maybe = NULL; |
---|
175 | |
---|
176 | have_open_loc = false; |
---|
177 | } |
---|
178 | void Output::cleanup() { |
---|
179 | close_file(); |
---|
180 | free(id); |
---|
181 | free(name); |
---|
182 | if (maybe) { |
---|
183 | maybe->not_destroyed_error(); |
---|
184 | delete maybe; |
---|
185 | } |
---|
186 | } |
---|
187 | |
---|
188 | void Output::maybe_start() { |
---|
189 | maybe = new PrintMaybe(maybe, *this, Interpreter::instance->at()->source); |
---|
190 | } |
---|
191 | int Output::maybe_write(const char *line) { |
---|
192 | if (!maybe) { |
---|
193 | print_error(Interpreter::instance->at(), "no PMSTART before PM"); |
---|
194 | return -1; |
---|
195 | } |
---|
196 | maybe->add(line); |
---|
197 | return 0; |
---|
198 | } |
---|
199 | int Output::maybe_end() { |
---|
200 | if (!maybe) { |
---|
201 | print_error(Interpreter::instance->at(), "no PMSTART before PMEND"); |
---|
202 | return -1; |
---|
203 | } |
---|
204 | PrintMaybe::pop(maybe); |
---|
205 | return 0; |
---|
206 | } |
---|
207 | |
---|
208 | int Output::write(const char *line) { |
---|
209 | if (!inUse()) { |
---|
210 | print_error(Interpreter::instance->at(), "Fatal: attempt to write to unused file"); |
---|
211 | return -1; |
---|
212 | } |
---|
213 | |
---|
214 | if (maybe) maybe->will_print(); |
---|
215 | |
---|
216 | int res = formatter.write(line); |
---|
217 | formatter.flush(fp); |
---|
218 | return res; |
---|
219 | } |
---|
220 | |
---|
221 | Formatter::Formatter() |
---|
222 | : tabstop(4), |
---|
223 | column(0), |
---|
224 | indent(0), |
---|
225 | printed_sth(false) |
---|
226 | { |
---|
227 | set_tabstop(4); |
---|
228 | |
---|
229 | for (int i = 0; i < 256; i++) { |
---|
230 | outtab[i] = i; |
---|
231 | } |
---|
232 | |
---|
233 | outtab[(unsigned char)'n'] = '\n'; |
---|
234 | outtab[(unsigned char)'t'] = '\t'; |
---|
235 | outtab[(unsigned char)'|'] = ALIGN_MARKER; |
---|
236 | outtab[(unsigned char)'0'] = 0; |
---|
237 | outtab[(unsigned char)'1'] = 0; |
---|
238 | outtab[(unsigned char)'2'] = 0; |
---|
239 | outtab[(unsigned char)'3'] = 0; |
---|
240 | outtab[(unsigned char)'4'] = 0; |
---|
241 | outtab[(unsigned char)'5'] = 0; |
---|
242 | outtab[(unsigned char)'6'] = 0; |
---|
243 | outtab[(unsigned char)'7'] = 0; |
---|
244 | outtab[(unsigned char)'8'] = 0; |
---|
245 | outtab[(unsigned char)'9'] = 0; |
---|
246 | outtab[(unsigned char)'\\'] = 0; |
---|
247 | } |
---|
248 | |
---|
249 | int Formatter::write(const char *str) { |
---|
250 | int no_nl = 0; |
---|
251 | const char *p = str; |
---|
252 | char c; |
---|
253 | |
---|
254 | while ((c = *(p++))) { |
---|
255 | if (c == '$') { |
---|
256 | c = *(p++); |
---|
257 | if (!c) |
---|
258 | break; |
---|
259 | |
---|
260 | if (!outtab[(unsigned)(c)]) { |
---|
261 | if (c == '\\') { |
---|
262 | no_nl = 1; |
---|
263 | } |
---|
264 | else if (isdigit(c)) { |
---|
265 | int pos = tabs[c - '0']; |
---|
266 | tab_to_pos(pos); |
---|
267 | } |
---|
268 | continue; |
---|
269 | } |
---|
270 | else { |
---|
271 | c = outtab[(unsigned)(c)]; |
---|
272 | } |
---|
273 | } |
---|
274 | if (c == '\t') { |
---|
275 | int pos = ((column/tabstop)+1)*tabstop; |
---|
276 | tab_to_pos(pos); |
---|
277 | } |
---|
278 | else if (c == '\n') { |
---|
279 | if (no_nl) { |
---|
280 | no_nl = 0; |
---|
281 | } |
---|
282 | else { |
---|
283 | finish_line(); |
---|
284 | } |
---|
285 | } |
---|
286 | else if (c == '@') { |
---|
287 | if (strncmp(p, "SETSOURCE", 9) == 0) { // skip '@SETSOURCE file, line@' |
---|
288 | p = strchr(p, '@'); |
---|
289 | if (!p) { |
---|
290 | print_error(Interpreter::instance->at(), "expected '@' after '@SETSOURCE' (injected code)"); |
---|
291 | return 1; |
---|
292 | } |
---|
293 | p++; |
---|
294 | } |
---|
295 | else { |
---|
296 | print_char(c); |
---|
297 | } |
---|
298 | } |
---|
299 | else { |
---|
300 | print_char(c); |
---|
301 | } |
---|
302 | } |
---|
303 | if (!no_nl) { |
---|
304 | finish_line(); |
---|
305 | } |
---|
306 | return 0; |
---|
307 | } |
---|
308 | |
---|
309 | bool Interpreter::set_data(const char *dataBlock, int offset_in_line) { |
---|
310 | parser.set_line_start(dataBlock, offset_in_line); |
---|
311 | parser.set_source(at()->source); // remove ? |
---|
312 | data.set_tokens(parser.parseTokenListBlock(dataBlock)); |
---|
313 | return data.get_tokens(); |
---|
314 | } |
---|
315 | |
---|
316 | |
---|
317 | int Interpreter::launch(int argc, char ** argv) { |
---|
318 | int exitcode = EXIT_FAILURE; |
---|
319 | |
---|
320 | // save CL-arguments as variables (with names like 'argv[0]' ..) |
---|
321 | { |
---|
322 | for (int i=0; i<argc; i++) { |
---|
323 | write_var(formatted("argv[%i]", i), argv[i]); |
---|
324 | } |
---|
325 | write_var("argc", formatted("%i", argc)); |
---|
326 | } |
---|
327 | |
---|
328 | { |
---|
329 | char *buf = read_aisc_file(argv[1], NULL); |
---|
330 | if (buf) { |
---|
331 | prg = parser.parse_program(buf, argv[1]); |
---|
332 | free(buf); |
---|
333 | } |
---|
334 | } |
---|
335 | |
---|
336 | if (!prg) { |
---|
337 | fputs("Nothing to execute\n", stderr); |
---|
338 | } |
---|
339 | else { |
---|
340 | if (compile_program()) { |
---|
341 | fprintf(stderr, "Compilation of '%s' failed\n", argv[1]); |
---|
342 | } |
---|
343 | else { |
---|
344 | if (run_program()) { |
---|
345 | if (!Location::get_error_count()) { |
---|
346 | print_error(at(), "AISC compiler bailed out w/o error"); |
---|
347 | } |
---|
348 | fputs("AISC reports errors\n", stderr); |
---|
349 | for (int i = 0; i < OPENFILES; i++) output[i].close_and_unlink(); |
---|
350 | fflush(stdout); |
---|
351 | } |
---|
352 | else { |
---|
353 | aisc_assert(!Location::get_error_count()); |
---|
354 | exitcode = EXIT_SUCCESS; |
---|
355 | } |
---|
356 | } |
---|
357 | } |
---|
358 | |
---|
359 | return exitcode; |
---|
360 | } |
---|
361 | |
---|
362 | int main(int argc, char ** argv) { |
---|
363 | int exitcode = EXIT_FAILURE; |
---|
364 | |
---|
365 | if (argc < 2) { |
---|
366 | fprintf(stderr, "AISC - ARB integrated source compiler\n"); |
---|
367 | fprintf(stderr, "Usage: aisc [fileToCompile]+\n"); |
---|
368 | fprintf(stderr, "Error: missing file name\n"); |
---|
369 | } |
---|
370 | else { |
---|
371 | try { |
---|
372 | exitcode = Interpreter().launch(argc, argv); |
---|
373 | } |
---|
374 | catch (const char *err) { |
---|
375 | fprintf(stderr, "\nAISC: exception: %s [terminating]\n", err); |
---|
376 | exitcode = EXIT_FAILURE; |
---|
377 | } |
---|
378 | catch (...) { |
---|
379 | fprintf(stderr, "\nAISC: unknown exception [terminating]\n"); |
---|
380 | exitcode = EXIT_FAILURE; |
---|
381 | } |
---|
382 | } |
---|
383 | return exitcode; |
---|
384 | } |
---|
385 | |
---|
386 | |
---|