codeb: iburg austricksen...
[uebersetzerbau-ss10.git] / codeb / parser.y
1 %{
2         #include <stdio.h>
3         #include <stdlib.h>
4         #include <string.h>
5         #include "symtable.h"
6         #include "chelper.h"
7         #include "tree.h"
8
9         #define MAX(A,B) (A > B ? A : B)
10 %}
11
12 %start Input
13 %token STRUCT END METHOD VAR IF THEN ELSE WHILE DO RETURN NOT OR THIS IDENT NUM ASSIGN
14
15 @macro xxputsin(xx,)
16         @i xx = @Statement.sin@;
17 @end
18
19 @macro statinout()
20         @i @Statement.sout@ = @Statement.sin@;
21         /* das
22          *> xxputsin(@Statement.sout@,)
23          * geht nicht, weil verschachtelte macros deaktiviert sind */
24 @end
25
26 @macro lblcountinout()
27         @i @Statement.lblcnt_out@ = @Statement.lblcnt_in@;
28 @end
29
30 /* beschreibung der attribute
31  * s: symboltabelle
32  * f: symboltabelle fuer quirks mit structur und parameter
33  * gparamges: anzahl der parameter in einer methode
34  * parms: parametercounter
35  * node: baum fuer iburg
36  * sin: symboltabelle fuer statement ("eingabe")
37  * sout: symboltabelle die aus einem statement wieder rauskommt ("ausgabe")
38  */
39 @autoinh s gparamges
40 @autosyn node imm
41
42 @attributes { char *name; } IDENT
43 @attributes { long val; } NUM
44 @attributes { struct symbol *f; int paramges; int parms; } Parms
45 @attributes { struct symbol *f; } Program Structdef;
46 @attributes { struct symbol *f; int offsetcount; } FeldID
47 @attributes { struct symbol *s; } Methoddef
48 @attributes { struct symbol *s; int gparamges; } Exprs
49 @attributes { struct symbol *s; int gparamges; int lblcnt_in; int lblcnt_out; } Statseq
50 @attributes { struct symbol *s; int gparamges; int lblcnt_in; int lblcnt_out; int reallblcnt; } Elsestat
51 @attributes { struct symbol *s; int gparamges; struct treenode *node; short imm; } Expr Minusterm Multerm Orterm Feld Term
52 @attributes { struct symbol *s; int gparamges; struct treenode *node; } Lexpr
53 @attributes { struct symbol *sin; int gparamges; struct symbol *sout; struct treenode *node; int vars; int lblcnt_in; int lblcnt_out; } Statement
54
55 @traversal @postorder c
56 @traversal @preorder reg
57 @traversal @preorder gen
58
59 %%
60 Input:
61           Program
62           @{
63             @i @Program.f@ = tab_new();
64             @gen printf("\t.text\n");
65           @}
66         ;
67
68 Program:
69           Methoddef ';' Program
70           @{
71             @i @Methoddef.s@ = @Program.0.f@;
72             @i @Program.1.f@ = @Program.0.f@;
73           @}
74
75         | Structdef ';' Program
76           @{
77             @i @Program.1.f@ = tab_merge(@Program.0.f@, @Structdef.f@, 1);
78           @}
79         |
80         ;
81
82 Methoddef:
83           METHOD IDENT '(' Parms ')' Statseq END
84           @{
85             @i @Parms.parms@ = 1;
86             @i @Statseq.s@ = tab_merge(@Methoddef.s@, @Parms.f@, 0);
87                 @i @Statseq.gparamges@ = @Parms.paramges@;
88                 @i @Statseq.lblcnt_in@ = 0;
89             @gen func_header(@IDENT.name@);
90           @}
91         ;
92
93 Structdef:
94           STRUCT FeldID END
95           @{
96             @i @Structdef.f@ = @FeldID.f@;
97                 @i @FeldID.offsetcount@ = 0;
98           @}
99         ;
100
101 Parms:
102           /* lokale Vars werden in Statement in die tabelle eingefuegt */
103           IDENT Parms
104           @{
105             @i @Parms.1.parms@ = @Parms.0.parms@ + 1;
106                 @i @Parms.0.paramges@ = @Parms.1.paramges@;
107             @i @Parms.0.f@ = tab_add_symbol(@Parms.1.f@, @IDENT.name@, S_PARM, 1, @Parms.parms@, -1);
108           @}
109
110         |
111           @{
112             @i @Parms.f@ = tab_new();
113                 @i @Parms.paramges@ = @Parms.parms@;
114           @}
115         ;
116
117 FeldID:
118           IDENT FeldID
119           @{
120             @i @FeldID.1.offsetcount@ = @FeldID.0.offsetcount@ + 1;
121             @i @FeldID.0.f@ = tab_add_symbol(@FeldID.1.f@, @IDENT.name@, S_FIELD, 1, -1, @FeldID.0.offsetcount@);
122           @}
123
124         |
125           @{
126             @i @FeldID.f@ = tab_new();
127           @}
128         ;
129
130 Statseq:
131           Statement ';' Statseq
132           @{
133                 @i @Statement.sin@ = @Statseq.0.s@;
134                 @i @Statement.lblcnt_in@ = @Statseq.0.lblcnt_in@;
135
136                 @i @Statseq.1.s@ = @Statement.sout@;
137                 @i @Statseq.1.lblcnt_in@ = @Statement.lblcnt_out@;
138                 @i @Statseq.1.gparamges@ = @Statseq.0.gparamges@ + @Statement.vars@;
139
140                 @i @Statseq.0.lblcnt_out@ = @Statseq.1.lblcnt_out@;
141           @}
142
143         |
144           @{
145                 @i @Statseq.0.lblcnt_out@ = @Statseq.0.lblcnt_in@;
146           @}
147         ;
148
149 Statement:
150           Lexpr ASSIGN Expr
151           @{
152                 statinout()
153                 lblcountinout()
154                 xxputsin(@Lexpr.s@,)
155                 xxputsin(@Expr.s@,)
156             @i @Statement.node@ = new_node(O_ASSIGN, @Expr.node@, @Lexpr.node@);
157                 @i @Statement.vars@ = 0;
158                 @reg @Statement.node@->reg = @Expr.node@->reg = next_reg((char *)NULL, @Expr.gparamges@);
159
160                 @gen write_tree(@Statement.node@, 0); burm_label(@Statement.node@); burm_reduce(@Statement.node@, 1);
161           @}
162
163         | VAR IDENT ASSIGN Expr
164           @{
165                 /* tab_clone ist hier noetig, vgl. folgendes statement
166                  * > var x := x - 1; */
167                 @i @Statement.sout@ = tab_add_symbol(tab_clone(@Statement.sin@), @IDENT.name@, S_VAR, 1, @Statement.gparamges@, -1);
168                 lblcountinout()
169                 xxputsin(@Expr.s@,)
170
171                 @i @Statement.node@ = new_node(O_ASSIGN, @Expr.node@, new_param(O_ID, @IDENT.name@, TREENULL, TREENULL, @Statement.gparamges@));
172                 @i @Statement.vars@ = 1;
173                 @reg @Statement.node@->reg = @Expr.node@->reg = next_reg((char *)NULL, @Expr.gparamges@);
174
175                 @gen write_tree(@Statement.node@, 0); burm_label(@Statement.node@); burm_reduce(@Statement.node@, 1);
176           @}
177
178         | Expr
179           @{
180                 statinout()
181                 lblcountinout()
182                 xxputsin(@Expr.s@,)
183             @i @Statement.node@ = TREENULL;
184                 @i @Statement.vars@ = 0;
185           @}
186
187         | IF Expr THEN Statseq END
188           @{
189                 statinout()
190                 @i @Statseq.lblcnt_in@ =  @Statement.lblcnt_in@ + 1;
191                 @i @Statement.lblcnt_out@ = @Statseq.lblcnt_out@;
192                 xxputsin(@Expr.s@,)
193                 xxputsin(@Statseq.s@,)
194
195                 @i @Statement.node@ = new_node(O_IF, @Expr.node@, TREENULL);
196                 @i @Statement.vars@ = 0;
197
198                 @reg @Statement.node@->reg = @Expr.node@->reg = next_reg((char *)NULL, @Expr.gparamges@);
199                 @gen {
200                         printf("%s_ifstart_%d:\n", get_func_name(), @Statement.lblcnt_in@);
201                         write_tree(@Statement.node@, 0); burm_label(@Statement.node@); burm_reduce(@Statement.node@, 1);
202                         /* TODO: kann ich mir das test wirklich wegan and davor sparen? */
203                         printf("\ttest %s1, %%rax\n\tjz %s_ifend_%d\n", "$", get_func_name(), @Statement.lblcnt_in@);
204                 }
205                 @gen @revorder(1) printf("%s_ifend_%d:\n", get_func_name(), @Statement.lblcnt_in@);
206           @}
207
208         | IF Expr THEN Statseq Elsestat END
209           @{
210                 statinout()
211                 @i @Statseq.0.lblcnt_in@ = @Statement.lblcnt_in@ + 1;
212                 @i @Elsestat.lblcnt_in@ = @Statseq.lblcnt_out@;
213                 @i @Statement.lblcnt_out@ = @Elsestat.lblcnt_out@;
214
215                 /* im Elsestat muss noch ein label numeriert werden */
216                 @i @Elsestat.reallblcnt@ = @Statement.lblcnt_in@;
217
218                 xxputsin(@Expr.s@,)
219                 xxputsin(@Statseq.0.s@,)
220                 xxputsin(@Elsestat.s@,)
221
222                 @i @Statement.node@ = new_node(O_IF, @Expr.node@, TREENULL);
223                 @i @Statement.vars@ = 0;
224
225                 @reg @Statement.node@->reg = @Expr.node@->reg = next_reg((char *)NULL, @Expr.gparamges@);
226                 @gen {
227                         printf("%s_ifstart_%d:\n", get_func_name(), @Statement.lblcnt_in@);
228                         write_tree(@Statement.node@, 0); burm_label(@Statement.node@); burm_reduce(@Statement.node@, 1);
229                         /* TODO: kann ich mir das test wirklich wegan and davor sparen? */
230                         printf("\ttest %s1, %%rax\n\tjz %s_ifelse_%d\n", "$", get_func_name(), @Statement.lblcnt_in@);
231                 }
232                 @gen @revorder(1) printf("%s_ifend_%d:\n", get_func_name(), @Statement.lblcnt_in@);
233           @}
234
235         | WHILE Expr DO Statseq END
236           @{
237                 statinout()
238                 @i @Statseq.lblcnt_in@ =  @Statement.lblcnt_in@ + 1;
239                 @i @Statement.lblcnt_out@ = @Statseq.lblcnt_out@;
240                 xxputsin(@Expr.s@,)
241                 xxputsin(@Statseq.s@,)
242
243                 @i @Statement.node@ = new_node(O_IF, @Expr.node@, TREENULL);
244                 @i @Statement.vars@ = 0;
245
246                 @reg @Statement.node@->reg = @Expr.node@->reg = next_reg((char *)NULL, @Expr.gparamges@);
247                 @gen {
248                         printf("%s_whilestart_%d:\n", get_func_name(), @Statement.lblcnt_in@);
249                         write_tree(@Statement.node@, 0); burm_label(@Statement.node@); burm_reduce(@Statement.node@, 1);
250                         /* TODO: kann ich mir das test wirklich wegan and davor sparen? */
251                         printf("\ttest %s1, %%rax\n\tjz %s_whileend_%d\n", "$", get_func_name(), @Statement.lblcnt_in@);
252                 }
253                 @gen @revorder(1) printf("\tjmp %s_whilestart_%d\n%s_whileend_%d:\n", get_func_name(), @Statement.lblcnt_in@, get_func_name(), @Statement.lblcnt_in@);
254           @}
255
256         | RETURN Expr
257           @{
258                 statinout()
259                 lblcountinout()
260                 xxputsin(@Expr.s@,)
261
262                 @i @Statement.vars@ = 0;
263                 @i @Statement.node@ = new_node(O_RET, @Expr.node@, TREENULL);
264                 @reg @Statement.node@->reg = @Expr.node@->reg = next_reg((char *)NULL, @Expr.gparamges@);
265
266                 @gen write_tree(@Statement.node@, 0); burm_label(@Statement.node@); burm_reduce(@Statement.node@, 1);
267           @}
268         ;
269
270 Elsestat:
271           ELSE Statseq
272           @{
273                 @i @Statseq.lblcnt_in@ =  @Elsestat.lblcnt_in@;
274                 @i @Elsestat.lblcnt_out@ =  @Statseq.lblcnt_out@;
275
276                 @gen printf("\tjmp %s_ifend_%d\n%s_ifelse_%d:\n", get_func_name(), @Elsestat.reallblcnt@, get_func_name(), @Elsestat.reallblcnt@);
277           @}
278
279 Lexpr:
280           IDENT
281           @{
282             @c check(@Lexpr.s@, @IDENT.name@, S_VAR|S_PARM);
283
284                 /* TODO: selbe Code wie bei Term/IDENT -- schoener machen! */
285             @i {
286                         @Lexpr.node@ = TREENULL;
287                         if(tab_lookup(@Lexpr.s@, @IDENT.name@, S_VAR|S_PARM) == SYMNULL) {
288                                 /* es handelt sich um ein feldzugriff auf this */
289                                 @Lexpr.node@ = new_field(@IDENT.name@, new_param(O_ID, strdup("this"), TREENULL, TREENULL, 0), TREENULL, tab_lookup(@Lexpr.s@, @IDENT.name@, S_FIELD) == SYMNULL ? -1 : tab_lookup(@Lexpr.s@, @IDENT.name@, S_FIELD)->soffset);
290                         } else { /* param oder var */
291                                 int tmp = tab_lookup(@Lexpr.s@, @IDENT.name@, S_VAR|S_PARM) == SYMNULL ? -1 : tab_lookup(@Lexpr.s@, @IDENT.name@, S_VAR|S_PARM)->param_index;
292                                 @Lexpr.node@ = new_param(O_ID, @IDENT.name@, TREENULL, TREENULL, tmp);
293                         }
294                 }
295
296                 @reg if(tab_lookup(@Lexpr.s@, @IDENT.name@, S_VAR|S_PARM) == SYMNULL) {
297                         /* TODO: kein schoener hack? */
298                         @Lexpr.node@->kids[0]->reg = @Lexpr.node@->reg;
299                 }
300           @}
301
302         | Feld
303         ;
304
305 Feld: Term '.' IDENT
306           @{
307             @c check(@Feld.s@, @IDENT.name@, S_FIELD);
308             @i @Feld.node@ = new_field(@IDENT.name@, @Term.node@, TREENULL, tab_lookup(@Feld.s@, @IDENT.name@, S_FIELD) == SYMNULL ? -1 : tab_lookup(@Feld.s@, @IDENT.name@, S_FIELD)->soffset);
309
310                 @reg @Term.node@->reg = @Feld.node@->reg;
311           @}
312         ;
313
314 Expr:
315           Term
316           @{
317             @reg @Term.node@->reg = @Expr.node@->reg;
318           @}
319
320         | NOT Term
321           @{
322                 @i @Expr.node@ = new_node(O_EQ, @Term.node@, new_node(O_NULL, TREENULL, TREENULL));
323
324                 @reg @Term.node@->reg = @Expr.node@->reg;
325           @}
326
327         | Term Minusterm
328           @{
329             @i @Expr.node@ = new_node(O_SUB, @Term.node@, @Minusterm.node@);
330                 @i @Expr.imm@ = @Term.imm@ && @Minusterm.imm@;
331
332                 @reg {
333                         if(!(@Expr.node@->kids[0] == TREENULL && @Expr.node@->kids[1] == TREENULL)) {
334                                 @Term.node@->reg = @Expr.node@->reg;
335                                 if(@Minusterm.imm@) {
336                                         @Minusterm.node@->reg = @Expr.node@->reg;
337                                 } else {
338                                         @Minusterm.node@->reg = next_reg(@Term.node@->reg, @Expr.gparamges@);
339                                 }
340                         }
341                 }
342           @}
343
344         | Term Multerm
345           @{
346             @i @Expr.node@ = new_node(O_MUL, @Term.node@, @Multerm.node@);
347                 @i @Expr.imm@ = @Term.imm@ && @Multerm.imm@;
348
349                 @reg {
350                         @Term.node@->reg = @Expr.node@->reg;
351                         if(@Term.imm@) {
352                                 @Multerm.node@->reg = @Expr.node@->reg;
353                         } else {
354                                 @Multerm.node@->reg = next_reg(@Term.node@->reg, @Expr.gparamges@);
355                         }
356                 }
357           @}
358
359         | Term Orterm
360           @{
361             @i @Expr.node@ = new_node(O_OR, @Term.node@, @Orterm.node@);
362                 @i @Expr.imm@ = @Term.imm@ && @Orterm.imm@;
363
364                 @reg {
365                         @Term.node@->reg = @Expr.node@->reg;
366                         @Orterm.node@->reg = next_reg(@Term.node@->reg, @Expr.gparamges@);
367                 }
368           @}
369
370         | Term '<' Term
371           @{
372             @i @Expr.node@ = new_node(O_LESS, @Term.0.node@, @Term.1.node@);
373                 @i @Expr.imm@ = @Term.0.imm@ && @Term.0.imm@;
374
375                 @reg {
376                         @Term.0.node@->reg = @Expr.node@->reg;
377                         @Term.1.node@->reg = next_reg(@Term.0.node@->reg, @Expr.gparamges@);
378                 }
379           @}
380
381         | Term '=' Term
382           @{
383             @i @Expr.node@ = new_node(O_EQ, @Term.0.node@, @Term.1.node@);
384                 @i @Expr.imm@ = @Term.0.imm@ && @Term.0.imm@;
385
386                 @reg {
387                         @Term.0.node@->reg = @Expr.node@->reg;
388                         @Term.1.node@->reg = next_reg(@Term.0.node@->reg, @Expr.gparamges@);
389                 }
390           @}
391         ;
392
393 Minusterm:
394           '-' Term Minusterm
395           @{
396             @i @Minusterm.node@ = new_node(O_ADD, @Minusterm.1.node@, @Term.node@);
397                 @i @Minusterm.0.imm@ = @Term.imm@ && @Minusterm.1.imm@;
398
399             @reg {
400                         @Minusterm.1.node@->reg = @Minusterm.node@->reg;
401                         if(@Minusterm.1.imm@) {
402                                 @Term.node@->reg = @Minusterm.node@->reg;
403                         } else {
404                                 @Term.node@->reg = next_reg(@Minusterm.1.node@->reg, @Minusterm.gparamges@);
405                         }
406                 }
407           @}
408
409         | '-' Term
410           @{
411             @reg @Term.node@->reg = @Minusterm.node@->reg;
412           @}
413         ;
414
415 Multerm:
416           '*' Term Multerm
417           @{
418             @i @Multerm.node@ = new_node(O_MUL, @Multerm.1.node@, @Term.node@);
419                 @i @Multerm.0.imm@ = @Term.imm@ && @Multerm.1.imm@;
420
421             @reg {
422                         @Multerm.1.node@->reg = @Multerm.node@->reg;
423                         if(@Multerm.1.imm@) {
424                                 @Term.node@->reg = @Multerm.node@->reg;
425                         } else {
426                                 @Term.node@->reg = next_reg(@Multerm.1.node@->reg, @Multerm.gparamges@);
427                         }
428                 }
429           @}
430
431         | '*' Term
432           @{
433             @reg @Term.node@->reg = @Multerm.node@->reg;
434           @}
435         ;
436
437 Orterm:
438           OR Term Orterm
439           @{
440             @i @Orterm.node@ = new_node(O_OR, @Orterm.1.node@, @Term.node@);
441                 @i @Orterm.0.imm@ = @Term.imm@ && @Orterm.1.imm@;
442
443             @reg {
444                         @Orterm.1.node@->reg = @Orterm.node@->reg;
445                         if(@Orterm.1.imm@) {
446                                 @Term.node@->reg = @Orterm.node@->reg;
447                         } else {
448                                 @Term.node@->reg = next_reg(@Orterm.1.node@->reg, @Orterm.gparamges@);
449                         }
450                 }
451           @}
452         | OR Term
453           @{
454             @reg @Term.node@->reg = @Orterm.node@->reg;
455           @}
456
457         ;
458
459 Term:
460           '(' Expr ')'
461           @{
462             @i @Term.node@ = @Expr.node@;
463           @}
464
465         | NUM
466           @{
467             @i @Term.node@ = new_number(@NUM.val@);
468                 @i @Term.imm@ = 1;
469           @}
470
471         | '-' NUM
472           @{
473             @i @Term.node@ = new_number(-1 * (@NUM.val@));
474                 @i @Term.imm@ = 1;
475           @}
476
477         | THIS
478           @{
479             @i @Term.node@ = new_param(O_ID, strdup("this"), TREENULL, TREENULL, 0);
480                 @i @Term.imm@ = 0;
481           @}
482
483         | IDENT
484           @{
485             @c check(@Term.s@, @IDENT.name@, S_VAR|S_PARM);
486
487                 @i @Term.imm@ = 0;
488             @i {
489                         @Term.node@ = TREENULL;
490                         if(tab_lookup(@Term.s@, @IDENT.name@, S_VAR|S_PARM) == SYMNULL) {
491                                 /* es handelt sich um ein feldzugriff auf this */
492                                 @Term.node@ = new_field(@IDENT.name@, new_param(O_ID, strdup("this"), TREENULL, TREENULL, 0), TREENULL, tab_lookup(@Term.s@, @IDENT.name@, S_FIELD) == SYMNULL ? -1 : tab_lookup(@Term.s@, @IDENT.name@, S_FIELD)->soffset);
493                         } else { /* param oder var */
494                                 int tmp = tab_lookup(@Term.s@, @IDENT.name@, S_VAR|S_PARM) == SYMNULL ? -1 : tab_lookup(@Term.s@, @IDENT.name@, S_VAR|S_PARM)->param_index;
495                                 @Term.node@ = new_param(O_ID, @IDENT.name@, TREENULL, TREENULL, tmp);
496                         }
497                 }
498
499                 @reg if(tab_lookup(@Term.s@, @IDENT.name@, S_VAR|S_PARM) == SYMNULL) {
500                         /* TODO: kein schoener hack? */
501                         @Term.node@->kids[0]->reg = @Term.node@->reg;
502                 }
503           @}
504
505         | Feld
506           @{
507             @i @Term.node@ = @Feld.node@;
508                 @i @Term.imm@ = 0;
509           @}
510
511         | IDENT '(' Exprs ')'
512           @{
513             @i @Term.node@ = TREENULL;
514                 @i @Term.imm@ = 0;
515           @}
516
517         | Term '.' IDENT '(' Exprs ')'
518           @{
519             @i @Term.node@ = TREENULL;
520                 @i @Term.imm@ = 0;
521           @}
522
523         ;
524
525 Exprs:
526           Expr ',' Exprs
527         | Expr
528         |
529         ;
530 %%
531
532 extern int yylex();
533 extern int yylineno;
534
535 int yyerror(char *error_text)
536 {
537         fprintf(stderr,"Zeile %i: %s\n", yylineno, error_text);
538         exit(2);
539 }
540
541 int main(int argc, char **argv)
542 {
543         #if 0
544         yydebug=1;
545         #endif
546         yyparse();
547         return 0;
548 }
549