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