source: mainline/uspace/app/sbi/src/run.c@ 09ababb7

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 09ababb7 was 09ababb7, checked in by Jiri Svoboda <jiri@…>, 16 years ago

Add Sysel Bootstrap Interpreter (SBI) from Sysel repository rev. 53.

  • Property mode set to 100644
File size: 12.2 KB
Line 
1/*
2 * Copyright (c) 2010 Jiri Svoboda
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @file Runner (executes the code). */
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <assert.h>
34#include "builtin.h"
35#include "debug.h"
36#include "intmap.h"
37#include "list.h"
38#include "mytypes.h"
39#include "rdata.h"
40#include "run_expr.h"
41#include "stree.h"
42#include "strtab.h"
43#include "symbol.h"
44
45#include "run.h"
46
47static void run_block(run_t *run, stree_block_t *block);
48static void run_stat(run_t *run, stree_stat_t *stat);
49static void run_exps(run_t *run, stree_exps_t *exps);
50static void run_vdecl(run_t *run, stree_vdecl_t *vdecl);
51static void run_if(run_t *run, stree_if_t *if_s);
52static void run_while(run_t *run, stree_while_t *while_s);
53
54static void run_value_item_to_var(rdata_item_t *item, rdata_var_t **var);
55
56/** Initialize runner instance. */
57void run_init(run_t *run)
58{
59}
60
61/** Run program */
62void run_program(run_t *run, stree_program_t *prog)
63{
64 stree_symbol_t *main_class_sym;
65 stree_symbol_t *main_fun_sym;
66 stree_csi_t *main_class;
67 stree_fun_t *main_fun;
68 stree_ident_t *fake_ident;
69 list_t main_args;
70
71 /* Note down link to program code. */
72 run->program = prog;
73
74 /* Initialize thread activation record. */
75 run->thread_ar = run_thread_ar_new();
76 list_init(&run->thread_ar->fun_ar);
77
78 /*
79 * Resolve class @c HelloWorld
80 */
81 fake_ident = stree_ident_new();
82
83 fake_ident->sid = strtab_get_sid("HelloWorld");
84 main_class_sym = symbol_lookup_in_csi(prog, NULL, fake_ident);
85 main_class = symbol_to_csi(main_class_sym);
86 if (main_class == NULL) {
87 printf("Error: HelloWorld is not a CSI.\n");
88 exit(1);
89 }
90
91#ifdef DEBUG_RUN_TRACE
92 printf("Found class '"); symbol_print_fqn(prog, main_class_sym);
93 printf("'.\n");
94#endif
95
96 /*
97 * Resolve function @c main within the class.
98 */
99 fake_ident->sid = strtab_get_sid("main");
100 main_fun_sym = symbol_lookup_in_csi(prog, main_class, fake_ident);
101 main_fun = symbol_to_fun(main_fun_sym);
102 if (main_fun == NULL) {
103 printf("Error: HelloWorld.main is not a function.\n");
104 exit(1);
105 }
106
107#ifdef DEBUG_RUN_TRACE
108 printf("Found function '"); symbol_print_fqn(prog, main_fun_sym);
109 printf("'.\n");
110#endif
111
112 list_init(&main_args);
113 run_fun(run, main_fun, &main_args);
114}
115
116/** Run member function */
117void run_fun(run_t *run, stree_fun_t *fun, list_t *args)
118{
119 stree_symbol_t *fun_sym;
120 run_fun_ar_t *fun_ar;
121 run_block_ar_t *block_ar;
122 list_node_t *rarg_n, *farg_n;
123 list_node_t *node;
124 rdata_item_t *rarg;
125 stree_fun_arg_t *farg;
126 rdata_var_t *var;
127
128 fun_sym = fun_to_symbol(fun);
129
130#ifdef DEBUG_RUN_TRACE
131 printf("Start executing function '");
132 symbol_print_fqn(run->program, fun_sym);
133 printf("'.\n");
134#endif
135
136 /* Create function activation record. */
137 fun_ar = run_fun_ar_new();
138 fun_ar->fun_sym = fun_sym;
139 list_init(&fun_ar->block_ar);
140
141 /* Add function AR to the stack. */
142 list_append(&run->thread_ar->fun_ar, fun_ar);
143
144 /* Create special block activation record to hold function arguments. */
145 block_ar = run_block_ar_new();
146 intmap_init(&block_ar->vars);
147 list_append(&fun_ar->block_ar, block_ar);
148
149 /* Declare local variables to hold argument values. */
150 rarg_n = list_first(args);
151 farg_n = list_first(&fun->args);
152
153 while (farg_n != NULL) {
154 if (rarg_n == NULL) {
155 printf("Error: Too few arguments to function '");
156 symbol_print_fqn(run->program, fun_sym);
157 printf("'.\n");
158 exit(1);
159 }
160
161 rarg = list_node_data(rarg_n, rdata_item_t *);
162 farg = list_node_data(farg_n, stree_fun_arg_t *);
163
164 assert(rarg->ic == ic_value);
165
166 /* Construct a variable from the argument value. */
167 run_value_item_to_var(rarg, &var);
168
169 /* Declare variable using name of formal argument. */
170 intmap_set(&block_ar->vars, farg->name->sid, var);
171
172 rarg_n = list_next(args, rarg_n);
173 farg_n = list_next(&fun->args, farg_n);
174 }
175
176 /* Check for excess real parameters. */
177 if (rarg_n != NULL) {
178 printf("Error: Too many arguments to function '");
179 symbol_print_fqn(run->program, fun_sym);
180 printf("'.\n");
181 exit(1);
182 }
183
184 /* Run main function block. */
185 if (fun->body != NULL) {
186 run_block(run, fun->body);
187 } else {
188 builtin_run_fun(run, fun_sym);
189 }
190
191#ifdef DEBUG_RUN_TRACE
192 printf("Done executing function '");
193 symbol_print_fqn(run->program, fun_sym);
194 printf("'.\n");
195
196 run_print_fun_bt(run);
197#endif
198
199 /* Remove function activation record from the stack. */
200 node = list_last(&run->thread_ar->fun_ar);
201 assert(list_node_data(node, run_fun_ar_t *) == fun_ar);
202 list_remove(&run->thread_ar->fun_ar, node);
203}
204
205/** Run code block */
206static void run_block(run_t *run, stree_block_t *block)
207{
208 run_fun_ar_t *fun_ar;
209 run_block_ar_t *block_ar;
210 list_node_t *node;
211 stree_stat_t *stat;
212
213#ifdef DEBUG_RUN_TRACE
214 printf("Executing one code block.\n");
215#endif
216
217 /* Create block activation record. */
218 block_ar = run_block_ar_new();
219 intmap_init(&block_ar->vars);
220
221 /* Add block activation record to the stack. */
222 fun_ar = run_get_current_fun_ar(run);
223 list_append(&fun_ar->block_ar, block_ar);
224
225 node = list_first(&block->stats);
226 while (node != NULL) {
227 stat = list_node_data(node, stree_stat_t *);
228 run_stat(run, stat);
229 node = list_next(&block->stats, node);
230 }
231
232#ifdef DEBUG_RUN_TRACE
233 printf("Done executing code block.\n");
234#endif
235
236 /* Remove block activation record from the stack. */
237 node = list_last(&fun_ar->block_ar);
238 assert(list_node_data(node, run_block_ar_t *) == block_ar);
239 list_remove(&fun_ar->block_ar, node);
240}
241
242/** Run statement. */
243static void run_stat(run_t *run, stree_stat_t *stat)
244{
245#ifdef DEBUG_RUN_TRACE
246 printf("Executing one statement %p.\n", stat);
247#endif
248
249 switch (stat->sc) {
250 case st_exps:
251 run_exps(run, stat->u.exp_s);
252 break;
253 case st_vdecl:
254 run_vdecl(run, stat->u.vdecl_s);
255 break;
256 case st_if:
257 run_if(run, stat->u.if_s);
258 break;
259 case st_while:
260 run_while(run, stat->u.while_s);
261 break;
262 case st_for:
263 case st_raise:
264 case st_wef:
265 printf("Ignoring unimplemented statement type %d.\n", stat->sc);
266 break;
267 default:
268 assert(b_false);
269 }
270}
271
272/** Run expression statement. */
273static void run_exps(run_t *run, stree_exps_t *exps)
274{
275 rdata_item_t *rexpr;
276
277#ifdef DEBUG_RUN_TRACE
278 printf("Executing expression statement.\n");
279#endif
280 run_expr(run, exps->expr, &rexpr);
281
282 if (rexpr != NULL) {
283 printf("Warning: Expression value ignored.\n");
284 }
285}
286
287/** Run variable declaration statement. */
288static void run_vdecl(run_t *run, stree_vdecl_t *vdecl)
289{
290 run_block_ar_t *block_ar;
291 rdata_var_t *var, *old_var;
292 rdata_int_t *int_v;
293
294#ifdef DEBUG_RUN_TRACE
295 printf("Executing variable declaration statement.\n");
296#endif
297
298 /* XXX Need to support other variables than int. */
299
300 var = rdata_var_new(vc_int);
301 int_v = rdata_int_new();
302
303 var->u.int_v = int_v;
304 int_v->value = 0;
305
306 block_ar = run_get_current_block_ar(run);
307 old_var = (rdata_var_t *) intmap_get(&block_ar->vars, vdecl->name->sid);
308
309 if (old_var != NULL) {
310 printf("Error: Duplicate variable '%s'\n",
311 strtab_get_str(vdecl->name->sid));
312 exit(1);
313 }
314
315 intmap_set(&block_ar->vars, vdecl->name->sid, var);
316
317#ifdef DEBUG_RUN_TRACE
318 printf("Declared variable '%s'\n", strtab_get_str(vdecl->name->sid));
319#endif
320}
321
322/** Run @c if statement. */
323static void run_if(run_t *run, stree_if_t *if_s)
324{
325 rdata_item_t *rcond;
326
327#ifdef DEBUG_RUN_TRACE
328 printf("Executing if statement.\n");
329#endif
330 run_expr(run, if_s->cond, &rcond);
331
332 if (run_item_boolean_value(run, rcond) == b_true) {
333#ifdef DEBUG_RUN_TRACE
334 printf("Taking true path.\n");
335#endif
336 run_block(run, if_s->if_block);
337 } else {
338#ifdef DEBUG_RUN_TRACE
339 printf("Taking false path.\n");
340#endif
341 if (if_s->else_block != NULL)
342 run_block(run, if_s->else_block);
343 }
344
345#ifdef DEBUG_RUN_TRACE
346 printf("If statement terminated.\n");
347#endif
348}
349
350/** Run @c while statement. */
351static void run_while(run_t *run, stree_while_t *while_s)
352{
353 rdata_item_t *rcond;
354
355#ifdef DEBUG_RUN_TRACE
356 printf("Executing while statement.\n");
357#endif
358 run_expr(run, while_s->cond, &rcond);
359
360 while (run_item_boolean_value(run, rcond) == b_true) {
361 run_block(run, while_s->body);
362 run_expr(run, while_s->cond, &rcond);
363 }
364
365#ifdef DEBUG_RUN_TRACE
366 printf("While statement terminated.\n");
367#endif
368}
369
370/** Find a local variable in the currently active function. */
371rdata_var_t *run_local_vars_lookup(run_t *run, sid_t name)
372{
373 run_fun_ar_t *fun_ar;
374 run_block_ar_t *block_ar;
375 rdata_var_t *var;
376 list_node_t *node;
377
378 fun_ar = run_get_current_fun_ar(run);
379 node = list_last(&fun_ar->block_ar);
380
381 /* Walk through all block activation records. */
382 while (node != NULL) {
383 block_ar = list_node_data(node, run_block_ar_t *);
384 var = intmap_get(&block_ar->vars, name);
385 if (var != NULL)
386 return var;
387
388 node = list_prev(&fun_ar->block_ar, node);
389 }
390
391 /* No match */
392 return NULL;
393}
394
395/** Get current function activation record. */
396run_fun_ar_t *run_get_current_fun_ar(run_t *run)
397{
398 list_node_t *node;
399
400 node = list_last(&run->thread_ar->fun_ar);
401 return list_node_data(node, run_fun_ar_t *);
402}
403
404/** Get current block activation record. */
405run_block_ar_t *run_get_current_block_ar(run_t *run)
406{
407 run_fun_ar_t *fun_ar;
408 list_node_t *node;
409
410 fun_ar = run_get_current_fun_ar(run);
411
412 node = list_last(&fun_ar->block_ar);
413 return list_node_data(node, run_block_ar_t *);
414}
415
416/** Construct variable from a value item.
417 *
418 * XXX This should be in fact implemented using existing code as:
419 *
420 * (1) Create a variable of the desired type.
421 * (2) Initialize the variable with the provided value.
422 */
423static void run_value_item_to_var(rdata_item_t *item, rdata_var_t **var)
424{
425 rdata_int_t *int_v;
426 rdata_string_t *string_v;
427 rdata_var_t *in_var;
428
429 assert(item->ic == ic_value);
430 in_var = item->u.value->var;
431
432 switch (in_var->vc) {
433 case vc_int:
434 *var = rdata_var_new(vc_int);
435 int_v = rdata_int_new();
436
437 (*var)->u.int_v = int_v;
438 int_v->value = item->u.value->var->u.int_v->value;
439 break;
440 case vc_string:
441 *var = rdata_var_new(vc_string);
442 string_v = rdata_string_new();
443
444 (*var)->u.string_v = string_v;
445 string_v->value = item->u.value->var->u.string_v->value;
446 break;
447 default:
448 printf("Error: Unimplemented argument type.\n");
449 exit(1);
450
451 }
452}
453
454/** Print function activation backtrace. */
455void run_print_fun_bt(run_t *run)
456{
457 list_node_t *node;
458 run_fun_ar_t *fun_ar;
459
460 printf("Backtrace:\n");
461 node = list_last(&run->thread_ar->fun_ar);
462 while (node != NULL) {
463 printf(" * ");
464 fun_ar = list_node_data(node, run_fun_ar_t *);
465 symbol_print_fqn(run->program, fun_ar->fun_sym);
466 printf("\n");
467
468 node = list_prev(&run->thread_ar->fun_ar, node);
469 }
470}
471
472run_thread_ar_t *run_thread_ar_new(void)
473{
474 run_thread_ar_t *thread_ar;
475
476 thread_ar = calloc(1, sizeof(run_thread_ar_t));
477 if (thread_ar == NULL) {
478 printf("Memory allocation failed.\n");
479 exit(1);
480 }
481
482 return thread_ar;
483}
484
485run_fun_ar_t *run_fun_ar_new(void)
486{
487 run_fun_ar_t *fun_ar;
488
489 fun_ar = calloc(1, sizeof(run_fun_ar_t));
490 if (fun_ar == NULL) {
491 printf("Memory allocation failed.\n");
492 exit(1);
493 }
494
495 return fun_ar;
496}
497
498run_block_ar_t *run_block_ar_new(void)
499{
500 run_block_ar_t *block_ar;
501
502 block_ar = calloc(1, sizeof(run_block_ar_t));
503 if (block_ar == NULL) {
504 printf("Memory allocation failed.\n");
505 exit(1);
506 }
507
508 return block_ar;
509}
Note: See TracBrowser for help on using the repository browser.