-
Notifications
You must be signed in to change notification settings - Fork 0
/
Compiler.atg
197 lines (158 loc) · 6.37 KB
/
Compiler.atg
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
import fi.tkk.cs.tkkcc.slx.CommandWord;
COMPILER SLXProject
CodeGenerator gen;
SymbolTable tab;
public static final int UNDEF = 0;
public static final int INTEGER = 1;
public static final int BOOL = 2;
public static final int AND = 3;
public static final int LT = 4;
public static final int GT = 5;
public static final int ADD = 6;
public static final int SUB = 7;
public static final int MUL = 8;
public static final int DIV = 9;
public static final int LOAD = 10;
public static final int STORE = 11;
CHARACTERS
letter = 'A'..'Z' + 'a'..'z'.
digit = '0'..'9'.
/*
While more tokens could be defined such as assignment ':=' , and '&&', '+', '-' etc,
I'll specify them in the parser as literals to keep my EBNF productions
looking similar as in the original assignment. Productions will be easier to read.
*/
TOKENS
identifier = letter {letter | digit | '_'}. /* Identifier must start with a letter to prevent ambiguity */
integer = digit { digit }. /* Negative numbers not possible in grammar. Also Interger size check implemented later in parser */
IGNORE '\n' + '\r' /* Ignore LF CR */
PRODUCTIONS
SLXProject
=
MainFuncDecl
.
MainFuncDecl
=
"main" FuncBody (. gen.emit(CommandWord.HLT); .) /* Halt the program after execution */
.
FuncBody
=
'{' VarDecl StatementList ReturnStatement '}'
.
VarDecl (. String name; int type; .)
=
{
Type<out type>
Ident<out name> (. if(tab.FindObj(name) != null) { SemErr("Symbol " + name + " already declared"); } /* Semantic error if symbol already exists in symbol table */
else { tab.NewObj(name, type); } /* Otherwise insert into symbol table */ .)
';'
}
.
/* Return value on top of the stack, no need to do anything since Expr-production already does that */
ReturnStatement (. int type; .)
=
"return" Expr<out type> ';'
.
StatementList
=
[Statement StatementList]
.
Statement (. Obj a; String name; int type; .)
=
"if" '(' Expr<out type> ')' (. if(type!=BOOL) SemErr("Boolean type required for if-clause");
gen.emit(CommandWord.JZE, gen.lab); /* If Expr value in the stack Equals 0, Jump to next emitted label */ .)
"then"
Statement (. gen.emit(CommandWord.JMP, gen.lab + 1); /* Expr did not equal zero, jump till the end after executing Statement code */ .)
"else" (. gen.emit(CommandWord.LAB, gen.lab); /* Label for "false" statement */ .)
Statement "fi" (. gen.emit(CommandWord.LAB, gen.lab); /* Label for end of if statement */ .)
| "repeat" (. gen.emit(CommandWord.LAB, gen.lab); /* Label for start of program code to be repeated */ .)
Statement
"until" '(' Expr<out type> ')' ';' (. /* If executing Statement puts 0 in the stack, jump back to label */
gen.emit(CommandWord.JZE, gen.lab - 1); .)
| "print" '(' Expr<out type> ')' ';' (. gen.emit(CommandWord.WRI); /* Emit write */ .)
| '{' StatementList '}'
| IdAccess<out name> (. a = tab.FindObj(name); if(a != null) { gen.emit(CommandWord.ENT, a.adr); } /* Variable address from symbol table to stack */ .)
":=" Expr<out type> ';' (. if(a != null) {
if(type != a.type) SemErr("Assigning incompatible type");
gen.emit(CommandWord.STM);
} .)
.
/* Different operations and type checking for them. Result will be left on top of the stack */
Expr<out int type> (. int type2, type3, op; type = UNDEF; .)
=
BaseExpr<out type2> (. type = type2; .)
[Operation<out op> BaseExpr<out type3> (. if(type2==INTEGER) {
if(type3==BOOL) { SemErr("Incompatible types Integer and Boolean in operation, expected type Integer and Integer"); }
else if(op == AND) { SemErr("Invalid operation for types Integer and Integer"); }
else {
if(op == ADD) { gen.emit(CommandWord.ADD); type = INTEGER; }
if(op == SUB) { gen.emit(CommandWord.SUB); type = INTEGER; }
if(op == MUL) { gen.emit(CommandWord.MUL); type = INTEGER; }
if(op == DIV) { gen.emit(CommandWord.DIV); type = INTEGER; }
if(op == LT) { gen.emit(CommandWord.RLT); type = BOOL; }
if(op == GT) { gen.emit(CommandWord.RGT); type = BOOL; }
}
} else if(type2==BOOL) {
if(type3==INTEGER) { SemErr("Incompatible types Boolean and Integer in operation, expected type Boolean and Boolean"); }
else if(op == ADD || op == SUB || op == MUL || op == DIV || op == LT || op == GT) {
SemErr("Invalid operation for types Boolean and Boolean");
} else {
if(op == AND) {
/* SLX has no AND instruction so let's emulate it with a series of commands
tested to produce correct results with 0&&0=0 0&&1=0 1&&0=0 1&&1=1 */
gen.emit(CommandWord.NOT);
gen.emit(CommandWord.ENT, 1);
gen.emit(CommandWord.ADD);
gen.emit(CommandWord.REQ);
type = BOOL;
}
}
} .)
] | '!' BaseExpr<out type2> (. gen.emit(CommandWord.NOT); type = BOOL; .)
.
/* New production for operation */
Operation<out int op> (. op = UNDEF; .)
=
"&&" (. op = AND; .)
| '<' (. op = LT; .)
| '>' (. op = GT; .)
| '+' (. op = ADD; .)
| '-' (. op = SUB; .)
| '*' (. op = MUL; .)
| '/' (. op = DIV; .)
.
BaseExpr<out int type> (. int type2; Obj a; String name; type = UNDEF; .)
=
'(' Expr<out type> ')'
| IdAccess<out name> (. a = tab.FindObj(name); if(a != null) { type = a.type; gen.emit(CommandWord.ENT, a.adr); gen.emit(CommandWord.LDM); } .)
| Integer (. type = INTEGER; .)
| Boolean (. type = BOOL; .)
| "read" '(' ')' (. gen.emit(CommandWord.REA); type = INTEGER; .)
.
IdAccess<out String name> (. Obj a; .)
=
Ident<out name> (. a = tab.FindObj(name); if(a == null) { SemErr("Undeclared variable: " + name); } /* Less code to do this here */ .)
.
Type<out int type> (. type = UNDEF; .)
=
"int" (. type = INTEGER; .)
| "boolean" (. type = BOOL; .)
.
/* Ident for variable declaration. Separate production for clarity. */
Ident<out String name>
=
identifier (. name = t.val; .)
.
/* New production for integer */
Integer (. int temp = 0; .)
=
integer (. try { temp = Integer.parseInt(t.val); gen.emit(CommandWord.ENT, temp); /* Try to parse Integer */
} catch(Exception e) { SemErr("Integer overflow"); } /* Exception generated. Cannot parse Integer */ .)
.
/* New production for boolean */
Boolean
=
"true" (. gen.emit(CommandWord.ENT, 1); .)
| "false" (. gen.emit(CommandWord.ENT, 0); .)
.
END SLXProject.