-
Notifications
You must be signed in to change notification settings - Fork 0
/
SELMA.tex
1239 lines (1075 loc) · 59 KB
/
SELMA.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
\documentclass[]{article}
\title{SELMA}
\author{
Vonk, J\\
(herhaler)\\
s0132778\\
Matenweg 75-201\\
\\
Florisson, M\\
(herhaler)\\
s0165972\\
Box Calslaan 60-30\\
\\
Studentassistent:\\
Edwin Smulders}
\usepackage{listings}
\usepackage{lscape}
\usepackage{color}
\usepackage[pdftex,bookmarks=true]{hyperref}
\usepackage{hyperref}
\usepackage{verbatim}
\usepackage{url}
% \usepackage[T1]{fontenc}
\hypersetup{
colorlinks,
citecolor=black,
filecolor=black,
linkcolor=black,
urlcolor=black
}
\begin{document}
\lstdefinestyle{ANTLR}
{frame=shadowbox, breaklines=true,basicstyle=\footnotesize}
\lstdefinestyle{SELMA}
{frame=shadowbox, breaklines=true,basicstyle=\small}
\lstdefinestyle{JAVA}
{frame=shadowbox, language=Java, breaklines=true,basicstyle=\footnotesize}
\lstdefinestyle{JVM}
{frame=shadowbox, breaklines=true,basicstyle=\small}
\lstdefinestyle{ANTLRfile}
{frame=LB, breaklines=true, basicstyle=\scriptsize, numbers=left, stepnumber=5, firstnumber=1, numberstyle=\tiny}
\lstdefinestyle{SELMAfile}
{frame=LB, breaklines=true, basicstyle=\scriptsize, numbers=left, stepnumber=5, firstnumber=1, numberstyle=\tiny}
\lstdefinestyle{JAVAfile}
{frame=LB, language=Java, breaklines=true, numbers=left, stepnumber=5, firstnumber=1, numberstyle=\tiny}
\lstdefinestyle{JVMfile}
{frame=LB, breaklines=true, numbers=left, stepnumber=5, firstnumber=1, numberstyle=\tiny}
\newcommand{\todo}[1]{\marginpar{\fcolorbox{red}{yellow}{\textbf{#1}}}}
\begin{titlepage}
\maketitle
\end{titlepage}
\setcounter{secnumdepth}{5}
\setcounter{tocdepth}{5}
\tableofcontents{}
\newpage
\section{Inleiding}
%Korte beschrijving van de practicumopdracht.
Voor vertalerbouw dient als eindopdracht een eigen taal geschreven te worden. Deze taal dient een expression-language te zijn, dit is een taal die geen statements, maar enkel expressies kent. Alles wat je dus aanroept zal een waarde teruggeven.\\
Voor deze zelfbedachte taal dient een parser en lexer geschreven te worden, een checker en een compiler. Hierbij dient een verslag met een uitgebreide beschrijving van de taal en een goede kijk op hoe alles onder de motorkap werkt. Ook moet er een bewijs worden geleverd dat de taal werkt, dit kan door een testprogramma te schrijven dat tamelijk uitgebreid is en te kijken of dit werkt naar behoren. (black-box testing) \\
Hoe uitgebreid de te definieren taal wordt is aan de studenten zelf - dit is echter terug te zien in het te behalen cijfer.\\
Voor onze taal, SELMA, hebben wij gekozen voor het volgende:
\begin{itemize}
\item Basic Expression Language
\item If- \& while-statements
\item Ondersteunen van functies
\item Compileren naar JVM-code in plaats van TAM-code
\end{itemize}
Onze taal heet SELMA. Een naam aan een taal geven is lastig, zo waren er een aantal andere opties zoals: SMEF of Taal voor Vertalerbouw (TV).
De SEL staat voor Simpel Expression Language. Nu moest de afkorting wat meer zeggen dus kozen we voor de meisjesnaam SELMA, alleen maar omdat een afkorting vinden voor SELDERIE wel heel veel werk is.\\
Gelukkig heet onze taal dus geen SELDERIE, maar SELMA:\\
Waarbij de MA voor Minor Adjustments stond, we hebben inmiddels zoveel werk eraan gehad dat "Minor" dat geen eer meer aan doet. \\
Dus met gepaste trots presenteren wij u SELMA:\\
Simple Expression Language Met Augurk\\
Vanaf nu enkel nog naar te verwijzen als SELMA.\\
\newpage
\section{Beknopte beschrijving}
%van de programmeertaal (maximaal een A4-tje).
Onze taal is gemaakt naar de gegeven instructies van de practicumhandleiding en alles is of een expressie of declaration in deze taal. Bij sommige expressies is het echter niet mogelijk een resultaat te geven, hier kunnen die expressies niet anders dan een void-resultaat retouneren, wat ze effectief een statement maakt. De structuur van de taal en de keywords lijken qua layout op een hybride tussen C en Pascal. \\
De volledige taal is LL(1) wij hebben hierdoor vooral tijdens het ontwerpen goed moeten nadenken hoe we de taal zo logisch mogelijk opbouwden zodat de parser er mee uit de voeten kon. Eventueel is er de mogelijkheid om lokaal 1 stap verder te kijken, wij hebben dit echter niet nodig gehad omdat wij voldoende keywords hebben gebruikt, zoals voor een functie een @ zetten - en we in de parser bewust rekening hebben gehouden met de LL(1) limitatie.\\
\\
SELMA compileerde in eerste instantie naar TAM, op de cd is een fragment van deze code te zien. We hebben echter besloten dat het mooier was om JVM te gebruiken, niet zo zeer uit praktisch oogpunt, maar meer omdat JVM-bytecode ook door "echte" talen wordt gebruikt en omdat het een pluspunt is in de eindbeoordeling.\\
Op het moment dat we besloten om te schakelen waren we blij dat we hadden gekozen voor het gebruik van stringTemplates bij de codegeneratie, dit heeft ons wat werk gescheeld. En technisch gezien zouden we zo een extra compiler naar TAM-code erbij kunnen doen, aangezien er geen andere reden is dan "omdat het kan" hebben we onszelf die moeite bespaard.\\
\\
Lees verder - of probeer eens een testprogramma te compileren in SELMA - om te leren hoe de vork nou precies in de steel zit met deze taal.\\
\\
\\
\textit{- Mark \& Jeroen}\\
\\
NB: Aangezien CD's lang niet zo hip zijn als wat het internet heeft te bieden is ons gehele werk \'{o}\'{o}k te vinden op github: \\
\\
\url{http://github.com/markflorisson88/selma/}
\newpage
\section{Problemen en oplossingen}
%uitleg over de wijze waarop je de problemen die je bent tegenge-
%komen bij het maken van de opdracht hebt opgelost (maximaal twee A4-tjes).
Tijdens het maken van de taal zijn we uiteraard af en toe tegen problemen aangelopen. Nu hebben wij tijdens het practicum de calc-taal al ontwikkeld dus we hadden al wat handigheid met ANTLR - en ANTLR's soms wat aparte foutmeldingen.\\
\subsection{Taalconstructie}
Wat ons is opgevallen is dat je van te voren goed moet specificeren hoe je taal er uit moet zien. Door bijvoorbeeld onze keuze om overal SEMICOLON's achter te zetten - wat op zich logisch is - kregen we soms wat onwennige taalconstructies. Zo dien je ook een semicolon na een functiedeclaratie te zetten, want het is een declaratie - en ook een semicolon na een if-expressie voelt wat ongebruikelijk. Omdat echter alles een expressie is in deze taal vonden we het passend hier geen uitzonderingen op te gaan maken door sommige expressies niet met een semicolon af te sluiten. \\
De eis om een taal LL(1) te maken heeft echter niet echt problemen opgeleverd, behalve dat we de declaratie voor een assignment op een andere plek wouden doen in eerste instantie (onder expressies-toplevel), hierbij was echter met LL(1) geen onderscheid te maken tussen een identifier en een assignment.\\
Een ander punt waar het onderscheid moeilijk was, waren functies. Deze zijn namelijk niet te onderscheiden van identifiers, tot je een haakje-openen na een identifier ziet. We hebben overwogen om een lokale forward-lookup te gebruiken, dit hebben we echter snel bestempeld als "slim valsspelen" en we hebben een '@' voor alle functie-aanroepen gezet. Klinkt ook mooi, aangezien je ook daadwerkelijk verwijst naar een stuk eerder gedefineerde code.\\
Soms was het noodzakelijk om een stevige herschrijfregel te gebruiken, om in de checker en compiler wat meer gemak te hebben. Zo hebben we UMIN en EXPRESSION\_STATEMENT toegevoegd. En hebben we vormen zoals (ID (COMMA ID)* COLON type) naar \^(ID TYPE)+ omgeschreven.
\subsection{Checker}
De checker heeft vrijwel geen problemen opgeleverd, aangezien onze randcode - Java-helperclasses etc. - gewoon netjes aansloot en een hoop werk uit handen nam.\\
Waar we wel consequent tegenaan liepen waren de wat vage manieren waarop er data uit de boom te halen is. Dollartekens voor Tokens, of juist niet, het was soms wat onduidelijk.
\subsection{Compiler}
In eerste instantie is de compiler in TAM geschreven, toen het echter een project van 2 werdt in plaats van 1, is er besloten om een tandje bij te zetten en SELMA in een wat algemener geaccepteerde code-vorm te compilen: JVM.\\
\subsubsection{Jasmin \& JVM}
Er waren niet echt problemen met Jasmin of met de JVM. Een hindernis was het gebrek aan closures en global scope, dus om globale variabelen beschikbaar te maken tot functies moeten deze (statische) velden gemaakt worden en speciaal behandeld worden bij het laden van identifiers of assignment daaraan. Dit was vooral vervelend door het grote ongemak van string templates.\\
\subsubsection{String Templates}
String Templates is niet de meest flexibele template library. De syntax is raar en de restricties zijn enorm. Zo is het niet mogelijk een simpele comparison te doen in een 'if', en moet je dus een hoop booleans als argumenten meegeven (of wellicht een object de template in sturen met de juiste getters). Er is ook geen enkele mogelijkheid voor insertion points (e.g. code op bepaalde plekken te genereren, in plaats van "op de huidige positie"). Dit was vooral een probleem met functies, waarvoor we nieuwe methoden genereren die buiten de \texttt{main} methode moeten komen te staan. Hiervoor hebben we in \texttt{SELMA.java} een simpele vorm van post-processing gedaan waarbij we methoden in methoden buiten methoden zetten, zodat we een platte hierarchy krijgen.
\subsection{Randcode}
De randcode is deels gebaseerd op de symboltables gebruikt tijdens het practicum en neemt een hoop werk uit handen. De symboltable-entries zijn per onderdeel (checker,compiler) anders. Dit omdat we merkten dat er soms te weinig gegevens waren over declaraties. \\
In de boom zelf konden we ook niet genoeg info kwijt, vandaar dat we een extension op de normale Tree hebben gemaakt, SELMATree, waarin is op te slaan wat het type is van elke expressie en of er variabele onderdelen in een expressie zitten.
\newpage
\section{Syntax, context-beperkingen en semantiek}
%van de taal met waar nodig nadere uitleg over de
%betekenis. Geef de beschrijving bij voorkeur in dezelfde terminologie als die gebruikt is bij
%de beschrijving van Triangle in Watt \& Brown (hoofdstuk 1 en appendix B).
\subsection{Lexer - terminals}
Om de code te kunnen parsen zal deze eerst door de lexer moeten gaan. Hier definieren wij een aantal terminal symbolen. Dit is een eindige set van een aantal symbolen of woorden, de lexer zal deze herkennen. Mits ze in de juiste volgorde worden gebruikt krijg je taalconstructies die de parser vervolgens weer begrijpt. We hebben een aantal speciale terminals die zijn opgebouwd uit meerdere karakters bijvoorbeeld. Deze vormen de lexicon. En een zestal terminals zonder textuele vorm. Deze zijn enkel voor de interne boekhouding van de parser.
\\
\begin{lstlisting}[style=ANTLR]
CHARV APOSTROPHE LETTER APOSTROPHE;
BOOLEAN (TRUE | FALSE);
ID LETTER (LETTER | DIGIT)*;
NUMBER DIGIT+;
DIGIT ('0'..'9');
LOWER ('a'..'z');
UPPER ('A'..'Z');
LETTER (LOWER | UPPER);
TRUE 'true';
FALSE 'false';
UMIN;
UPLUS;
BEGIN;
END;
COMPOUND;
EXPRESSION_STATEMENT;
\end{lstlisting}
\newpage
Verder zijn er nog de 'gewone' terminals. Te verdelen in keywords, tokens en operators. Keywords geven aan dat er een bepaalde actie gedaan wordt, zoals een variabele declareren of een if statement. Tokens zijn er om de taal iets meer structuur te geven, denk aan comma's tussen de variabelen. En operators zijn bewerkingen die je kunt uitvoeren op 1 of meer expressies.
\\
\begin{lstlisting}[style=ANTLR]
Tokens Keywords
COLON ':'; PRINT 'print';
SEMICOLON ';'; READ 'read';
LPAREN '('; VAR 'var';
RPAREN ')'; CONST 'const';
LCURLY '{'; INT 'integer';
RCURLY '}'; BOOL 'boolean';
COMMA ','; CHAR 'character';
EQ '='; BEGIN 'begin';
APOSTROPHE '''; END 'end.';
UNDERSCORE '_'; IF 'if';
THEN 'then';
ELSE 'else';
FI 'fi';
WHILE 'while';
Operators DO 'do';
OD 'od';
NOT '!'; FUNCDEF 'function';
MULT '*'; FUNCRETURN 'return';
DIV '/'; FUNCTION '@';
MOD '%';
PLUS '+';
MINUS '-';
RELS '<';
RELSE '<=';
RELGE '>=';
RELG '>';
RELE '==';
RELNE '<>';
AND '&&';
OR '||';
BECOMES ':=';
\end{lstlisting}
\newpage
\subsection{De basis - Programma}
De basis van het programma geeft een aantal restricties op aan de taal.
Allereerst is er het programma, dit bestaat uit een (zeer grote) compoundexpression waarna het programma stopt (End Of File). Deze wordt hier herschreven. Een compoundexpression is uiteindelijk opgebouwd uit een serie declaraties en statements, gescheiden door een semicolon. Hier is te zien dat het programma uit minimaal 1 expressie bestaat, dat declaraties en expressies door elkaar gebruikt mogen worden en dat het laatste statement in een programma altijd een expressie is.
\lstinputlisting[style=ANTLR,linerange={100-111}]{../g-files/SELMA.g}
\subsection{Expression\_statement}
Dit is een speciale tussenstap voor de interne boekhouding. Na elke semicolumn zal de mogelijk resterende waarde van de stack worden gepopped. Dit maakt dat er niet aan het eind van ons programma een hoop troep op de stack staat. Voorwaarde is wel dat er wordt bijgehouden wanneer een expression van het type void is, dan hoeft er namelijk niet gepopped te worden.
\lstinputlisting[style=ANTLR,linerange={146-148}]{../g-files/SELMA.g}
\subsection{Declaraties en types}
SELMA kent twee soorten waarden-declaraties, variabelen en constanten. SELMA staat toe om per declaratie meerdere identifiers te definieren. Bij de declaratie dien je het type van de te declareren waarde mee te geven. En bij een constante dien je uiteraard een waarde mee te geven.
De functie declaratie die je ziet staan wordt apart besproken.
\subsubsection{Syntax}
\lstinputlisting[style=ANTLR,linerange={115-129}]{../g-files/SELMA.g}
\subsubsection{Context}
\begin{itemize}
\item Het gegeven type dient bij de constante overeen te komen met het type van de gegeven waarde.
\item Identifiers mogen niet eerder gedeclareerd zijn, in de huidige of bovenliggende scope.
\end{itemize}
\subsubsection{Semantiek}
Er zal ruimte gereserveerd worden voor de variabele en het adres wordt onthouden. Voor een constante geldt hetzelfde behalve dat dan ook direct de desbetreffende waarde op dat adres wordt gezet. Op het moment dat elders in het programma een verwijzing is naar deze gedeclareerde dan zal deze variabele of constante geladen worden.
\subsubsection{Voorbeeld}
\begin{lstlisting}[style=SELMA]
var i, x: integer;
const c: char = 'g';
const b,t: boolean = true;
\end{lstlisting}
\subsection{Functiedeclaratie}
SELMA kent ook nog een functie declaratie. Deze valt logischerwijs ook onder de declaraties. De declaratie van een functie dient altijd voor het gebruik te komen. Een functie kan als een soort procedure worden gebruikt door geen return-type op te geven. Het return-type wordt dan automatisch void. Dit hebben we express gedaan, we willen het namelijk altijd een functie noemen, aangezien procedures niet echt een plek hebben binnen een expressietaal.
\subsubsection{Syntax}
\lstinputlisting[style=ANTLR,linerange={122-122,131-134}]{../g-files/SELMA.g}
\subsubsection{Context}
\begin{itemize}
\item De naam van de functie moet uniek zijn.
\item De opgegeven identifiers moeten allemaal een andere naam hebben, ze hoeven echter niet uniek te zijn binnen het programma aangezien ze in een aparte scope staan.
\item Het type van de expressie na het returntype dient hetzelfde te zijn als type.
\end{itemize}
\subsubsection{Semantiek}
Het adres waar deze functie staat wordt opgeslagen. Daarna komt de code van de functie. Aan het einde van de functie zal eventueel een result op de stack worden gezet en wordt het adres dat aan het begin is gegeven aangeroepen om weer terug te komen op de plek waar de functie werdt aangeroepen.
\subsubsection{Voorbeeld}
\begin{lstlisting}[style=SELMA]
function foo() {
6*7;
}
function foo(awesome,less:boolean;bar:integer;): integer {
var i: integer;
if (awesome;) then
i := 42;
else
i := 2;
fi;
return i;
}
\end{lstlisting}
\subsection{Expressies - assignment}
De expressies zijn ingedeeld in verschillende niveaus, dit om te zorgen dat ze in de juiste volgorde worden uitgevoerd. Zo willen we dat 6+3*12 niet 108 is maar 42, niet alleen om dat 42 een mooier getal is, maar voornamelijk omdat het fijn is als de taal voldoet aan de conventionele rekenregels. \\
Het hoogste niveau is de assignment.
\subsubsection{Syntax}
\lstinputlisting[style=ANTLR,linerange={151-157}]{../g-files/SELMA.g}
\subsubsection{Context}
\begin{itemize}
\item expr\_arithmetic moet een identifier worden, in het eind, aangezien dat het enige is waaraan je een waarde kunt toekennen
\item deze identiefier moet dan verwijzen naar een geldige variabele
\item het type van expression en expression\_arithmetic moet hetzelfde zijn
\item expression is van het type van expr\_assignment
\item expr\_assignment is van het type van expr\_arithmetic
\end{itemize}
\subsubsection{Semantiek}
De waarde van expression zal worden toegekend aan het linker deel van de assignment.
Tevens gaat de waarde van de hele expressie op de stack, zo is er een asignement met meerdere identifiers mogelijk.
\subsubsection{Voorbeeld}
\begin{lstlisting}[style=SELMA]
7*6;
foo := 7*6;
foo := bar := 7*6;
\end{lstlisting}
\subsection{Expressies - OR}
De Of-operator is de laagste operator in het rijtje, vandaar dat deze bovenin de structuur zit.
\\
NB: expr\_al1 staat voor "expression arithmetic level 1"
\subsubsection{Syntax}
\lstinputlisting[style=ANTLR,linerange={159-165}]{../g-files/SELMA.g}
\subsubsection{Context}
\begin{itemize}
\item Als expr\_al1 enkel uit 1 expr\_al2 bestaat dan zijn er geen restricties
\item In de andere gevallen dienen alle expr\_al2 van het type boolean te zijn.
\item het type van expr\_arithmetic is het type van expr\_al1
\item als exp\_1 == expr\_al2 dan is het type van expr\_al1 het type van expr\_al2
\item als exp\_1 != expr\_al2 dan is het type van expr\_al1 een boolean
\end{itemize}
\subsubsection{Semantiek}
De eerste expr\_al2 zal op de stack worden gezet. Hierna wordt er telkens een expr\_al2 erbij gezet. De OR-operatie zal worden aangeroepen en het resultaat blijft op de stack zijn. Als er nog een expr\_al2 is dan zal deze ook op de stack worden gezet en wordt de OR-operatie opnieuw aangeroepen. Aldoende blijft er uiteindelijk 1 waarde op de stack staan.
\subsubsection{Voorbeeld}
\begin{lstlisting}[style=SELMA]
7*6;
true || false;
true || false || foo;
\end{lstlisting}
\subsection{Expressies - AND}
Hier wordt de AND-expressie beschreven. Net zoals bij de OR-expressie is het mogelijk nul tot veel AND-operatoren achter elkaar te plakken. De AND-expressie is een niveau hoger dan de OR-expressie en zal dus eerder worden uitgevoerd. \\
Het is eventueel mogelijk later in de compiler om een AND eerder af te breken aangezien als er een false in het rijtje zit het resultaat altijd false is. Wij hebben deze optimalisatie er nog niet inzitten, dit omdat sommige expressies ongeacht de eerdere expressies uitgevoerd dienen te worden, denk bijvoorbeeld aan een READ()-statement dat anders niet uitgevoerd zou worden.
\subsubsection{Syntax}
\lstinputlisting[style=ANTLR,linerange={167-169}]{../g-files/SELMA.g}
\subsubsection{Context}
\begin{itemize}
\item Als expr\_al2 enkel uit 1 expr\_al3 bestaat dan zijn er geen restricties
\item In de andere gevallen dienen alle expr\_al3 van het type boolean te zijn.
\item als exp\_2 == expr\_al3 dan is het type van expr\_al2 het type van expr\_al3
\item als exp\_2 != expr\_al3 dan is het type van expr\_al2 een boolean
\end{itemize}
\subsubsection{Semantiek}
Hetzelfde als bij het OR-statement. De waardes zullen op de stack geladen worden en er zal telkens een AND-operatie op 2 waardes worden uitgevoerd. De resulterende waarde is weer geschikt voor bijvoorbeeld nog een AND-operatie.
\subsubsection{Voorbeeld}
\begin{lstlisting}[style=SELMA]
7*6;
foo && bar;
foo && false && bar;
\end{lstlisting}
\subsection{Expressies - Relaties}
Hier worden bijna alle comperatoren afgehandeld. Het is belangrijk dat er in de checker goed wordt gekeken of de types van de linker en rechterzijde compatible zijn.
\subsubsection{Syntax}
% : expr_al4 ((RELS|RELSE|RELG|RELGE|RELE|RELNE)^ expr_al4)*
\lstinputlisting[style=ANTLR,linerange={171-173}]{../g-files/SELMA.g}
\subsubsection{Context}
\begin{itemize}
\item alle expr\_al4 dienen van hetzelfde type te zijn
\item bij een operatie tussen twee expr\_al4 anders dan RELE \& RELNE dient expr\_al4 een integer te zijn.
\item als exp\_3 == expr\_al4 dan is het type van expr\_al3 het type van expr\_al4
\item als exp\_3 != expr\_al4 dan is het type van expr\_al3 een boolean
\end{itemize}
\subsubsection{Semantiek}
Vergelijkbaar met andere binaire operatoren zoals AND en OR, er zullen waardes op de stack worden gezet en de operatie zal 1 waarde achterlaten op de stack.
\subsubsection{Voorbeeld}
\begin{lstlisting}[style=SELMA]
5 > 6;
true == false;
5 == 42;
\end{lstlisting}
\subsection{Expressies - plus en minus}
Hier zijn we aangeland bij de eerder genoemde 6+3*12, plus en minus zit 1 niveau lager dan de vermenigvuldigingen.
\subsubsection{Syntax}
\lstinputlisting[style=ANTLR,linerange={175-177}]{../g-files/SELMA.g}
\subsubsection{Context}
\begin{itemize}
\item als er minimaal 1 operatie wordt uitgevoerd dan dient expr\_al5 een integer te zijn
\item als exp\_4 == expr\_al5 dan is het type van expr\_al4 het type van expr\_al5
\item als exp\_4 != expr\_al5 dan is het type van expr\_al4 een integer
\end{itemize}
\subsubsection{Semantiek}
Wederom een binaire operatie. Let op, de unaire plus en minus komen nog. Dus 5 - - 6 zal de tweede minus niet hier worde opgevangen.
\subsubsection{Voorbeeld}
\begin{lstlisting}[style=SELMA]
foo := 5;
foo := 5 + 37;
10 + 50 - 18;
\end{lstlisting}
\subsection{Expressies - delen en vermenigvuldigen}
Naast delen en vermenigvuldigen is het ook mogelijk een modulus te nemen.
Wat wellicht is opgevallen bij het bovenstaande, is dat het mogelijk is om enkel een som in de code te zetten. Dit vinden wij prima, echter moet daarbij wel de resulterende waarde gepopped worden als die niet meer gebruikt wordt.
\subsubsection{Syntax}
\lstinputlisting[style=ANTLR,linerange={179-181}]{../g-files/SELMA.g}
\subsubsection{Context}
\begin{itemize}
\item als er minimaal 1 operatie wordt uitgevoerd dan dient expr\_al6 een integer te zijn
\item als exp\_5 == expr\_al6 dan is het type van expr\_al5 het type van expr\_al6
\item als exp\_5 != expr\_al6 dan is het type van expr\_al5 een integer
\end{itemize}
\subsubsection{Semantiek}
Hetzelfde als bij optellen. Goed om te weten is dat de geretouneerde waarde een integer is, dus er zal worden afgerond.
\subsubsection{Voorbeeld}
\begin{lstlisting}[style=SELMA]
foo := 6;
foo := 6*7;
foo := 21*6%84;
\end{lstlisting}
\subsection{Expressies - unaries}
Hier wordt gekeken of de expressie eventueel een NOT-, PLUS- of MIN-operator voor zich heeft staan.
Om later verwarring te voorkomen zullen PLUS en MIN vervangen worden door speciale terminals, zijnde UMIN en UPLUS. UPLUS zou eventueel weg kunnen worden gelaten aangezien +x==x.
Als er geen operator voor de expressie staat dan is expr\_al6 gewoon een expr\_al7
\subsubsection{Syntax}
\lstinputlisting[style=ANTLR,linerange={183-191}]{../g-files/SELMA.g}
\subsubsection{Context}
\begin{itemize}
\item expr\_al7 dient bij PLUS expr\_al7 een integer te zijn
\item expr\_al7 dient bij MIN expr\_al7 een integer te zijn
\item expr\_al7 dient bij NOT expr\_al7 een boolean te zijn
\item het type van expr\_al6 het type van expr\_al7
\end{itemize}
\subsubsection{Semantiek}
Bij UMIN zal expr\_al6 == - expr\_al7 \\
Bij UPLUS zal expr\_al6 == expr\_al7 \\
Bij NOT zal expr\_al6 == ! expr\_al7
\subsubsection{Voorbeeld}
\begin{lstlisting}[style=SELMA]
one := +1;
evil := -42;
foo := ! foobar;
\end{lstlisting}
\subsection{Expressies - toplevel}
Op het hoogste nivau kan een expressie bestaan uit een semi-statement zoals een if-expressie of een print-expressie, of het kan een identifier of waarde zijn, of het kan een aparte (compound)expressie binnen haken zijn.
Zoals je ziet stond in eerste de assignment hier. Maar aangezien het meest linkerdeel van een assignment een identiefier is kan op lL(1) geen onderscheid worden gemaakt tussen identifier of een assignment. Vandaar dat een assignment bij expr\_al1 is gedefineerd.
\subsubsection{Syntax}
\lstinputlisting[style=ANTLR,linerange={193-204}]{../g-files/SELMA.g}
\subsubsection{Context}
\begin{itemize}
\item expr\_al7 is van hetzelfde type als de gegeven expressie of waarde.
\end{itemize}
\subsubsection{Semantiek}
Dit is enkel een lijst van mogelijke expressies en waardes en dus zal er in de compiler enkel deze expressie of waarde op stack hebben staan, maar wordt er geen operatie op uitgevoerd.
\subsubsection{Voorbeeld}
\begin{lstlisting}[style=SELMA]
foo;
42;
(foobar);
\end{lstlisting}
\subsection{Unsigned constants}
Uiteraard bied onze taal ook de mogelijkheid aan om constanten te gebruiken zonder deze eerst te moeten declareren. Oftewel, je kunt gewoon nummers gebruiken bijvoorbeeld.
\subsubsection{Syntax}
\lstinputlisting[style=ANTLR,linerange={244-260,266-268}]{../g-files/SELMA.g}
\subsubsection{Context}
\begin{itemize}
\item unsignedconstant is van het type van de gegeven waarde
\item boolval is een boolean type
\item charval is een char
\item intval is een integer
\end{itemize}
\subsubsection{Semantiek}
De desbetreffende waarde wordt op de stack gezet.
\subsubsection{Voorbeeld}
\begin{lstlisting}[style=SELMA]
'Y';
42;
true;
\end{lstlisting}
\subsection{Identifier}
Een identifier van een bestaande variabele of constante in de huidige of een hogere scope.
\subsubsection{Syntax}
\lstinputlisting[style=ANTLR,linerange={261-264,275-277}]{../g-files/SELMA.g}
\subsubsection{Context}
\begin{itemize}
\item De identifier dient te verwijzen naar een geldige variabele of constante
\item Het type is het type van de variabele of declaratie waar de identifier naar verwijst.
\end{itemize}
\subsubsection{Semantiek}
Er zal een commando aangeroepen worden om de waarde uit het geheugen te laden. Deze waarde wordt dan op de stack gezet. Bij constanten gebeurd dit ook. Eventueel zou je ook de constante zelf al kunnen neerzetten op de stack, dit scheelt weer wat werk voor de processor. Dit doen wij echter niet momenteel. - Last minute update - Nu doen wij dat wel, constanten zullen direct uit de symboltable getrokken worden.
/todo{Mark}
\subsubsection{Voorbeeld}
\begin{lstlisting}[style=SELMA]
Answer42;
\end{lstlisting}
\subsection{Read}
Om contact te hebben met de buitenwereld kan onze taal lezen en schrijven naar de standard-out.
\subsubsection{Syntax}
\lstinputlisting[style=ANTLR,linerange={205-207}]{../g-files/SELMA.g}
\subsubsection{Context}
\begin{itemize}
\item Identifier dient te verwijzen naar een geldige identifier
\item De ingelezen waarde dient van het zelfde type als identifier te zijn
\item Als er 1 identifier is opgegeven dan geeft read de gelezen waarde/type terug
\item Als er meer dan 1 identifier wordt ingelezen dan is het returntype void
\end{itemize}
\subsubsection{Semantiek}
Het read-commando wordt aangeroepen en de waarde wordt van de standard-out gelezen en op de stack gezet. Vervolgens wordt die waarde opgeslagen in de variabele.
\subsubsection{Voorbeeld}
\begin{lstlisting}[style=SELMA]
read(foo);
read(foo,bar);
\end{lstlisting}
\subsection{Print}
De taal heeft ook de mogelijkheid om dat wat er bijvoorbeeld berekend is naar buiten te communiceren.
\subsubsection{Syntax}
\lstinputlisting[style=ANTLR,linerange={209-212}]{../g-files/SELMA.g}
\subsubsection{Context}
\begin{itemize}
\item -
\end{itemize}
\subsubsection{Semantiek}
De waarde van de expressie staat op de stack. Vervolgens wordt deze netjes naar het scherm uitgevoerd. Afhankelijk van het type zal dat anders gebeuren.
\subsubsection{Voorbeeld}
\begin{lstlisting}[style=SELMA]
print(42);
print('4','2');
\end{lstlisting}
\subsection{If}
Om keuzes in het programma mogelijk te maken zal er een conditioneel statement nodig zijn, het IF-statement is een dergelijk statement. Een ELSE-deel is optioneel.
\subsubsection{Syntax}
\lstinputlisting[style=ANTLR,linerange={213-215}]{../g-files/SELMA.g}
\subsubsection{Context}
\begin{itemize}
\item De eerste compoundexpression moet een boolean-type retouneren
\item De if retouneerd de waarde en type van de expressie die wordt uitgevoerd. (na de then of else)
\item De if retouneerd void als er geen expressie wordt uitgevoerd.
\end{itemize}
\subsubsection{Semantiek}
Als de waarde binnen het ifstatement waar is dan zal de eerste compoundexpressie worden uitgevoerd (na de then). Anders zal de andere compoundexpressie worden uitgevoerd, mits deze is gedeclareerd.
\subsubsection{Voorbeeld}
\begin{lstlisting}[style=SELMA]
if true; then i := 42; fi;
if false; then i := 0; else i:=42; fi;
\end{lstlisting}
\subsection{While}
De while zal net zolang een blok code uitvoeren tot een gegeven expressie waar is.
\subsubsection{Syntax}
\lstinputlisting[style=ANTLR,linerange={217-219}]{../g-files/SELMA.g}
\subsubsection{Context}
\begin{itemize}
\item De eerste compoundexpression moet een boolean-type retouneren
\item De while retouneerd een type void
\end{itemize}
\subsubsection{Semantiek}
De tweede compoundexpression zal worden uitgevoerd tot de eerste compoundexpression waar is. Het kan zijn dat de tweede compoundexpression nooit wordt uitgevoerd dus.
\subsubsection{Voorbeeld}
\begin{lstlisting}[style=SELMA]
while false; do
\\ this is not gonna be executed
tru := false;
od;
while foo<5; do
foo := foo + 1;
od;
\end{lstlisting}
\subsection{Functieaanroep}
Een functieaanroep naar een eerder gedefineerde functie
\subsubsection{Syntax}
\lstinputlisting[style=ANTLR,linerange={221-223}]{../g-files/SELMA.g}
\subsubsection{Context}
\begin{itemize}
\item Het aantal expressies en hun type dient overeen te komen met de declaratie van de functie
\item De functie retouneert het eerder gespecificeerde type. Als er geen type was gedeclareerd dan is dat dus void.
\end{itemize}
\subsubsection{Semantiek}
Het returnadres wordt op de stack gezet, zodat de functie weer hiernaartoe kan terugkeren.
De expressies worden op de stack gezet in de gespecificeerde volgorde.
De functie wordt aangeroepen.
De functie returned en het result staat op de stack.
\subsubsection{Voorbeeld}
\begin{lstlisting}[style=SELMA]
@foo();
i := @foo('b','a','r',);
\end{lstlisting}
\subsection{Closed expression}
Een expressie tussen haakjes is soms handig, bijvoorbeeld bij sommetjes: (5+2)*6;
\subsubsection{Syntax}
\lstinputlisting[style=ANTLR,linerange={229-231}]{../g-files/SELMA.g}
\subsubsection{Context}
\begin{itemize}
\item De geretouneerde waarde zal de waarde van de expressie zijn binnen de haakjes.
\item Het retourneerde type is ook hetzelfde als die van de expressie.
\end{itemize}
\subsubsection{Semantiek}
De expressie binnen de haakjes zal worden uitgevoerd binnen de haakjes.
\subsubsection{Voorbeeld}
\begin{lstlisting}[style=SELMA]
(3*(6+8))%102;
\end{lstlisting}
\subsection{Closed compoundexpression}
Is een compoundexpressie binnen haakjes. Verschil met de expressie tussen haakjes is dat deze ook toestaat om declaraties te gebruiken. Een compound tussen haakjes zal een eigen scope hebben.
\subsubsection{Syntax}
\lstinputlisting[style=ANTLR,linerange={225-227}]{../g-files/SELMA.g}
\subsubsection{Context}
\begin{itemize}
\item retouneerd het waarde en de type van de laatste expressie in de compound, dit kan van het type void zijn.
\end{itemize}
\subsubsection{Semantiek}
De compoundexpressie zal in een eigen scope worden uitgevoerd.
\subsubsection{Voorbeeld}
\begin{lstlisting}[style=SELMA]
{
var foo: integer;
foo := 40;
foo+2;
};
\end{lstlisting}
%
%expression_statement
% : expression SEMICOLON
% -> ^(EXPRESSION_STATEMENT expression)
% ;
%
%==================================OPMAAK======================================
%\subsection{Expressies - }
%
%\subsubsection{Syntax}
%\lstinputlisting[style=ANTLR,linerange={131-137}]{../g-files/SELMA.g}
%\subsubsection{Context}
%\begin{itemize}
%\item
%\end{itemize}
%\subsubsection{Semantiek}
%
%\subsubsection{Voorbeeld}
%\begin{lstlisting}[style=SELMA]
%\end{lstlisting}
%==================================OPMAAK======================================
\newpage
\section{Vertaalregels}
Deze sectie specificeerd hoe selma programmas naar Jasmin worden vertaald. Jasmin is een assembler die gegeven Jasmin assembly JVM bytecode genereerd in de vorm van een \texttt{.class} file.
De vertaling wordt gedaan door middel van een compiler (g-files/SELMACompiler.g) in ANTLR die executeerd na de checker en producties uit de Jasmin string template aanroept (SELMACodeJasmin.stg).
We gebruiken de volgende code functies:
\begin{itemize}
\item run : Program $\rightarrow$ Instruction*
\item execute : ExpressionStatement $\rightarrow$ Instruction*
\item evaluate : Expression $\rightarrow$ Instruction*
\item elaborate : Declaration $\rightarrow$ Instruction*
\end{itemize}
\begin{tabular}{| l | c | l |}
\hline
Phase & Code Function & Effect \\
\hline \hline
Program & run P & Run P en begin en eindig met een lege stack. Doe ook de \\
&& nodige declaraties om classen en methoden te genereren. \\
&& Return hierna.\\
\hline
ExprStat & execute S & Executeer statement S. Als S een expressie is dat \\
&& een waarde op de stack genereerd, pop. Dit veranderd de \\
&& stack niet. \\
\hline
Expression & evaluate E & Evalueer expressie E en laat de nieuwe waarde op de stack staan.\\
&& Een expressie kan 1 of 2 oude waarden van de stack halen (e.g. AND). \\
\hline
Declaration & elaborate & Behandel een declaratie voor constanten, variabelen en functies.\\
&& Dit maakt entries aan in de symbol table en genereerd simpele \\
&& declaratie code zoals methoden en velden.\\
\hline
\end{tabular}
\\
In onze vertaalregels zullen we variabelen omringen met \textless en \textgreater. Soms zijn er hulpvariabelen nodig die geen deel uitmaken van de syntax. We zullen dit aanduiden als extra argumenten aan de code function, e.g. \texttt{evaluate[ID := E, is\_global, type]}, waarbij \texttt{is\_global} en \texttt{type} extra argumenten zijn die geen deel uitmaken van de syntax maar van de context.\\
\subsection{Run}
\subsubsection{Program}
\lstinputlisting[style=ANTLR,linerange={122-122,131-134}]{../g-files/SELMACodeJasmin.stg}
\begin{verbatim}
run[P, source_file, stack_limit, locals_limit, pop] =
.source <source_file>
.class public Main
.super java/lang/Object
.field public static scanner_field Ljava/Util/Scanner;
.method public static main([Ljava/lang/String;)V
.limit stack <stack_limit>
.limit locals <locals_limit>
new java/util/Scanner
dup
getstatic java/lang/System/in Ljava/io/InputStream;
invokespecial java/util/Scanner/<init>(Ljava/io/InputStream;)V
putstatic Main/scanner_field Ljava/util/Scanner;
evaluate[P]
if <pop>:
pop
return
.end method
\end{verbatim}
De \texttt{source\_file}, \texttt{stack\_limit} en \texttt{locals\_limit} geven respectievelijk aan wat de originele source file was (voor runtime excepties), de grootte van de stack en het aantal locale variabelen dat het programma gebruikt. \texttt{pop} geeft aan of P een expressie was en nog een waarde op de stack heeft achtergelaten. Dit zou ook opgelost kunnen worden door de regel
\begin{verbatim}
program -> expression_statement
expression_statement -> expression
expression -> ... | compoundexpression
compoundexpression -> (declaration | expression_statement)*
\end{verbatim}
in plaats van
\begin{verbatim}
program -> compoundexpression
\end{verbatim}
Helaas resulteerd dit in Left Recursion waar we geen tijd meer voor hadden dit op te lossen. Een simpele \texttt{pop = expression.type != type.VOID} lost dit echter gauw genoeg op.\\
\\
Als er labels in code regels voorkomen als L1, L2, etc, zullen deze in werkelijkheid uniek genummerd zijn.
\subsection{Execute}
\subsubsection{ExpressionStatement}
\begin{verbatim}
execute[S, pop] =
evaluate[S]
if pop:
pop
\end{verbatim}
\texttt{S} is hierbij een expressie en pop is wederom true iff \texttt{expression.type != type.VOID}.
\subsubsection{while}
\begin{verbatim}
execute[while E; do S; od] =
L1:
evaluate[E]
ifeq L2
execute[S]
goto L1
L2:
\end{verbatim}
De \texttt{ifeq} instructie kijkt of de waarde op de top van de stack gelijk is aan 0 (boolean waarden zijn integer waarden 0 of 1), en als dat het geval is jumpt de interpreter naar de label L2 (naar de eerstvolgende instructie na de while loop). Als dit niet het geval is gaat hij verder met de eerste instructie van \texttt{S} en hierna volgt een jump naar het begin om te kijken of een volgende iteratie nodig is.
\subsection{Evaluate}
\subsubsection{Compound Expression}
Omdat een compound expression ook weer een expressie is, maar bestaat uit expressie statements, moet de codegenerator de mogelijk gegenereerde pop van de laatste expressie statement verwijderen. De regel is als volgt:
\begin{verbatim}
compoundexpression = COMPOUND (declaration | expression_statement)*
evaluate[E, last_expr_is_void] =
evaluate[E]
if not <last_expr_is_void>:
remove_last_instruction
\end{verbatim}
Hier geeft de variabele \texttt{last\_expr\_is\_void} aan of de laatste expressie (als er tenminste 1 expressie is) van type VOID is. Als dit niet het geval is, is er een pop gegenereerd door \texttt{expression\_statement} die verwijderd moet worden. Dit gebeurt door een dummy instructie \texttt{remove\_last\_instruction} te genereren die de laaste instructie verwijderd. Dit gebeurd voordat mhet resultaat naar een Jasmin aseembly file geschreven wordt.
\subsubsection{if then else expression}
\begin{verbatim}
evaluate[if E1 then E2 (else E3)?] =
evaluate[E1]
ifeq L1
evaluate[E2]
goto L2
L1:
evaluate[E3]
L2:
\end{verbatim}
\subsubsection{Identifier}
\label{Identifier}
\begin{verbatim}
evaluate[ID, kind, is_global, type] =
if kind == CONST:
ldc getvalue(<ID>)
else if is_global:
getstatic Main/<ID> <type>
else:
iload address_of(<ID>)
\end{verbatim}
Als de variabele een constante is wordt de waarde bijgehouden in de symbol table. De functie \texttt{getvalue} haalt hier de waarde van de constante op.
\texttt{address\_of} is hier een functie die gegeven een identifier zijn address als locale variabele ophaalt. Als de waarde een globale variabele is, is het een field zodat functies beschikking hebben tot deze variabele (als het een locale variabele in de statische \texttt{main} functie zou zijn zou dit niet het geval zijn). In dit geval is de \texttt{is\_global} boolean true en is \texttt{type} het type van de variabele.
\subsubsection{Integer Literal}
\begin{verbatim}
evaluate[literal, iconst, bipush, ldc] =
if iconst:
iconst_<literal>
elif bipush:
bipush <literal>
else:
ldc <literal>
\end{verbatim}
Als de integer literal in de juiste range van iconst of bipush zit, worden deze geprefereerd over ldc voor compactere bytecode.
\subsubsection{Character Literal}
\begin{verbatim}
evaluate[literal] =
bipush <literal>
\end{verbatim}
\subsubsection{Boolean Literals}
\begin{verbatim}
evaluate[true] =
iconst_1
\end{verbatim}
en
\begin{verbatim}
evaluate[false] =
iconst_0
\end{verbatim}
\subsubsection{Arithmetic, AND en OR}
\begin{verbatim}
evaluate[E1, op, E2, instruction] =
evaluate[E1]
evaluate[E2]
<instruction> ; E1 <op> E2
\end{verbatim}
Hierbij is op een binaire arithmetic operator zoals \texttt{+}, \texttt{-}, etc, of AND/OR. \texttt{instruction} is de bijbehorende JVM Jasmin instructie. De operators mappen als volgt naar hun instructies:
\begin{itemize}
\item \texttt{+} : \texttt{iadd}
\item \texttt{-} : \texttt{isub}
\item \texttt{*} : \texttt{imul}
\item \texttt{/} : \texttt{idiv}
\item \texttt{\%} : \texttt{irem}
\item \texttt{\&\&} : \texttt{iand}
\item || : \texttt{ior}
\end{itemize}
\subsubsection{Relational operators}
\begin{verbatim}
evaluate[E1 op E2, instruction] =
evaluate[E1]
evaluate[E2]
<instruction> L1 ; E1 <op> E2
iconst_0
goto L2
L1:
iconst_1
L2:
\end{verbatim}
Voor elke relational relational operator zoals \texttt{\textless=}, \texttt{==} etc wordt deze code gegenereerd met bijbehorende instructie. De opererator naar instructie mapping is als volgt:
\begin{verbatim}
< : ifcmp_lt
<= : ifcmp_le
== : ifcmp_eq
!= : ifcmp_ne
>= : ifcmp_ge
> : ifcmp_gt
\end{verbatim}
\subsubsection{Unary Plus and Minus}
\begin{verbatim}
evaluate[-E] =
evaluate[E]
ineg
\end{verbatim}
Voor unary \texttt{+} hoeft er niets te gebeuren.
\subsubsection{NOT}
\begin{verbatim}
evaluate[!E] =
evaluate[E]
ifeq L1
iconst_0
goto L2
L1:
iconst_1
L2:
\end{verbatim}
\subsubsection{Assignment}
\begin{verbatim}
evaluate[ID := E, is_global, type] =
evaluate[E]
dup
if is_global:
putstatic Main/<ID> <type>
else:
istore address_of(<ID>)
\end{verbatim}
\texttt{address\_of} is hier een functie die gegeven een identifier zijn address als locale variabele ophaalt. De boolean \texttt{is\_global} geeft aan of de variabele een globale variabele variabele is (in welk geval het een statisch veld is van de \texttt{Main} class). \texttt{type} geeft vervolgens aan van welk type dit veld (de variabele) is. De \texttt{dup} is nodig om de waarde eerst te dupliceren aangezien assignment een expressie is.
\subsubsection{Print}
\begin{verbatim}
evaluate[print(E+), type_denoters, bools, dup_top] =
for expr, type_denoter, is_bool in E, type_denoters, bools:
evaluate[expr]
if <dup_top>:
dup
if <is_bool>:
ifeq L1
ldc "true"
goto L2
L1:
ldc "false"
L2:
getstatic java/lang/System/out Ljava/io/PrintStream;
swap
invokevirtual java/io/PrintStream/println(<type_denoter>)V
\end{verbatim}
Hier krijgt de vertaalregel voor elke expressie mee of het type \texttt{boolean} is (\texttt{bools}), en welke overloaded versie van \texttt{System.out.println} moet worden aangeroepen (\texttt{type\_denoters}). In het geval van een boolean moet de waarde \texttt{"true"} of \texttt{"false"} worden geladen in plaats van de integer waarde. De boolean dup\_top geeft aan of de print een statement of expressie is. Als het een expressie is (in het geval van een enkele print), moet de waarde worden gedupliceerd op de stack voordat de println de waarde popt.
\subsubsection{Read}
\begin{verbatim}
evaluate[read(ID+), bools, ints, dup_top] =
for id, is_bool, is_int in ID, bools, ints:
getstatic Main/scanner_field Ljava/util/Scanner;
if <is_bool>:
invokevirtual java/util/Scanner/nextBoolean()Z
elif <is_int>:
invokevirtual java/util/Scanner/nextInt()I
else:
invokevirtual java/util/Scanner/nextByte()I
if <dup_top>:
dup
evaluate[ID := top of stack]
\end{verbatim}
Hier krijgt de vertaalregel voor elke expressie mee of het type \texttt{boolean} of int is (\texttt{bools}, texttt{ints}) en of de read een expressie is (\texttt{dup\_top}). \texttt{address\_of} is hier een functie die gegeven een identifier zijn address als locale variabele ophaalt. Afhankelijk van het type (boolean, integer of character) wordt een aanroep gedaan naar de methoden nextBoolean(), nextInt() of nextByte() van Scanner.
\subsubsection{Function Call}
\begin{verbatim}
evaluate[FUNCCALL ID (expr)*, param_types, return_type] =
for each expr:
evaluate[expr]
invokestatic Main/<ID>(<param_type> for param_type in <param_types>)<return_type>
\end{verbatim}
We evalueren eerst alle argumenten (\texttt{expr}), waarna we een statische aanroep doen naar de methode in \texttt{Main} met de naam van de functie aanroep. \texttt{param\_types} zijn de typen van de parameters van de functie en \texttt{return\_type} is het return type van de functie.
\subsection{Elaborate}
De elaborate code functie handeld declaraties af van constanten en variabelen en van functie definities. In elk geval worden er symbol table entries aangemaakt. In het geval van constanten wordt er geen code gegenereerd, maar wordt de constante waarde onthouden in de symbol table.
\subsubsection{Variabelen en Constanten}
\begin{verbatim}
elaborate[VarDeclaration type ID] =
increase amount of local variables by one
entry = enter <ID> of <type> and kind VAR in symbol table
if entry.level == 0:
; global scope, declare field
.field public static <ID> <type>
else:
increase amount of local variables by one
elaborate[ConstDeclaration type ID value] =
increase amount of local variables by one
enter <ID> of <type> and kind CONST in symbol table
set value on symbol table entry of <ID>
\end{verbatim}
\subsubsection{Function definition}
\begin{verbatim}
elaborate[FUNCTION ID (param_type param)* body (RETURN return_expr)? return_type] =
enter <ID> of <type> and kind FUNC in symbol table
.method public static <funcname>(<param_type for each param_type>)<return_type>
.limit stack <stack_limit>
.limit locals <locals_limit>
execute[body]
if <return_expr>:
evaluate[return_expr]
ireturn
else:
return
.end method
\end{verbatim}
Hier is \texttt{ID} de naam van de functie, \texttt{param\_type} en \texttt{param} het type en naam van elke respectievelijke parameter, \texttt{body} de function body, de optionele \texttt{return\_expr} de expressie waarvan de waarde returned wordt, en \texttt{return\_type} het return type van de functie.
We genereren dus een statische methode, aangezien we de \texttt{Main} class nooit instantieren.
\\
Aangezien methoden niet gegeneerd kunnen worden in een andere methode, herschrijft onze "post-processor" methoden in methoden naar een lijst van methoden. i.e.
\begin{verbatim}
.method A
.method B
...
.end method
.end method
\end{verbatim}
wordt
\begin{verbatim}