2 * Copyright (C) 2001-2008, Parrot Foundation.
7 examples/c/nanoparrot.c
11 demonstrates how the interpreter interprets bytecode
12 its vastly simplified but the very basics are the same
15 -DTRACE ... turn on opcode tracing (FUNC_CORE, SWITCH_CORE only)
16 -DFUNC_CORE run function base opcodes
18 -DSWITCH_CORE run switched opcode core
22 The CGOTO run core works only for compilers like gcc that allow
27 cc -o nanoparrot -Wall nanoparrot.c -O3 && time ./nanoparrot mops
43 typedef double FLOATVAL
;
47 #define NUM_REGISTERS 32
56 #define REG_INT(interp, x) (interp)->bp[(x)].int_reg
58 #if defined(PREDEREF_CORE)
59 # define IREG(x) (_reg_base + pc[(x)])
60 # define ICONST(x) *(INTVAL*)pc[(x)]
61 # define SCONST(x) *(STRING**)pc[(x)]
63 # define IREG(x) REG_INT(interp, pc[(x)])
64 # define ICONST(x) pc[(x)]
65 # define SCONST(x) interp->code->const_table[pc[(x)]]
73 typedef struct Interp
{
76 opcode_t
*(**op_func
)(opcode_t
*, struct Interp
*);
85 #define OPCODES OP(end), OP(print_sc), OP(print_i), \
86 OP(set_i_ic), OP(if_i_ic), OP(sub_i_i_i), \
90 * some macros to get 3 different kinds of run loops
91 * you might skip this ugliness and continue
92 * at dispatch loop ~90 lines below
94 * or for the curious: look at the preprocessor output
98 typedef enum { OPCODES
} opcodes
;
108 #if defined(FUNC_CORE)
112 run(Interp *interp, opcode_t *pc) \
115 printf("PC %2d %s\n", pc - interp->code->byte_code, \
116 interp->op_info[*pc]); \
117 pc = interp->op_func[*pc](pc, interp); \
123 run(Interp *interp, opcode_t *pc) \
126 pc = interp->op_func[*pc](pc, interp); \
133 # define CASE(function) \
135 function(opcode_t *pc, Interp *interp) \
138 # define NEXT return pc; }
139 # define DONE return 0; }
141 #else /* !FUNC_CORE */
145 # if defined(SWITCH_CORE)
149 =item C<static void run(Interp *interp, opcode_t *pc)>
151 Execute a single opcode.
158 run(Interp
*interp
, opcode_t
*pc
)
163 printf("PC %2d %s\n", pc - interp->code->byte_code, \
164 interp->op_info[*pc]); \
172 # define CASE(x) case OP_##x:
173 # define NEXT continue;
174 # define DONE return;
175 # define ENDDISPATCH default : printf("illegal instruction"); \
176 exit(EXIT_FAILURE); \
181 run(Interp
*interp
, opcode_t
*pc
)
183 # define OP(x) &&lOP_##x
184 static void *labels
[] = { OPCODES
};
186 # define CASE(x) lOP_##x:
187 # define NEXT goto *labels[*pc];
188 # define DISPATCH NEXT
190 # define DONE return;
192 # endif /* SWITCH or CGOTO */
193 #endif /* !FUNC_CORE */
196 * dispatch loop / opcode (function) bodies i.e. the .ops files
203 printf("%s", SCONST(1));
207 printf("%d", IREG(1));
221 IREG(1) = IREG(2) - IREG(3);
225 printf("illegal opcode\n");
232 # define DEF_OP(op) \
233 interp->op_func[OP_##op] = (op); \
234 interp->op_info[OP_##op] = #op
236 # define DEF_OP(op) \
237 interp->op_info[OP_##op] = #op
242 =item C<static void init(Interp *interp, opcode_t *prog)>
249 init(Interp
*interp
, opcode_t
*prog
)
252 * create 1 register frame
254 interp
->bp
= calloc(NUM_REGISTERS
, sizeof (struct Reg
));
256 * and some space for opcodes
258 interp
->op_func
= malloc(OP_MAX
* sizeof (void*));
259 interp
->op_info
= malloc(OP_MAX
* sizeof (char*));
261 * define opcode function and opcode info
274 interp
->code
= malloc(sizeof (struct pf
));
275 interp
->code
->byte_code
= prog
;
278 * create a simplified constant table
281 interp
->code
->const_table
= malloc(N_CONSTS
* sizeof (char*));
282 interp
->code
->const_table
[0] = "\n";
283 interp
->code
->const_table
[1] = "done\n";
284 interp
->code
->const_table
[2] = "error\n";
285 interp
->code
->const_table
[3] = "usage: ./nanoparrot mops\n";
290 =item C<int main(int argc, char *argv[])>
292 Initialize a minimal Parrotesque interpreter and run some hard-coded bytecode.
299 main(int argc
, char *argv
[])
307 { OP_set_i_ic
, 4, 100000000, /* set I4, n */
308 OP_print_i
, 4, /* print I4 */
309 OP_print_sc
, 0, /* print "\n" */
310 OP_set_i_ic
, 5, 1, /* set I5, 1 */
311 OP_sub_i_i_i
, 4, 4, 5, /* L1: sub I4, I4, I5 */
312 OP_if_i_ic
, 4, -4, /* if I4, L1 */
313 OP_print_sc
, 1, /* print "done\n" */
318 OP_set_i_ic
, 0, 2, /* set I0, 2 */
319 OP_if_i_ic
, 0, 6, /* if I0, L1 */
320 OP_print_sc
, 2, /* print "error\n" */
322 OP_print_sc
, 3, /* L1: print "usage...\n" */
325 Interp
*interp
= malloc(sizeof (Interp
));
329 if (strcmp(argv
[1], "mops") == 0)
339 * c-file-style: "parrot"
341 * vim: expandtab shiftwidth=4: