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
|
package ast.nodes;
import ast.types.*;
import codegen.Label;
import java.util.ArrayList;
import java.util.Arrays;
import semanticanalysis.STentry;
import semanticanalysis.SemanticError;
import semanticanalysis.SymbolTable;
/**
* Node for the `expr` statement of the grammar.
*/
public class ExprNode implements Node {
private final AtomNode atom;
private final Node compOp;
private final String op;
private final ArrayList<Node> exprs;
private final ArrayList<Node> trailers;
// VERY scatchy
private int paramNumber;
private String funL;
public ExprNode(Node atom, Node compOp, ArrayList<Node> exprs, String op, ArrayList<Node> trailers) {
this.atom = (AtomNode) atom;
this.compOp = compOp;
this.exprs = exprs;
this.op = op;
this.trailers = trailers;
}
/**
* Returns the i-th expressions of `exprs` field. If the index is greater or
* equals than the size return `null`.
*/
public Node getExpr(int i) {
if (i >= this.exprs.size()) {
return null;
}
return this.exprs.get(i);
}
public void setExpr(int i, Node expr) {
this.exprs.set(i, expr);
}
/**
* Returns the identifier of the `AtomNode` if it's not `null`, otherwise
* returns `null`.
*/
public String getId() {
if (atom != null) {
return ((AtomNode) this.atom).getId();
} else {
return null;
}
}
public Node getCompOp() {
return compOp;
}
public String getOp() {
return op;
}
public ArrayList<Node> getTrailers() {
return trailers;
}
public ArrayList<Node> getExprs() {
return exprs;
}
public AtomNode getAtom() {
return atom;
}
@Override
public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting, FunctionType ft) {
ArrayList<SemanticError> errors = new ArrayList<>();
// Check if the atom is a function
if (isFunctionCall()) {
// Check if the atom is not a built-in function
if (!Arrays.asList(bif).contains(atom.getId())) {
errors.addAll(atom.checkSemantics(ST, _nesting, ft));
TrailerNode trailer = (TrailerNode) trailers.get(0);
String funName = atom.getId();
STentry fun = ST.lookup(funName);
if (fun != null && !(fun.getType() instanceof ImportType)) {
if ((fun.getType() instanceof FunctionType)) {
FunctionType atomFt = (FunctionType) fun.getType();
paramNumber = atomFt.getParamNumber();
funL = atomFt.getLabel();
int argNumber = trailer.getArgumentNumber();
if (paramNumber != argNumber) {
errors.add(new SemanticError(funName + "() takes " + String.valueOf(paramNumber)
+ " positional arguments but " + String.valueOf(argNumber) + " were given."));
}
}
for (var t : trailers) {
errors.addAll(t.checkSemantics(ST, _nesting, ft));
}
}
} else {
for (var trailer : trailers) {
errors.addAll(trailer.checkSemantics(ST, _nesting, ft));
}
}
} else if (atom != null) {
errors.addAll(atom.checkSemantics(ST, _nesting, ft));
}
if (compOp != null) {
errors.addAll(compOp.checkSemantics(ST, _nesting, ft));
}
for (var expr : exprs) {
errors.addAll(expr.checkSemantics(ST, _nesting, ft));
}
return errors;
}
@Override
public Type typeCheck() {
if (this.atom != null) {
return this.atom.typeCheck();
}
return new VoidType();
}
public boolean isFunctionCall() {
return atom != null && !trailers.isEmpty();
}
@Override
public String codeGeneration() {
// A function call
if (isFunctionCall()) {
TrailerNode trailer = (TrailerNode) trailers.get(0);
String trailerS = trailer.codeGeneration();
// If the atom is a built-in function. return the trailer's content
if (Arrays.asList(bif).contains(atom.getId())) {
// remove "pushr A0\n" at the end of the trailer because it's useless
return trailerS.substring(0, trailerS.length() - 9);
}
// We're not considering nested functions, so despite of slide 62
// we do not have a forloop for nesting_level -
// loopkup(..).nesting_level here.
return "pushr FP\n"
+ "move SP FP\n"
+ "addi FP 1\n"
+ "move AL T1\n"
+ "pushr T1\n"
+ trailerS
+ "move FP AL\n"
+ "subi AL 1\n"
+ "jsub " + funL + "\n";
}
// Check operation
if (op != null) {
switch (op) {
case "+":
case "-":
case "*":
// In real Python `/` is a float division but we'll consider the
// int division here below.
case "/":
return intOpCodeGen(exprs.get(0), exprs.get(1), op);
case "%":
return modCodeGen(exprs.get(0), exprs.get(1));
case "and":
return andCodeGen(exprs.get(0), exprs.get(1));
case "or":
return orCodeGen(exprs.get(0), exprs.get(1));
case "not":
return notCodeGen(exprs.get(0));
default:
return "Error: operation " + op + " not supported\n";
}
}
// Check comp operation
if (compOp != null) {
CompOpNode cmpOp = (CompOpNode) compOp;
String op = cmpOp.getOp();
switch (op) {
case "==":
return eqCodeGen(exprs.get(0), exprs.get(1));
case "!=":
return neqCodeGen(exprs.get(0), exprs.get(1));
case "<":
return lsCodeGen(exprs.get(0), exprs.get(1));
case "<=":
return leqCodeGen(exprs.get(0), exprs.get(1));
case ">":
return gtCodeGen(exprs.get(0), exprs.get(1));
case ">=":
return gteCodeGen(exprs.get(0), exprs.get(1));
default:
return "Error: operation " + op + " not supported\n";
}
}
if (atom != null) {
return atom.codeGeneration();
}
if (!exprs.isEmpty()) {
String str = "";
for (var expr : exprs) {
str += expr.codeGeneration();
}
return str;
}
return "Error: cannot recognize the expression\n";
}
@Override
public String printAST(String prefix) {
String str = prefix + "Expr\n";
prefix += " ";
if (atom != null) {
str += atom.printAST(prefix);
for (var trailer : trailers) {
str += trailer.printAST(prefix);
}
} else {
if (compOp != null) {
str += compOp.printAST(prefix);
}
if (exprs != null) {
for (var expr : exprs) {
str += expr.printAST(prefix);
}
}
if (op != null) {
str += prefix + "Op(" + op + ")\n";
}
}
return str;
}
@Override
public String toPrint(String prefix) {
String str = prefix;
if (atom != null) {
str += atom.toPrint("");
for (var trailer : trailers) {
str += trailer.toPrint("");
}
} else {
if (op == "+" || op == "-" || op == "~") {
str += prefix + op + exprs.get(0).toPrint("");
} else {
str += prefix + exprs.get(0).toPrint("") + " ";
if (compOp != null) {
str += compOp.toPrint("") + " " + exprs.get(1).toPrint("");
} else {
str += op + " " + exprs.get(1).toPrint("");
}
}
}
return str;
}
private String intOpCodeGen(Node leftE, Node rightE, String op) {
String ls = leftE.codeGeneration();
String rs = rightE.codeGeneration();
String ops;
switch (op) {
case "+":
ops = "add";
break;
case "-":
ops = "sub";
break;
case "*":
ops = "mul";
break;
case "/":
ops = "div";
break;
default:
ops = "Error: cannot manage op " + op;
}
return ls
+ "pushr A0\n"
+ rs
+ "popr T1\n"
+ ops + " T1 A0\n"
+ "popr A0\n";
}
private String modCodeGen(Node leftE, Node rightE) {
String ls = leftE.codeGeneration();
String rs = rightE.codeGeneration();
// Push the register twice because, for instance,
// 7 % 2 =
// 7 / 2 = 3
// 3 * 2 = 6
// 7 - 6 = 1 <--- result
return ls
+ "pushr A0\n"
+ "pushr A0\n"
+ rs
+ "popr T1\n"
+ // Divide the two numbers
"div T1 A0\n"
+ "popr T1\n"
+ // Multiply the division result for the number at the left
"mul T1 A0\n"
+ "popr A0\n"
+ // Get the previous number at the left from the stack
"popr T1\n"
+ // Subtracting the two numbers we have the module value
"sub T1 A0\n"
+ "popr A0\n";
}
/**
* NOTE: for the boolean operation we assume that False = 0, True = 1 NOTE:
* we should optimize ignoring the the right value if the left value is
* false.
*/
private String andCodeGen(Node leftE, Node rightE) {
String endl = Label.newBasic("endAnd");
String ls = leftE.codeGeneration();
String rs = rightE.codeGeneration();
return ls
+ "storei T1 0\n"
+ "beq A0 T1 " + endl + "\n"
+ rs
+ endl + ":\n";
}
/**
* NOTE: we should optimize ignoring the right value if the left value is
* true.
*/
private String orCodeGen(Node leftE, Node rightE) {
String endl = Label.newBasic("endOr");
String ls = leftE.codeGeneration();
String rs = rightE.codeGeneration();
return ls
+ "storei T1 1\n"
+ "beq A0 T1 " + endl + "\n"
+ rs
+ endl + ":\n";
}
private String notCodeGen(Node expr) {
String exprs = expr.codeGeneration();
// We use the `sub` because:
// not True = 1 - 1 = 0 = False
// not False = 1 - 0 = 1 = True
return exprs
+ "storei T1 1\n"
+ "sub T1 A0\n"
+ "popr A0\n";
}
private String eqCodeGen(Node leftE, Node rightE) {
String truel = Label.newBasic("true");
String endl = Label.newBasic("end");
String ls = leftE.codeGeneration();
String rs = rightE.codeGeneration();
return ls
+ "pushr A0\n"
+ rs
+ "popr T1\n"
+ "beq T1 A0 " + truel + "\n"
+ "storei A0 0\n"
+ "b " + endl + "\n"
+ truel + ":\n"
+ "storei A0 1\n"
+ endl + ":\n";
}
private String neqCodeGen(Node leftE, Node rightE) {
String truel = Label.newBasic("true");
String endl = Label.newBasic("end");
String ls = leftE.codeGeneration();
String rs = rightE.codeGeneration();
return ls
+ "pushr A0\n"
+ rs
+ "popr T1\n"
+ "beq T1 A0 " + truel + "\n"
+ "storei A0 1\n"
+ // storei A0 1 instead of storei A0 0
"b " + endl + "\n"
+ truel + ":\n"
+ // storei A0 0 instead of storei A0 1
"storei A0 0\n"
+ endl + ":\n";
}
private String lsCodeGen(Node leftE, Node rightE) {
String truel = Label.newBasic("true");
String truel2 = Label.newBasic("true");
String endl = Label.newBasic("end");
String ls = leftE.codeGeneration();
String rs = rightE.codeGeneration();
return ls
+ "pushr A0\n"
+ rs
+ "popr T1\n"
+ "bleq T1 A0 " + truel + "\n"
+ "storei A0 0\n"
+ "b " + endl + "\n"
+ truel + ":\n"
+ "beq T1 A0 " + truel2 + "\n"
+ "storei A0 1\n"
+ "b " + endl + "\n"
+ truel2 + ":\n"
+ "storei A0 0\n"
+ "b " + endl + "\n"
+ endl + ":\n";
}
private String leqCodeGen(Node leftE, Node rightE) {
String truel = Label.newBasic("true");
String endl = Label.newBasic("end");
String ls = leftE.codeGeneration();
String rs = rightE.codeGeneration();
return ls
+ "pushr A0\n"
+ rs
+ "popr T1\n"
+ "bleq T1 A0 " + truel + "\n"
+ "storei A0 0\n"
+ "b " + endl + "\n"
+ truel + ":\n"
+ "storei A0 1\n"
+ endl + ":\n";
}
private String gtCodeGen(Node leftE, Node rightE) {
String truel = Label.newBasic("true");
String endl = Label.newBasic("end");
String ls = leftE.codeGeneration();
String rs = rightE.codeGeneration();
return ls
+ "pushr A0\n"
+ rs
+ "popr T1\n"
+ // Invert A0 and T1 (different than leq)
"bleq A0 T1 " + truel + "\n"
+ "storei A0 0\n"
+ "b " + endl + "\n"
+ truel + ":\n"
+ "storei A0 1\n"
+ endl + ":\n";
}
private String gteCodeGen(Node leftE, Node rightE) {
String truel = Label.newBasic("true");
String truel2 = Label.newBasic("true");
String endl = Label.newBasic("end");
String ls = leftE.codeGeneration();
String rs = rightE.codeGeneration();
return ls
+ "pushr A0\n"
+ rs
+ "popr T1\n"
+ "bleq T1 A0 " + truel + "\n"
+ "storei A0 1\n"
+ "b " + endl + "\n"
+ truel + ":\n"
+ "beq T1 A0 " + truel2 + "\n"
+ "storei A0 0\n"
+ "b " + endl + "\n"
+ truel2 + ":\n"
+ "storei A0 1\n"
+ "b " + endl + "\n"
+ endl + ":\n";
}
}
|