summaryrefslogtreecommitdiff
path: root/src/ast/nodes/ExprNode.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/ast/nodes/ExprNode.java')
-rw-r--r--src/ast/nodes/ExprNode.java354
1 files changed, 329 insertions, 25 deletions
diff --git a/src/ast/nodes/ExprNode.java b/src/ast/nodes/ExprNode.java
index 693176a..dec0b54 100644
--- a/src/ast/nodes/ExprNode.java
+++ b/src/ast/nodes/ExprNode.java
@@ -3,9 +3,11 @@ package ast.nodes;
import ast.types.*;
import java.util.ArrayList;
import java.util.Arrays;
+
import semanticanalysis.STentry;
import semanticanalysis.SemanticError;
import semanticanalysis.SymbolTable;
+import codegen.Label;
/**
* Node for the `expr` statement of the grammar.
@@ -18,6 +20,10 @@ public class ExprNode implements Node {
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;
@@ -51,16 +57,15 @@ public class ExprNode implements Node {
}
@Override
- public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ 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 a function
- if (atom != null && !trailers.isEmpty()) {
-
- // check if the atom is not a built-in function
+ // Check if the atom is not a built-in function
if (!Arrays.asList(bif).contains(atom.getId())) {
- errors.addAll(atom.checkSemantics(ST, _nesting));
+ errors.addAll(atom.checkSemantics(ST, _nesting, ft));
TrailerNode trailer = (TrailerNode) trailers.get(0);
String funName = atom.getId();
@@ -69,14 +74,10 @@ public class ExprNode implements Node {
STentry fun = ST.lookup(funName);
if (fun != null && !(fun.getType() instanceof ImportType)) {
- if (!(fun.getType() instanceof FunctionType)) {
- for (var t : trailers) {
- errors.addAll(t.checkSemantics(ST, _nesting));
- }
-
- } else {
- FunctionType ft = (FunctionType) fun.getType();
- int paramNumber = ft.getParamNumber();
+ if ((fun.getType() instanceof FunctionType)) {
+ FunctionType atomFt = (FunctionType) fun.getType();
+ paramNumber = atomFt.getParamNumber();
+ funL = atomFt.getLabel();
int argNumber = trailer.getArgumentNumber();
if (paramNumber != argNumber) {
@@ -84,23 +85,25 @@ public class ExprNode implements Node {
+ " 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));
+ errors.addAll(trailer.checkSemantics(ST, _nesting, ft));
}
-
}
} else if (atom != null) {
- errors.addAll(atom.checkSemantics(ST, _nesting));
+ errors.addAll(atom.checkSemantics(ST, _nesting, ft));
}
if (compOp != null) {
- errors.addAll(compOp.checkSemantics(ST, _nesting));
+ errors.addAll(compOp.checkSemantics(ST, _nesting, ft));
}
for (var expr : exprs) {
- errors.addAll(expr.checkSemantics(ST, _nesting));
+ errors.addAll(expr.checkSemantics(ST, _nesting, ft));
}
return errors;
@@ -116,10 +119,95 @@ public class ExprNode implements Node {
return new VoidType();
}
- // TODO: add code generation for expr
+ public boolean isFunctionCall() {
+ return atom != null && !trailers.isEmpty();
+ }
+
@Override
public String codeGeneration() {
- return "";
+
+ // 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())) {
+ return trailerS;
+ }
+
+ // 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
@@ -133,19 +221,19 @@ public class ExprNode implements Node {
if (compOp != null) {
str += compOp.toPrint(prefix);
}
-
+
if (exprs != null) {
for (var expr : exprs) {
str += expr.toPrint(prefix);
}
}
-
+
if (trailers != null) {
for (var trailer : trailers) {
str += trailer.toPrint(prefix);
}
- }
-
+ }
+
if (op != null) {
str += prefix + "Op(" + op + ")\n";
}
@@ -153,4 +241,220 @@ public class ExprNode implements Node {
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";
+ }
+
}