codeb: labels werden nun auch fuer 'IF expr THEN statseq ELSE statseq END' richtig...
[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, @Lexpr.node@, @Expr.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, new_param(O_ID, @IDENT.name@, TREENULL, TREENULL, @Statement.gparamges@), @Expr.node@);
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                         write_tree(@Statement.node@, 0); burm_label(@Statement.node@); burm_reduce(@Statement.node@, 1);
201                         /* TODO: kann ich mir das test wirklich wegan and davor sparen? */
202                         printf("\ttest %s1, %%rax\n\tjz %s_ifend_%d\n", "$", get_func_name(), @Statement.lblcnt_in@);
203                 }
204                 @gen @revorder(1) printf("%s_ifend_%d:\n", get_func_name(), @Statement.lblcnt_in@);
205           @}
206
207         | IF Expr THEN Statseq Elsestat END
208           @{
209                 statinout()
210                 @i @Statseq.0.lblcnt_in@ = @Statement.lblcnt_in@ + 1;
211                 @i @Elsestat.lblcnt_in@ = @Statseq.lblcnt_out@;
212                 @i @Statement.lblcnt_out@ = @Elsestat.lblcnt_out@;
213
214                 /* im Elsestat muss noch ein label numeriert werden */
215                 @i @Elsestat.reallblcnt@ = @Statement.lblcnt_in@;
216
217                 xxputsin(@Expr.s@,)
218                 xxputsin(@Statseq.0.s@,)
219                 xxputsin(@Elsestat.s@,)
220
221                 @i @Statement.node@ = new_node(O_IF, @Expr.node@, TREENULL);
222                 @i @Statement.vars@ = 0;
223
224                 @reg @Statement.node@->reg = @Expr.node@->reg = next_reg((char *)NULL, @Expr.gparamges@);
225                 @gen {
226                         write_tree(@Statement.node@, 0); burm_label(@Statement.node@); burm_reduce(@Statement.node@, 1);
227                         /* TODO: kann ich mir das test wirklich wegan and davor sparen? */
228                         printf("\ttest %s1, %%rax\n\tjz %s_ifelse_%d\n", "$", get_func_name(), @Statement.lblcnt_in@);
229                 }
230                 @gen @revorder(1) printf("%s_ifend_%d:\n", get_func_name(), @Statement.lblcnt_in@);
231           @}
232
233         | WHILE Expr DO Statseq END
234           @{
235                 statinout()
236                 lblcountinout()
237                 /* TODO */
238                 @i @Statseq.0.lblcnt_in@ =  @Statement.lblcnt_in@ + 1;
239                 xxputsin(@Expr.s@,)
240                 xxputsin(@Statseq.s@,)
241             @i @Statement.node@ = TREENULL;
242                 @i @Statement.vars@ = 0;
243           @}
244
245         | RETURN Expr
246           @{
247                 statinout()
248                 lblcountinout()
249                 xxputsin(@Expr.s@,)
250
251                 @i @Statement.vars@ = 0;
252                 @i @Statement.node@ = new_node(O_RET, @Expr.node@, TREENULL);
253                 @reg @Statement.node@->reg = @Expr.node@->reg = next_reg((char *)NULL, @Expr.gparamges@);
254
255                 @gen write_tree(@Statement.node@, 0); burm_label(@Statement.node@); burm_reduce(@Statement.node@, 1);
256           @}
257         ;
258
259 Elsestat:
260           ELSE Statseq
261           @{
262                 @i @Statseq.lblcnt_in@ =  @Elsestat.lblcnt_in@;
263                 @i @Elsestat.lblcnt_out@ =  @Statseq.lblcnt_out@;
264
265                 @gen printf("\tjmp %s_ifend_%d\n%s_ifelse_%d:\n", get_func_name(), @Elsestat.reallblcnt@, get_func_name(), @Elsestat.reallblcnt@);
266           @}
267
268 Lexpr:
269           IDENT
270           @{
271             @c check(@Lexpr.s@, @IDENT.name@, S_VAR|S_PARM);
272
273                 /* TODO: selbe Code wie bei Term/IDENT -- schoener machen! */
274             @i {
275                         @Lexpr.node@ = TREENULL;
276                         if(tab_lookup(@Lexpr.s@, @IDENT.name@, S_VAR|S_PARM) == SYMNULL) {
277                                 /* es handelt sich um ein feldzugriff auf this */
278                                 @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);
279                         } else { /* param oder var */
280                                 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;
281                                 @Lexpr.node@ = new_param(O_ID, @IDENT.name@, TREENULL, TREENULL, tmp);
282                         }
283                 }
284
285                 @reg if(tab_lookup(@Lexpr.s@, @IDENT.name@, S_VAR|S_PARM) == SYMNULL) {
286                         /* TODO: kein schoener hack? */
287                         @Lexpr.node@->kids[0]->reg = @Lexpr.node@->reg;
288                 }
289           @}
290
291         | Feld
292         ;
293
294 Feld: Term '.' IDENT
295           @{
296             @c check(@Feld.s@, @IDENT.name@, S_FIELD);
297             @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);
298
299                 @reg @Term.node@->reg = @Feld.node@->reg;
300           @}
301         ;
302
303 Expr:
304           Term
305           @{
306             @reg @Term.node@->reg = @Expr.node@->reg;
307           @}
308
309         | NOT Term
310           @{
311                 @i @Expr.node@ = new_node(O_EQ, @Term.node@, new_node(O_NULL, TREENULL, TREENULL));
312
313                 @reg @Term.node@->reg = @Expr.node@->reg;
314           @}
315
316         | Term Minusterm
317           @{
318             @i @Expr.node@ = new_node(O_SUB, @Term.node@, @Minusterm.node@);
319                 @i @Expr.imm@ = @Term.imm@ && @Minusterm.imm@;
320
321                 @reg {
322                         if(!(@Expr.node@->kids[0] == TREENULL && @Expr.node@->kids[1] == TREENULL)) {
323                                 @Term.node@->reg = @Expr.node@->reg;
324                                 if(@Minusterm.imm@) {
325                                         @Minusterm.node@->reg = @Expr.node@->reg;
326                                 } else {
327                                         @Minusterm.node@->reg = next_reg(@Term.node@->reg, @Expr.gparamges@);
328                                 }
329                         }
330                 }
331           @}
332
333         | Term Multerm
334           @{
335             @i @Expr.node@ = new_node(O_MUL, @Term.node@, @Multerm.node@);
336                 @i @Expr.imm@ = @Term.imm@ && @Multerm.imm@;
337
338                 @reg {
339                         @Term.node@->reg = @Expr.node@->reg;
340                         if(@Term.imm@) {
341                                 @Multerm.node@->reg = @Expr.node@->reg;
342                         } else {
343                                 @Multerm.node@->reg = next_reg(@Term.node@->reg, @Expr.gparamges@);
344                         }
345                 }
346           @}
347
348         | Term Orterm
349           @{
350             @i @Expr.node@ = new_node(O_OR, @Term.node@, @Orterm.node@);
351                 @i @Expr.imm@ = @Term.imm@ && @Orterm.imm@;
352
353                 @reg {
354                         @Term.node@->reg = @Expr.node@->reg;
355                         @Orterm.node@->reg = next_reg(@Term.node@->reg, @Expr.gparamges@);
356                 }
357           @}
358
359         | Term '<' Term
360           @{
361             @i @Expr.node@ = new_node(O_LESS, @Term.0.node@, @Term.1.node@);
362                 @i @Expr.imm@ = @Term.0.imm@ && @Term.0.imm@;
363
364                 @reg {
365                         @Term.0.node@->reg = @Expr.node@->reg;
366                         @Term.1.node@->reg = next_reg(@Term.0.node@->reg, @Expr.gparamges@);
367                 }
368           @}
369
370         | Term '=' Term
371           @{
372             @i @Expr.node@ = new_node(O_EQ, @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
382 Minusterm:
383           '-' Term Minusterm
384           @{
385             @i @Minusterm.node@ = new_node(O_ADD, @Minusterm.1.node@, @Term.node@);
386                 @i @Minusterm.0.imm@ = @Term.imm@ && @Minusterm.1.imm@;
387
388             @reg {
389                         @Minusterm.1.node@->reg = @Minusterm.node@->reg;
390                         if(@Minusterm.1.imm@) {
391                                 @Term.node@->reg = @Minusterm.node@->reg;
392                         } else {
393                                 @Term.node@->reg = next_reg(@Minusterm.1.node@->reg, @Minusterm.gparamges@);
394                         }
395                 }
396           @}
397
398         | '-' Term
399           @{
400             @reg @Term.node@->reg = @Minusterm.node@->reg;
401           @}
402         ;
403
404 Multerm:
405           '*' Term Multerm
406           @{
407             @i @Multerm.node@ = new_node(O_MUL, @Multerm.1.node@, @Term.node@);
408                 @i @Multerm.0.imm@ = @Term.imm@ && @Multerm.1.imm@;
409
410             @reg {
411                         @Multerm.1.node@->reg = @Multerm.node@->reg;
412                         if(@Multerm.1.imm@) {
413                                 @Term.node@->reg = @Multerm.node@->reg;
414                         } else {
415                                 @Term.node@->reg = next_reg(@Multerm.1.node@->reg, @Multerm.gparamges@);
416                         }
417                 }
418           @}
419
420         | '*' Term
421           @{
422             @reg @Term.node@->reg = @Multerm.node@->reg;
423           @}
424         ;
425
426 Orterm:
427           OR Term Orterm
428           @{
429             @i @Orterm.node@ = new_node(O_OR, @Orterm.1.node@, @Term.node@);
430                 @i @Orterm.0.imm@ = @Term.imm@ && @Orterm.1.imm@;
431
432             @reg {
433                         @Orterm.1.node@->reg = @Orterm.node@->reg;
434                         if(@Orterm.1.imm@) {
435                                 @Term.node@->reg = @Orterm.node@->reg;
436                         } else {
437                                 @Term.node@->reg = next_reg(@Orterm.1.node@->reg, @Orterm.gparamges@);
438                         }
439                 }
440           @}
441         | OR Term
442           @{
443             @reg @Term.node@->reg = @Orterm.node@->reg;
444           @}
445
446         ;
447
448 Term:
449           '(' Expr ')'
450           @{
451             @i @Term.node@ = @Expr.node@;
452           @}
453
454         | NUM
455           @{
456             @i @Term.node@ = new_number(@NUM.val@);
457                 @i @Term.imm@ = 1;
458           @}
459
460         | '-' NUM
461           @{
462             @i @Term.node@ = new_number(-1 * (@NUM.val@));
463                 @i @Term.imm@ = 1;
464           @}
465
466         | THIS
467           @{
468             @i @Term.node@ = new_param(O_ID, strdup("this"), TREENULL, TREENULL, 0);
469                 @i @Term.imm@ = 0;
470           @}
471
472         | IDENT
473           @{
474             @c check(@Term.s@, @IDENT.name@, S_VAR|S_PARM);
475
476                 @i @Term.imm@ = 0;
477             @i {
478                         @Term.node@ = TREENULL;
479                         if(tab_lookup(@Term.s@, @IDENT.name@, S_VAR|S_PARM) == SYMNULL) {
480                                 /* es handelt sich um ein feldzugriff auf this */
481                                 @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);
482                         } else { /* param oder var */
483                                 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;
484                                 @Term.node@ = new_param(O_ID, @IDENT.name@, TREENULL, TREENULL, tmp);
485                         }
486                 }
487
488                 @reg if(tab_lookup(@Term.s@, @IDENT.name@, S_VAR|S_PARM) == SYMNULL) {
489                         /* TODO: kein schoener hack? */
490                         @Term.node@->kids[0]->reg = @Term.node@->reg;
491                 }
492           @}
493
494         | Feld
495           @{
496             @i @Term.node@ = @Feld.node@;
497                 @i @Term.imm@ = 0;
498           @}
499
500         | IDENT '(' Exprs ')'
501           @{
502             @i @Term.node@ = TREENULL;
503                 @i @Term.imm@ = 0;
504           @}
505
506         | Term '.' IDENT '(' Exprs ')'
507           @{
508             @i @Term.node@ = TREENULL;
509                 @i @Term.imm@ = 0;
510           @}
511
512         ;
513
514 Exprs:
515           Expr ',' Exprs
516         | Expr
517         |
518         ;
519 %%
520
521 extern int yylex();
522 extern int yylineno;
523
524 int yyerror(char *error_text)
525 {
526         fprintf(stderr,"Zeile %i: %s\n", yylineno, error_text);
527         exit(2);
528 }
529
530 int main(int argc, char **argv)
531 {
532         #if 0
533         yydebug=1;
534         #endif
535         yyparse();
536         return 0;
537 }
538