diff options
Diffstat (limited to 'src/ast/nodes/ExprNode.java')
-rw-r--r-- | src/ast/nodes/ExprNode.java | 354 |
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"; + } + } |