[PDD] Add docs for the Parrot_PMC_push_* and Parrot_PMC_pop_* functions
[parrot.git] / examples / c / nanoparrot.c
blob912fc20f286e23146337beb59f46c10169da3a46
1 /*
2 * Copyright (C) 2001-2008, Parrot Foundation.
3 * $Id$
5 =head1 NAME
7 examples/c/nanoparrot.c
9 =head1 DESCRIPTION
11 demonstrates how the interpreter interprets bytecode
12 its vastly simplified but the very basics are the same
14 - compile with:
15 -DTRACE ... turn on opcode tracing (FUNC_CORE, SWITCH_CORE only)
16 -DFUNC_CORE run function base opcodes
17 -DF same
18 -DSWITCH_CORE run switched opcode core
19 -DS same
20 else run CGOTO core
22 The CGOTO run core works only for compilers like gcc that allow
23 labels as values.
25 =head1 SYNOPSIS
27 cc -o nanoparrot -Wall nanoparrot.c -O3 && time ./nanoparrot mops
29 =head2 Functions
31 =over 4
33 =cut
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <string.h>
41 typedef int INTVAL;
42 typedef int opcode_t;
43 typedef double FLOATVAL;
44 typedef void PMC;
45 typedef void STRING;
47 #define NUM_REGISTERS 32
49 struct Reg {
50 INTVAL int_reg;
51 FLOATVAL num_reg;
52 STRING *string_reg;
53 PMC *pmc_reg;
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)]
62 #else
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)]]
66 #endif
68 struct pf {
69 opcode_t *byte_code;
70 char **const_table;
73 typedef struct Interp {
74 struct Reg *bp;
75 struct pf *code;
76 opcode_t *(**op_func)(opcode_t *, struct Interp*);
77 const char **op_info;
78 int flags;
79 } Interp;
82 * list of all opcodes
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), \
87 OP(MAX)
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
97 #define OP(x) OP_##x
98 typedef enum { OPCODES } opcodes;
99 #undef OP
101 #ifdef F
102 # define FUNC_CORE
103 #endif
104 #ifdef S
105 # define SWITCH_CORE
106 #endif
108 #if defined(FUNC_CORE)
109 # ifdef TRACE
110 # define ENDRUN \
111 static void \
112 run(Interp *interp, opcode_t *pc) \
114 while (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); \
120 # else
121 # define ENDRUN \
122 static void \
123 run(Interp *interp, opcode_t *pc) \
125 while (pc) { \
126 pc = interp->op_func[*pc](pc, interp); \
129 # endif
131 # define DISPATCH
132 # define ENDDISPATCH
133 # define CASE(function) \
134 static opcode_t * \
135 function(opcode_t *pc, Interp *interp) \
138 # define NEXT return pc; }
139 # define DONE return 0; }
141 #else /* !FUNC_CORE */
143 # define ENDRUN }
145 # if defined(SWITCH_CORE)
149 =item C<static void run(Interp *interp, opcode_t *pc)>
151 Execute a single opcode.
153 =cut
157 static void
158 run(Interp *interp, opcode_t *pc)
160 # ifdef TRACE
161 # define DISPATCH \
162 for (;;) { \
163 printf("PC %2d %s\n", pc - interp->code->byte_code, \
164 interp->op_info[*pc]); \
165 switch (*pc) {
166 # else
167 # define DISPATCH \
168 for (;;) { \
169 switch (*pc) {
170 # endif
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); \
178 # else /* CGOTO */
180 static void
181 run(Interp *interp, opcode_t *pc)
183 # define OP(x) &&lOP_##x
184 static void *labels[] = { OPCODES };
185 # undef OP
186 # define CASE(x) lOP_##x:
187 # define NEXT goto *labels[*pc];
188 # define DISPATCH NEXT
189 # define ENDDISPATCH
190 # define DONE return;
192 # endif /* SWITCH or CGOTO */
193 #endif /* !FUNC_CORE */
196 * dispatch loop / opcode (function) bodies i.e. the .ops files
199 DISPATCH
200 CASE(end)
201 DONE
202 CASE(print_sc)
203 printf("%s", SCONST(1));
204 pc += 2;
205 NEXT
206 CASE(print_i)
207 printf("%d", IREG(1));
208 pc += 2;
209 NEXT
210 CASE(set_i_ic)
211 IREG(1) = ICONST(2);
212 pc += 3;
213 NEXT
214 CASE(if_i_ic)
215 if (IREG(1))
216 pc += ICONST(2);
217 else
218 pc += 3;
219 NEXT
220 CASE(sub_i_i_i)
221 IREG(1) = IREG(2) - IREG(3);
222 pc += 4;
223 NEXT
224 CASE(MAX)
225 printf("illegal opcode\n");
226 exit(EXIT_FAILURE);
227 NEXT
228 ENDDISPATCH
229 ENDRUN
231 #ifdef FUNC_CORE
232 # define DEF_OP(op) \
233 interp->op_func[OP_##op] = (op); \
234 interp->op_info[OP_##op] = #op
235 #else
236 # define DEF_OP(op) \
237 interp->op_info[OP_##op] = #op
238 #endif
242 =item C<static void init(Interp *interp, opcode_t *prog)>
244 =cut
248 static void
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
263 DEF_OP(end);
264 DEF_OP(print_sc);
265 DEF_OP(print_i);
266 DEF_OP(set_i_ic);
267 DEF_OP(if_i_ic);
268 DEF_OP(sub_i_i_i);
269 DEF_OP(MAX);
272 * the "packfile"
274 interp->code = malloc(sizeof (struct pf));
275 interp->code->byte_code = prog;
278 * create a simplified constant table
280 #define N_CONSTS 4
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.
294 =cut
299 main(int argc, char *argv[])
301 opcode_t *prog;
304 * the mops main loop
306 opcode_t mops[] =
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" */
314 OP_end /* end */
316 opcode_t usage[] =
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" */
321 OP_end, /* end */
322 OP_print_sc, 3, /* L1: print "usage...\n" */
323 OP_end /* end */
325 Interp *interp = malloc(sizeof (Interp));
327 prog = usage;
328 if (argc > 1) {
329 if (strcmp(argv[1], "mops") == 0)
330 prog = mops;
332 init(interp, prog);
333 run(interp, prog);
334 return 0;
338 * Local variables:
339 * c-file-style: "parrot"
340 * End:
341 * vim: expandtab shiftwidth=4: