]> mj.ucw.cz Git - umpf.git/blob - code.c
bf3906f9525838915175380dc07ad63250779413
[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         } 
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         }
131         die("evaluate: Never can get here :)");
132 }
133
134 static void
135 do_ass(struct tree* t, struct list* where)
136 {
137         int var_l, var_r;
138         struct code ins;
139         var_l = t->pt.ass.left->pt.leaf.n;
140         var_r = evaluate(t->pt.ass.right, -1, where);
141         
142         ins.opcode = OPC_SET;
143         ins.u.set.l = var_l;
144         ins.u.set.r = var_r;
145         new_instr(ins, where);
146
147 }
148
149 static int
150 eval_cond(struct tree *t, int pref_var, struct list* where)
151 {
152         int left, right;
153         if (t->pt.cond.type == JUST_BOOL) {
154                 if (t->pt.cond.left->st == ST_LEAF)
155                         return t->pt.cond.left->pt.leaf.n;
156                 if (t->pt.cond.left->st == ST_OP)
157                         return evaluate(t->pt.cond.left, -1, where);
158                 else
159                         die("eval_cond: %d cannot be JUST_BOOL\n", 
160                         t->pt.cond.left->st);
161         }
162         if (t->pt.cond.type == OP_REL) {
163                 left = evaluate(t->pt.cond.left, -1, where);
164                 right = evaluate(t->pt.cond.right, -1, where);
165
166                 switch (t->pt.cond.op) {                
167                         case '>':
168                                 return new_3par_instr (OPC_GT, left, 
169                                         right, pref_var, where);
170                                 break;
171                         case '<':
172                                 return new_3par_instr (OPC_LT, left, 
173                                         right, pref_var, where);
174                                 break;
175                         case CC('<','='):
176                                 return new_3par_instr (OPC_LE, left, 
177                                         right, pref_var, where);
178                                 break;
179                         case CC('>','='):
180                                 return new_3par_instr (OPC_GE, left, 
181                                         right, pref_var, where);
182                                 break;
183                         case CC('!','~'):
184                                 return new_3par_instr (OPC_NRE, left, 
185                                         right, pref_var, where);
186                                 break;
187                         case CC('~','~'):
188                                 return new_3par_instr (OPC_RE, left, 
189                                         right, pref_var, where);
190                                 break;
191                         case CC('=','='):
192                                 return new_3par_instr (OPC_EQ, left, 
193                                         right, pref_var, where);
194                                 break;
195                         case CC('!','='):
196                                 return new_3par_instr (OPC_NEQ, left, 
197                                         right, pref_var, where);
198                                 break;
199                         /* fixme: do more of them */
200                         default:
201                                 die("eval_cond: unknown relation op %c\n", 
202                                 t->pt.cond.op);
203
204                 }
205         }
206         if (t->pt.cond.type == OP_BOOL) {
207                 struct code ins;
208
209                 left = eval_cond(t->pt.cond.left, -1, where);
210                 if (t->pt.cond.op != '!') /* ! is unary */
211                         right = eval_cond(t->pt.cond.right, -1, where);
212                 switch (t->pt.cond.op) {
213                         case '&':
214                                 return new_3par_instr (OPC_AND, left, 
215                                         right, pref_var, where);
216                                 break;
217                         case '|':
218                                 return new_3par_instr (OPC_OR, left, 
219                                         right, pref_var, where);
220                                 break;
221                         case '^':
222                                 return new_3par_instr (OPC_XOR, left, 
223                                         right, pref_var, where);
224                                 break;
225                         case '!':
226                                 ins.opcode = OPC_NOT;
227                                 ins.u.dpop.par = left;
228                                 if (pref_var >= 0)
229                                         ins.u.dpop.res = pref_var;
230                                 else
231                                         ins.u.dpop.res = current_varcode++;;
232                                 new_instr(ins, where);
233                                 return ins.u.dpop.res;
234                                 break;
235                         default:
236                                 die("eval_cond: unknown boolean op %c\n", 
237                                 t->pt.cond.op);
238                 }
239         }
240         
241         die("eval_cond: unknown condition type");
242 }
243
244 static void
245 do_if(struct tree *t, struct list* where)
246 {
247         int c;
248         struct code ins, nop, jmp;
249         struct list* if_branch = xmalloc(sizeof(struct list));
250         struct list* else_branch = xmalloc(sizeof(struct list));
251
252         list_init(if_branch);
253         list_init(else_branch);
254         nop.opcode  = OPC_NOP;
255         jmp.opcode = OPC_JUMP;
256
257         c = eval_cond(t->pt.tif.c, -1, where);
258
259         compile(t->pt.tif.i, if_branch);        
260         compile(t->pt.tif.i, else_branch);      
261         new_instr(nop, if_branch);
262         new_instr(nop, else_branch);
263         jmp.u.jump.target = list_last(else_branch);
264         new_instr(jmp, if_branch);
265         
266         ins.opcode = OPC_JUMP_UNLESS;
267         ins.u.jump_unless.cond = c;
268         ins.u.jump_unless.target = list_last(if_branch);
269         new_instr(ins, where);
270         list_cat(where, if_branch);
271         list_cat(where, else_branch);
272
273         free(if_branch);
274         free(else_branch);
275 }
276
277 static void
278 do_arrow(struct tree* t, struct list* where)
279 {
280         int v;
281         struct code ins;
282
283
284         if (t->pt.arrow.left == K_COPY)
285                 ins.u.arrow.copy = 1;
286         else
287                 ins.u.arrow.copy = 0;
288         switch (t->pt.arrow.right) {
289                 case K_EMPTY:
290                         ins.opcode = OPC_DELIVER;
291                         break;
292                 case K_PIPE:
293                         ins.opcode = OPC_PIPE;
294                         break;
295                 case K_MAIL:
296                         ins.opcode = OPC_MAIL;
297                         break;
298                 case K_DISCARD:
299                         ins.opcode = OPC_DISCARD;
300                         break;
301                 default:
302                         die("do_arrow: This cannot happen ;-)");
303         }
304
305         if (t->pt.arrow.right != K_DISCARD) {
306                 v = evaluate(t->pt.arrow.s, -1, where);
307                 ins.u.arrow.what = v;
308         }
309
310         new_instr(ins, where);
311 }
312
313 static void
314 reset_temp_var_count(void)
315 {
316         current_varcode = temp_varcode_start;
317 }
318
319 void
320 compile(struct tree* t, struct list* where)
321 {
322         if (!t)
323                 return;
324         if (! where)
325                 where = &input_code;
326
327         switch(t->st) {
328                 case ST_BLOCK:
329                         reset_temp_var_count();
330                         compile(t->pt.block.head, where);
331                         compile(t->pt.block.tail, where);
332                         break;
333                 case ST_EMPTY:
334                         break;
335                 case ST_LEAF: //warn?
336                         break;
337                 case ST_ASS:
338                         do_ass(t, where);
339                         break;
340                 case ST_OP:
341                         evaluate(t, -1, where); //emit warning?
342                         break;
343                 case ST_IF:
344                         do_if(t, where);
345                         break;
346                 case ST_COND:
347                         eval_cond(t, -1, where); // warn?
348                 case ST_ARROW:
349                         do_arrow(t, where);
350                         break;
351                 default:
352                         die("compile: got to default, type: %d", t->st);
353         }
354 }
355
356 void
357 print_code(void)
358 {
359         struct code* p;
360
361         LIST_FOREACH(p, &input_code) {
362                 switch (p->opcode) {
363                         case OPC_SET:
364                                 printf("SET %d %d\n", p->u.set.l, p->u.set.r);
365                                 break; 
366                         case OPC_CAT:
367                                 printf("CAT %d %d %d\n", p->u.tpop.l,
368                                 p->u.tpop.r, p->u.tpop.res);
369                                 break;
370                         case OPC_JUMP:
371                                 printf("JUMP %d\n", (int) p->u.jump.target);
372                                 break;
373                         case OPC_JUMP_UNLESS:
374                                 printf("JUMP_UNLESS %d %d\n", p->u.jump_unless.cond,(int) p->u.jump_unless.target);
375                                 break;
376                         case OPC_GT:
377                                 printf("GT %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
378                                 break;
379                         case OPC_LT:
380                                 printf("LT %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
381                                 break;
382                         case OPC_LE:
383                                 printf("LE %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
384                                 break;
385                         case OPC_GE:
386                                 printf("GE %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
387                                 break;
388                         case OPC_RE:
389                                 printf("RE %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
390                                 break;
391                         case OPC_NRE:
392                                 printf("NRE %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
393                                 break;
394                         case OPC_NEQ:
395                                 printf("NEQ %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
396                                 break;
397                         case OPC_EQ:
398                                 printf("EQ %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
399                                 break;
400                         case OPC_AND:
401                                 printf("AND %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
402                                 break;
403                         case OPC_OR:
404                                 printf("OR %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
405                                 break;
406                         case OPC_XOR:
407                                 printf("XOR %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
408                                 break;
409                         case OPC_PLUS:
410                                 printf("PLUS %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
411                                 break;
412                         case OPC_MINUS:
413                                 printf("MINUS %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
414                                 break;
415                         case OPC_MUL:
416                                 printf("MUL %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
417                                 break;
418                         case OPC_DIV:
419                                 printf("DIV %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
420                                 break;
421                         case OPC_NOT:
422                                 printf("NOT %d %d\n", p->u.dpop.par, p->u.dpop.res);
423                                 break;
424                         case OPC_NOP:
425                                 puts("NOP");    
426                                 break;
427                         case OPC_PIPE:
428                                 printf("PIPE %d %d\n", p->u.arrow.what, p->u.arrow.copy);
429                                 break;
430                         case OPC_DELIVER:
431                                 printf("DELIVER %d %d\n", p->u.arrow.what, p->u.arrow.copy);
432                                 break;
433                         case OPC_MAIL:
434                                 printf("MAIL %d %d\n", p->u.arrow.what, p->u.arrow.copy);
435                                 break;
436                         case OPC_DISCARD:
437                                 puts("DISCARD");
438                                 break;
439                         default:
440                                 printf("not implemented, opcode: %d\n",
441                                 p->opcode);
442                 }
443         }
444 }