]> mj.ucw.cz Git - umpf.git/blob - code.c
add arrows
[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 #define HASHSIZE 103
9 #define MAGIC 19
10
11 struct list* 
12 new_var_hash(void)
13 {
14         struct list* res;
15         int i;
16
17         res = xmalloc (HASHSIZE * sizeof(struct list));
18         for (i = 0; i < HASHSIZE; i++)
19                 list_init(res + i);
20         
21         return res;
22 }
23
24 static int
25 get_bucket_number(char* name)
26 {
27         unsigned int n = 0;
28         unsigned char* p = name;
29
30         while (*p != '\0'){
31                 n = n * MAGIC + toupper(*p++);
32         }
33         n %= HASHSIZE;
34
35         return n;
36 }
37
38 /* if not found, variable with value "" is created  */ 
39 int
40 find_var(char* name, struct list* hash)
41 {
42         int n;
43         struct variable *p;
44
45         n = get_bucket_number(name);
46         int nocase = isupper(*name);
47         LIST_FOREACH(p, hash + n)
48                 if (!(nocase ? strcasecmp : strcmp)(p->name,name))
49                         return p->varcode;
50
51         p = xmalloc(sizeof(struct variable));
52         p->name = xstrdup(name);
53         p->varcode = current_varcode++;
54         list_add_last(hash+n, &p->car);
55
56         return p->varcode;
57 }
58
59 int
60 store_const(char* c)
61 {
62         if (cur_const_n >= cur_const_s) {
63                 cur_const_s *= 2;
64                 const_tab = xrealloc(const_tab, cur_const_s);
65         }
66
67         const_tab[cur_const_n] = c;
68
69         return -cur_const_n++;  
70 }
71
72 static void
73 new_instr(struct code c, struct list* where)
74 {
75         struct code* p = xmalloc(sizeof(struct code));
76         *p = c;
77         if (where)
78                 list_add_last(where, &p->car);
79         else
80                 list_add_last(&input_code, &p->car);
81 }
82
83 /* return number of variable where lies result 
84  * pref_var < 0 => no preference
85  */
86 static int
87 evaluate(struct tree* t, int pref_var, struct list* where)
88 {
89         struct code ins;
90
91         if (t->st == ST_LEAF) { 
92                 return t->pt.leaf.n;
93         } else if (t->st == ST_OP) {
94                 int left, right;
95                 left = evaluate(t->pt.op.left, -1, where);
96                 right = evaluate(t->pt.op.right, -1, where);
97                 switch (t->pt.op.op) {
98                         case '.':
99                                 ins.opcode = CAT;
100                                 ins.u.tpop.l = left;
101                                 ins.u.tpop.r = right;
102                                 if (pref_var >= 0)
103                                         ins.u.tpop.res = pref_var;
104                                 else
105                                         ins.u.tpop.res = current_varcode++;;
106                                 new_instr(ins, where);
107                                 return ins.u.tpop.res;
108                                 break;
109                         default:
110                                 die("evaluate: got to default");
111                 }
112         } else
113                 die("evaluate: I can evaluate only expressions but I got %d",
114                         t->st);
115 }
116
117 static void
118 do_ass(struct tree* t, struct list* where)
119 {
120         int var_l, var_r;
121         struct code ins;
122         var_l = t->pt.ass.left->pt.leaf.n;
123         var_r = evaluate(t->pt.ass.right, -1, where);
124         
125         ins.opcode = SET;
126         ins.u.set.l = var_l;
127         ins.u.set.r = var_r;
128         new_instr(ins, where);
129
130 }
131
132 static int
133 new_cond_instr(int opcode, int left, int right, int pref_var, 
134                  struct list* where)
135 {
136         struct code ins;
137
138         ins.opcode = opcode;
139         ins.u.tpop.l = left;
140         ins.u.tpop.r = right;
141         if (pref_var >= 0)
142                 ins.u.tpop.res = pref_var;
143         else
144                 ins.u.tpop.res = current_varcode++;;
145         new_instr(ins, where);
146         return ins.u.tpop.res;
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_cond_instr(GT, left, 
169                                         right, pref_var, where);
170                                 break;
171                         /* fixme: do more of them */
172                         default:
173                                 die("eval_cond: unknown relation op %c\n", 
174                                 t->pt.cond.op);
175
176                 }
177         }
178         if (t->pt.cond.type == OP_BOOL) {
179                 left = eval_cond(t->pt.cond.left, -1, where);
180                 right = eval_cond(t->pt.cond.right, -1, where);
181                 switch (t->pt.cond.op) {
182                         case '&':
183                                 return new_cond_instr(AND, left, 
184                                         right, pref_var, where);
185                                 break;
186                         default:
187                                 die("eval_cond: unknown boolean op %c\n", 
188                                 t->pt.cond.op);
189                 }
190         }
191         
192         die("eval_cond: unknown condition type");
193 }
194
195 static void
196 do_if(struct tree *t, struct list* where)
197 {
198         int c;
199         struct code ins, nop, jmp;
200         struct list* if_branch = xmalloc(sizeof(struct list));
201         struct list* else_branch = xmalloc(sizeof(struct list));
202
203         list_init(if_branch);
204         list_init(else_branch);
205         nop.opcode  = NOP;
206         jmp.opcode = JUMP;
207
208         c = eval_cond(t->pt.tif.c, -1, where);
209
210         compile(t->pt.tif.i, if_branch);        
211         compile(t->pt.tif.i, else_branch);      
212         new_instr(nop, if_branch);
213         new_instr(nop, else_branch);
214         jmp.u.jump.target = list_last(else_branch);
215         new_instr(jmp, if_branch);
216         
217         ins.opcode = JUMP_UNLESS;
218         ins.u.jump_unless.cond = c;
219         ins.u.jump_unless.target = list_last(if_branch);
220         new_instr(ins, where);
221         list_cat(where, if_branch);
222         list_cat(where, else_branch);
223
224         free(if_branch);
225         free(else_branch);
226 }
227
228 static void
229 do_arrow(struct tree* t, struct list* where)
230 {
231         int v;
232         struct code ins;
233
234         v = evaluate(t->pt.arrow.s, -1, where);
235         ins.u.arrow.what = v;
236
237         if (t->pt.arrow.left == K_COPY)
238                 ins.u.arrow.copy = 1;
239         else
240                 ins.u.arrow.copy = 0;
241         switch (t->pt.arrow.right) {
242                 case K_EMPTY:
243                         ins.opcode = STORE;
244                         break;
245                 case K_PIPE:
246                         ins.opcode = PIPE;
247                         break;
248                 case K_MAIL:
249                         ins.opcode = MAIL;
250                         break;
251                 default:
252                         die("do_arrow: This cannot happen ;-)");
253         }
254         new_instr(ins, where);
255 }
256
257 static void
258 reset_temp_var_count(void)
259 {
260         current_varcode = temp_varcode_start;
261 }
262
263 void
264 compile(struct tree* t, struct list* where)
265 {
266         if (!t)
267                 return;
268         if (! where)
269                 where = &input_code;
270
271         switch(t->st) {
272                 case ST_BLOCK:
273                         reset_temp_var_count();
274                         compile(t->pt.block.head, where);
275                         compile(t->pt.block.tail, where);
276                         break;
277                 case ST_EMPTY:
278                         break;
279                 case ST_LEAF: //warn?
280                         break;
281                 case ST_ASS:
282                         do_ass(t, where);
283                         break;
284                 case ST_OP:
285                         evaluate(t, -1, where); //emit warning?
286                         break;
287                 case ST_IF:
288                         do_if(t, where);
289                         break;
290                 case ST_COND:
291                         eval_cond(t, -1, where); // warn?
292                 case ST_ARROW:
293                         do_arrow(t, where);
294                 default:
295                         die("compile: got to default");
296         }
297 }
298
299 void
300 print_code(void)
301 {
302         struct code* p;
303
304         LIST_FOREACH(p, &input_code) {
305                 switch (p->opcode) {
306                         case SET:
307                                 printf("SET %d %d\n", p->u.set.l, p->u.set.r);
308                                 break; 
309                         case CAT:
310                                 printf("CAT %d %d %d\n", p->u.tpop.l,
311                                 p->u.tpop.r, p->u.tpop.res);
312                                 break;
313                         case JUMP:
314                                 printf("JUMP %d\n", (int) p->u.jump.target);
315                                 break;
316                         case JUMP_UNLESS:
317                                 printf("JUMP_UNLESS %d %d\n", p->u.jump_unless.cond,(int) p->u.jump_unless.target);
318                                 break;
319                         case GT:
320                                 printf("GT %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
321                                 break;
322                         case AND:
323                                 printf("AND %d %d %d\n", p->u.tpop.l, p->u.tpop.r, p->u.tpop.res);
324                                 break;
325                         case NOP:
326                                 puts("NOP");    
327                                 break;
328                         default:
329                                 printf("not implemented, opcode: %d\n",
330                                 p->opcode);
331                 }
332         }
333 }