]> mj.ucw.cz Git - umpf.git/blob - code.c
1f47c3da2530ea0b327df34d58a4bc71b75cb34c
[umpf.git] / code.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5
6 #include "umpf.h"
7
8 struct list* 
9 new_var_hash(void)
10 {
11         struct list* res;
12         int i;
13
14         res = xmalloc (HASHSIZE * sizeof(struct list));
15         for (i = 0; i < HASHSIZE; i++)
16                 list_init(res + i);
17         
18         return res;
19 }
20
21 int
22 get_bucket_number(char* name)
23 {
24         unsigned int n = 0;
25         unsigned char* p = name;
26
27         while (*p != '\0'){
28                 n = n * MAGIC + toupper(*p++);
29         }
30         n %= HASHSIZE;
31
32         return n;
33 }
34
35 /* if not found, variable with value "" is created  */ 
36 int
37 find_var(char* name, struct list* hash)
38 {
39         int n;
40         struct variable *p;
41
42         n = get_bucket_number(name);
43         int nocase = isupper(*name);
44         LIST_FOREACH(p, hash + n)
45                 if (!(nocase ? strcasecmp : strcmp)(p->name,name))
46                         return p->varcode;
47
48         p = xmalloc(sizeof(struct variable));
49         p->name = xstrdup(name);
50         p->varcode = current_varcode++;
51         list_add_last(hash+n, &p->car);
52
53         return p->varcode;
54 }
55
56 int
57 store_const(char* c)
58 {
59         if (cur_const_n >= cur_const_s) {
60                 cur_const_s *= 2;
61                 const_tab = xrealloc(const_tab, cur_const_s);
62         }
63
64         const_tab[cur_const_n] = c;
65
66         return -cur_const_n++;  
67 }
68
69 static void
70 new_instr(struct code c, struct list* where)
71 {
72         struct code* p = xmalloc(sizeof(struct code));
73         *p = c;
74         if (where)
75                 list_add_last(where, &p->car);
76         else
77                 list_add_last(&input_code, &p->car);
78 }
79
80 static int
81 new_3par_instr(int opcode, int left, int right, int pref_var, 
82                  struct list* where)
83 {
84         struct code ins;
85
86         ins.opcode = opcode;
87         ins.u.tpop.l = left;
88         ins.u.tpop.r = right;
89         if (pref_var >= 0)
90                 ins.u.tpop.res = pref_var;
91         else
92                 ins.u.tpop.res = current_varcode++;;
93         new_instr(ins, where);
94         return ins.u.tpop.res;
95 }
96
97 /* return number of variable where lies result 
98  * pref_var < 0 => no preference
99  */
100 static int
101 evaluate(struct tree* t, int pref_var, struct list* where)
102 {
103         if (t->st == ST_LEAF) { 
104                 return t->pt.leaf.n;
105         } else if (t->st == ST_OP) {
106                 int left, right;
107                 left = evaluate(t->pt.op.left, -1, where);
108                 right = evaluate(t->pt.op.right, -1, where);
109                 switch (t->pt.op.op) {
110                         case '.':
111                                 return new_3par_instr(OPC_CAT, left, 
112                                         right, pref_var, where);
113                                 break;
114                         case '+':
115                                 return new_3par_instr(OPC_PLUS, left, 
116                                         right, pref_var, where);
117                                 break;
118                         case '-':
119                                 return new_3par_instr(OPC_MINUS, left, 
120                                         right, pref_var, where);
121                                 break;
122                         case '*':
123                                 return new_3par_instr(OPC_MUL, left, 
124                                         right, pref_var, where);
125                                 break;
126                         case '/':
127                                 return new_3par_instr(OPC_DIV, left, 
128                                         right, pref_var, where);
129                                 break;
130                         default:
131                                 die("evaluate: got to default");
132                 }
133         } else
134                 die("evaluate: I can evaluate only expressions but I got %d",
135                         t->st);
136 }
137
138 static void
139 do_ass(struct tree* t, struct list* where)
140 {
141         int var_l, var_r;
142         struct code ins;
143         var_l = t->pt.ass.left->pt.leaf.n;
144         var_r = evaluate(t->pt.ass.right, -1, where);
145         
146         ins.opcode = OPC_SET;
147         ins.u.set.l = var_l;
148         ins.u.set.r = var_r;
149         new_instr(ins, where);
150
151 }
152
153 static int
154 eval_cond(struct tree *t, int pref_var, struct list* where)
155 {
156         int left, right;
157         if (t->pt.cond.type == JUST_BOOL) {
158                 if (t->pt.cond.left->st == ST_LEAF)
159                         return t->pt.cond.left->pt.leaf.n;
160                 if (t->pt.cond.left->st == ST_OP)
161                         return evaluate(t->pt.cond.left, -1, where);
162                 else
163                         die("eval_cond: %d cannot be JUST_BOOL\n", 
164                         t->pt.cond.left->st);
165         }
166         if (t->pt.cond.type == OP_REL) {
167                 left = evaluate(t->pt.cond.left, -1, where);
168                 right = evaluate(t->pt.cond.right, -1, where);
169
170                 switch (t->pt.cond.op) {                
171                         case '>':
172                                 return new_3par_instr (OPC_GT, left, 
173                                         right, pref_var, where);
174                                 break;
175                         case '<':
176                                 return new_3par_instr (OPC_LT, left, 
177                                         right, pref_var, where);
178                                 break;
179                         case CC('<','='):
180                                 return new_3par_instr (OPC_LE, left, 
181                                         right, pref_var, where);
182                                 break;
183                         case CC('>','='):
184                                 return new_3par_instr (OPC_GE, left, 
185                                         right, pref_var, where);
186                                 break;
187                         case CC('!','~'):
188                                 return new_3par_instr (OPC_NRE, left, 
189                                         right, pref_var, where);
190                                 break;
191                         case CC('~','~'):
192                                 return new_3par_instr (OPC_RE, left, 
193                                         right, pref_var, where);
194                                 break;
195                         case CC('=','='):
196                                 return new_3par_instr (OPC_EQ, left, 
197                                         right, pref_var, where);
198                                 break;
199                         case CC('!','='):
200                                 return new_3par_instr (OPC_NEQ, left, 
201                                         right, pref_var, where);
202                                 break;
203                         /* fixme: do more of them */
204                         default:
205                                 die("eval_cond: unknown relation op %c\n", 
206                                 t->pt.cond.op);
207
208                 }
209         }
210         if (t->pt.cond.type == OP_BOOL) {
211                 struct code ins;
212
213                 left = eval_cond(t->pt.cond.left, -1, where);
214                 if (t->pt.cond.op != '!') /* ! is unary */
215                         right = eval_cond(t->pt.cond.right, -1, where);
216                 switch (t->pt.cond.op) {
217                         case '&':
218                                 return new_3par_instr (OPC_AND, left, 
219                                         right, pref_var, where);
220                                 break;
221                         case '|':
222                                 return new_3par_instr (OPC_OR, left, 
223                                         right, pref_var, where);
224                                 break;
225                         case '^':
226                                 return new_3par_instr (OPC_XOR, left, 
227                                         right, pref_var, where);
228                                 break;
229                         case '!':
230                                 ins.opcode = OPC_NOT;
231                                 ins.u.dpop.par = left;
232                                 if (pref_var >= 0)
233                                         ins.u.dpop.res = pref_var;
234                                 else
235                                         ins.u.dpop.res = current_varcode++;;
236                                 new_instr(ins, where);
237                                 return ins.u.dpop.res;
238                                 break;
239                         default:
240                                 die("eval_cond: unknown boolean op %c\n", 
241                                 t->pt.cond.op);
242                 }
243         }
244         
245         die("eval_cond: unknown condition type");
246 }
247
248 static void
249 do_if(struct tree *t, struct list* where)
250 {
251         int c;
252         struct code ins, nop, jmp;
253         struct list* if_branch = xmalloc(sizeof(struct list));
254         struct list* else_branch = xmalloc(sizeof(struct list));
255
256         list_init(if_branch);
257         list_init(else_branch);
258         nop.opcode  = OPC_NOP;
259         jmp.opcode = OPC_JUMP;
260
261         c = eval_cond(t->pt.tif.c, -1, where);
262
263         compile(t->pt.tif.i, if_branch);        
264         compile(t->pt.tif.i, else_branch);      
265         new_instr(nop, if_branch);
266         new_instr(nop, else_branch);
267         jmp.u.jump.target = list_last(else_branch);
268         new_instr(jmp, if_branch);
269         
270         ins.opcode = OPC_JUMP_UNLESS;
271         ins.u.jump_unless.cond = c;
272         ins.u.jump_unless.target = list_last(if_branch);
273         new_instr(ins, where);
274         list_cat(where, if_branch);
275         list_cat(where, else_branch);
276
277         free(if_branch);
278         free(else_branch);
279 }
280
281 static void
282 do_arrow(struct tree* t, struct list* where)
283 {
284         int v;
285         struct code ins;
286
287
288         if (t->pt.arrow.left == K_COPY)
289                 ins.u.arrow.copy = 1;
290         else
291                 ins.u.arrow.copy = 0;
292         switch (t->pt.arrow.right) {
293                 case K_EMPTY:
294                         ins.opcode = OPC_DELIVER;
295                         break;
296                 case K_PIPE:
297                         ins.opcode = OPC_PIPE;
298                         break;
299                 case K_MAIL:
300                         ins.opcode = OPC_MAIL;
301                         break;
302                 case K_DISCARD:
303                         ins.opcode = OPC_DISCARD;
304                         break;
305                 default:
306                         die("do_arrow: This cannot happen ;-)");
307         }
308
309         if (t->pt.arrow.right != K_DISCARD) {
310                 v = evaluate(t->pt.arrow.s, -1, where);
311                 ins.u.arrow.what = v;
312         }
313
314         new_instr(ins, where);
315 }
316
317 static void
318 reset_temp_var_count(void)
319 {
320         current_varcode = temp_varcode_start;
321 }
322
323 void
324 compile(struct tree* t, struct list* where)
325 {
326         if (!t)
327                 return;
328         if (! where)
329                 where = &input_code;
330
331         switch(t->st) {
332                 case ST_BLOCK:
333                         reset_temp_var_count();
334                         compile(t->pt.block.head, where);
335                         compile(t->pt.block.tail, where);
336                         break;
337                 case ST_EMPTY:
338                         break;
339                 case ST_LEAF: //warn?
340                         break;
341                 case ST_ASS:
342                         do_ass(t, where);
343                         break;
344                 case ST_OP:
345                         evaluate(t, -1, where); //emit warning?
346                         break;
347                 case ST_IF:
348                         do_if(t, where);
349                         break;
350                 case ST_COND:
351                         eval_cond(t, -1, where); // warn?
352                 case ST_ARROW:
353                         do_arrow(t, where);
354                         break;
355                 default:
356                         die("compile: got to default, type: %d", t->st);
357         }
358 }
359
360 void
361 print_code(void)
362 {
363         struct code* p;
364
365         LIST_FOREACH(p, &input_code) {
366                 switch (p->opcode) {
367                         case OPC_SET:
368                                 printf("SET %d %d\n", p->u.set.l, p->u.set.r);
369                                 break; 
370                         case OPC_CAT:
371                                 printf("CAT %d %d %d\n", p->u.tpop.l,
372                                 p->u.tpop.r, p->u.tpop.res);
373                                 break;
374                         case OPC_JUMP:
375                                 printf("JUMP %d\n", (int) p->u.jump.target);
376                                 break;
377                         case OPC_JUMP_UNLESS:
378                                 printf("JUMP_UNLESS %d %d\n", p->u.jump_unless.cond,(int) p->u.jump_unless.target);
379                                 break;
380                         case OPC_GT:
381                                 printf("GT %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
382                                 break;
383                         case OPC_LT:
384                                 printf("LT %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
385                                 break;
386                         case OPC_LE:
387                                 printf("LE %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
388                                 break;
389                         case OPC_GE:
390                                 printf("GE %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
391                                 break;
392                         case OPC_RE:
393                                 printf("RE %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
394                                 break;
395                         case OPC_NRE:
396                                 printf("NRE %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
397                                 break;
398                         case OPC_NEQ:
399                                 printf("NEQ %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
400                                 break;
401                         case OPC_EQ:
402                                 printf("EQ %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
403                                 break;
404                         case OPC_AND:
405                                 printf("AND %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
406                                 break;
407                         case OPC_OR:
408                                 printf("OR %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
409                                 break;
410                         case OPC_XOR:
411                                 printf("XOR %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
412                                 break;
413                         case OPC_PLUS:
414                                 printf("PLUS %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
415                                 break;
416                         case OPC_MINUS:
417                                 printf("MINUS %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
418                                 break;
419                         case OPC_MUL:
420                                 printf("MUL %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
421                                 break;
422                         case OPC_DIV:
423                                 printf("DIV %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
424                                 break;
425                         case OPC_NOT:
426                                 printf("NOT %d %d\n", p->u.dpop.par, p->u.dpop.res);
427                                 break;
428                         case OPC_NOP:
429                                 puts("NOP");    
430                                 break;
431                         case OPC_PIPE:
432                                 printf("PIPE %d %d\n", p->u.arrow.what, p->u.arrow.copy);
433                                 break;
434                         case OPC_DELIVER:
435                                 printf("DELIVER %d %d\n", p->u.arrow.what, p->u.arrow.copy);
436                                 break;
437                         case OPC_MAIL:
438                                 printf("MAIL %d %d\n", p->u.arrow.what, p->u.arrow.copy);
439                                 break;
440                         case OPC_DISCARD:
441                                 puts("DISCARD");
442                                 break;
443                         default:
444                                 printf("not implemented, opcode: %d\n",
445                                 p->opcode);
446                 }
447         }
448 }