* lib/Parrot/Pmc2c/MethodEmitter.pm:
[parrot.git] / examples / c / nanoparrot.c
blob153e53a99b76a4089fd4dd18deedb4bb85968dae
1 /*
2 * Copyright (C) 2001-2008, The Perl 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
150 run(Interp *interp, opcode_t *pc)>
152 RT#48260: Not yet documented!!!
154 =cut
158 static void
159 run(Interp *interp, opcode_t *pc)
161 # ifdef TRACE
162 # define DISPATCH \
163 for (;;) { \
164 printf("PC %2d %s\n", pc - interp->code->byte_code, \
165 interp->op_info[*pc]); \
166 switch (*pc) {
167 # else
168 # define DISPATCH \
169 for (;;) { \
170 switch (*pc) {
171 # endif
173 # define CASE(x) case OP_ ## (x):
174 # define NEXT continue;
175 # define DONE return;
176 # define ENDDISPATCH default : printf("illegal instruction"); \
177 exit(EXIT_FAILURE); \
179 # else /* CGOTO */
181 static void
182 run(Interp *interp, opcode_t *pc)
184 # define OP(x) &&lOP_##x
185 static void *labels[] = { OPCODES };
186 # undef OP
187 # define CASE(x) lOP_##x:
188 # define NEXT goto *labels[*pc];
189 # define DISPATCH NEXT
190 # define ENDDISPATCH
191 # define DONE return;
193 # endif /* SWITCH or CGOTO */
194 #endif /* !FUNC_CORE */
197 * dispatch loop / opcode (function) bodies i.e. the .ops files
200 DISPATCH
201 CASE(end)
202 DONE
203 CASE(print_sc)
204 printf("%s", SCONST(1));
205 pc += 2;
206 NEXT
207 CASE(print_i)
208 printf("%d", IREG(1));
209 pc += 2;
210 NEXT
211 CASE(set_i_ic)
212 IREG(1) = ICONST(2);
213 pc += 3;
214 NEXT
215 CASE(if_i_ic)
216 if (IREG(1))
217 pc += ICONST(2);
218 else
219 pc += 3;
220 NEXT
221 CASE(sub_i_i_i)
222 IREG(1) = IREG(2) - IREG(3);
223 pc += 4;
224 NEXT
225 CASE(MAX)
226 printf("illegal opcode\n");
227 exit(EXIT_FAILURE);
228 NEXT
229 ENDDISPATCH
230 ENDRUN
232 #ifdef FUNC_CORE
233 # define DEF_OP(op) \
234 interp->op_func[OP_ ## op] = op; \
235 interp->op_info[OP_ ## op] = #op
236 #else
237 # define DEF_OP(op) \
238 interp->op_info[OP_ ## op] = #op
239 #endif
243 =item C<static void
244 init(Interp *interp, opcode_t *prog)>
246 RT#48260: Not yet documented!!!
248 =cut
252 static void
253 init(Interp *interp, opcode_t *prog)
256 * create 1 register frame
258 interp->bp = calloc(NUM_REGISTERS, sizeof (struct Reg));
260 * and some space for opcodes
262 interp->op_func = malloc(OP_MAX * sizeof (void*));
263 interp->op_info = malloc(OP_MAX * sizeof (char*));
265 * define opcode function and opcode info
267 DEF_OP(end);
268 DEF_OP(print_sc);
269 DEF_OP(print_i);
270 DEF_OP(set_i_ic);
271 DEF_OP(if_i_ic);
272 DEF_OP(sub_i_i_i);
273 DEF_OP(MAX);
276 * the "packfile"
278 interp->code = malloc(sizeof (struct pf));
279 interp->code->byte_code = prog;
282 * create a simplified constant table
284 #define N_CONSTS 4
285 interp->code->const_table = malloc(N_CONSTS * sizeof (char*));
286 interp->code->const_table[0] = "\n";
287 interp->code->const_table[1] = "done\n";
288 interp->code->const_table[2] = "error\n";
289 interp->code->const_table[3] = "usage: ./nanoparrot mops\n";
294 =item C<int
295 main(int argc, char *argv[])>
297 RT#48260: Not yet documented!!!
299 =cut
304 main(int argc, char *argv[])
306 opcode_t *prog;
309 * the mops main loop
311 opcode_t mops[] =
312 { OP_set_i_ic, 4, 100000000, /* set I4, n */
313 OP_print_i, 4, /* print I4 */
314 OP_print_sc, 0, /* print "\n" */
315 OP_set_i_ic, 5, 1, /* set I5, 1 */
316 OP_sub_i_i_i, 4, 4, 5, /* L1: sub I4, I4, I5 */
317 OP_if_i_ic, 4, -4, /* if I4, L1 */
318 OP_print_sc, 1, /* print "done\n" */
319 OP_end /* end */
321 opcode_t usage[] =
323 OP_set_i_ic, 0, 2, /* set I0, 2 */
324 OP_if_i_ic, 0, 6, /* if I0, L1 */
325 OP_print_sc, 2, /* print "error\n" */
326 OP_end, /* end */
327 OP_print_sc, 3, /* L1: print "usage...\n" */
328 OP_end /* end */
330 Interp *interp = malloc(sizeof (Interp));
332 prog = usage;
333 if (argc > 1) {
334 if (strcmp(argv[1], "mops") == 0)
335 prog = mops;
337 init(interp, prog);
338 run(interp, prog);
339 return 0;
343 * Local variables:
344 * c-file-style: "parrot"
345 * End:
346 * vim: expandtab shiftwidth=4: