]> mj.ucw.cz Git - umpf.git/blob - code.c
really do local delivery
[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         if (current_varcode > max_varcode)
317                 max_varcode = current_varcode;
318         current_varcode = temp_varcode_start;
319 }
320
321 void
322 compile(struct tree* t, struct list* where)
323 {
324         if (!t)
325                 return;
326         if (! where)
327                 where = &input_code;
328
329         switch(t->st) {
330                 case ST_BLOCK:
331                         reset_temp_var_count();
332                         compile(t->pt.block.head, where);
333                         compile(t->pt.block.tail, where);
334                         break;
335                 case ST_EMPTY:
336                         break;
337                 case ST_LEAF: //warn?
338                         break;
339                 case ST_ASS:
340                         do_ass(t, where);
341                         break;
342                 case ST_OP:
343                         evaluate(t, -1, where); //emit warning?
344                         break;
345                 case ST_IF:
346                         do_if(t, where);
347                         break;
348                 case ST_COND:
349                         eval_cond(t, -1, where); // warn?
350                 case ST_ARROW:
351                         do_arrow(t, where);
352                         break;
353                 default:
354                         die("compile: got to default, type: %d", t->st);
355         }
356 }
357
358 void
359 print_code(void)
360 {
361         struct code* p;
362
363         LIST_FOREACH(p, &input_code) {
364                 switch (p->opcode) {
365                         case OPC_SET:
366                                 printf("SET %d %d\n", p->u.set.l, p->u.set.r);
367                                 break; 
368                         case OPC_CAT:
369                                 printf("CAT %d %d %d\n", p->u.tpop.l,
370                                 p->u.tpop.r, p->u.tpop.res);
371                                 break;
372                         case OPC_JUMP:
373                                 printf("JUMP %d\n", (int) p->u.jump.target);
374                                 break;
375                         case OPC_JUMP_UNLESS:
376                                 printf("JUMP_UNLESS %d %d\n", p->u.jump_unless.cond,(int) p->u.jump_unless.target);
377                                 break;
378                         case OPC_GT:
379                                 printf("GT %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
380                                 break;
381                         case OPC_LT:
382                                 printf("LT %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
383                                 break;
384                         case OPC_LE:
385                                 printf("LE %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
386                                 break;
387                         case OPC_GE:
388                                 printf("GE %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
389                                 break;
390                         case OPC_RE:
391                                 printf("RE %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
392                                 break;
393                         case OPC_NRE:
394                                 printf("NRE %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
395                                 break;
396                         case OPC_NEQ:
397                                 printf("NEQ %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
398                                 break;
399                         case OPC_EQ:
400                                 printf("EQ %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
401                                 break;
402                         case OPC_AND:
403                                 printf("AND %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
404                                 break;
405                         case OPC_OR:
406                                 printf("OR %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
407                                 break;
408                         case OPC_XOR:
409                                 printf("XOR %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
410                                 break;
411                         case OPC_PLUS:
412                                 printf("PLUS %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
413                                 break;
414                         case OPC_MINUS:
415                                 printf("MINUS %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
416                                 break;
417                         case OPC_MUL:
418                                 printf("MUL %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
419                                 break;
420                         case OPC_DIV:
421                                 printf("DIV %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
422                                 break;
423                         case OPC_NOT:
424                                 printf("NOT %d %d\n", p->u.dpop.par, p->u.dpop.res);
425                                 break;
426                         case OPC_NOP:
427                                 puts("NOP");    
428                                 break;
429                         case OPC_PIPE:
430                                 printf("PIPE %d %d\n", p->u.arrow.what, p->u.arrow.copy);
431                                 break;
432                         case OPC_DELIVER:
433                                 printf("DELIVER %d %d\n", p->u.arrow.what, p->u.arrow.copy);
434                                 break;
435                         case OPC_MAIL:
436                                 printf("MAIL %d %d\n", p->u.arrow.what, p->u.arrow.copy);
437                                 break;
438                         case OPC_DISCARD:
439                                 puts("DISCARD");
440                                 break;
441                         default:
442                                 printf("not implemented, opcode: %d\n",
443                                 p->opcode);
444                 }
445         }
446 }