summaryrefslogtreecommitdiff
path: root/src/ast
diff options
context:
space:
mode:
Diffstat (limited to 'src/ast')
-rw-r--r--src/ast/Python3VisitorImpl.java32
-rw-r--r--src/ast/nodes/ArglistNode.java15
-rw-r--r--src/ast/nodes/AssignmentNode.java65
-rw-r--r--src/ast/nodes/AtomNode.java71
-rw-r--r--src/ast/nodes/AugassignNode.java5
-rw-r--r--src/ast/nodes/BlockNode.java15
-rw-r--r--src/ast/nodes/CompForNode.java12
-rw-r--r--src/ast/nodes/CompIterNode.java9
-rw-r--r--src/ast/nodes/CompOpNode.java (renamed from src/ast/nodes/CompNode.java)16
-rw-r--r--src/ast/nodes/CompoundNode.java29
-rw-r--r--src/ast/nodes/DottedNameNode.java8
-rw-r--r--src/ast/nodes/ExprListNode.java13
-rw-r--r--src/ast/nodes/ExprNode.java354
-rw-r--r--src/ast/nodes/ForStmtNode.java11
-rw-r--r--src/ast/nodes/FuncdefNode.java37
-rw-r--r--src/ast/nodes/IfNode.java58
-rw-r--r--src/ast/nodes/ImportNode.java8
-rw-r--r--src/ast/nodes/Node.java2
-rw-r--r--src/ast/nodes/ParamdefNode.java2
-rw-r--r--src/ast/nodes/ParamlistNode.java9
-rw-r--r--src/ast/nodes/ReturnStmtNode.java28
-rw-r--r--src/ast/nodes/RootNode.java16
-rw-r--r--src/ast/nodes/SimpleStmtNode.java30
-rw-r--r--src/ast/nodes/SimpleStmtsNode.java13
-rw-r--r--src/ast/nodes/TestlistCompNode.java22
-rw-r--r--src/ast/nodes/TrailerNode.java10
-rw-r--r--src/ast/nodes/WhileStmtNode.java8
-rw-r--r--src/ast/types/FunctionType.java25
-rw-r--r--src/ast/types/Type.java2
29 files changed, 737 insertions, 188 deletions
diff --git a/src/ast/Python3VisitorImpl.java b/src/ast/Python3VisitorImpl.java
index 1cf15b7..98ede6d 100644
--- a/src/ast/Python3VisitorImpl.java
+++ b/src/ast/Python3VisitorImpl.java
@@ -336,7 +336,7 @@ public class Python3VisitorImpl extends Python3ParserBaseVisitor<Node> {
}
/**
- * Returns a `CompNode`. It should never be null.
+ * Returns a `CompOpNode`. It should never be null.
*
* ``` comp_op : '<' | '>' | '==' | '>=' | '<=' | '<>' | '!=' | 'in' | 'not'
* 'in' | 'is' | 'is' 'not' ; ```
@@ -344,24 +344,24 @@ public class Python3VisitorImpl extends Python3ParserBaseVisitor<Node> {
public Node visitComp_op(Comp_opContext ctx) {
Node comp = null;
if (ctx.LESS_THAN() != null) {
- comp = new CompNode(ctx.LESS_THAN());
+ comp = new CompOpNode(ctx.LESS_THAN());
} else if (ctx.GREATER_THAN() != null) {
- comp = new CompNode(ctx.GREATER_THAN());
+ comp = new CompOpNode(ctx.GREATER_THAN());
} else if (ctx.EQUALS() != null) {
- comp = new CompNode(ctx.EQUALS());
+ comp = new CompOpNode(ctx.EQUALS());
} else if (ctx.GT_EQ() != null) {
- comp = new CompNode(ctx.GT_EQ());
+ comp = new CompOpNode(ctx.GT_EQ());
} else if (ctx.LT_EQ() != null) {
- comp = new CompNode(ctx.LT_EQ());
+ comp = new CompOpNode(ctx.LT_EQ());
} else if (ctx.NOT_EQ_2() != null) {
// We're ignoring NOT_EQ_1() because no one uses `<>`
- comp = new CompNode(ctx.NOT_EQ_2());
+ comp = new CompOpNode(ctx.NOT_EQ_2());
} else if (ctx.IN() != null) {
- comp = new CompNode(ctx.IN());
+ comp = new CompOpNode(ctx.IN());
} else if (ctx.NOT() != null) {
- comp = new CompNode(ctx.NOT());
+ comp = new CompOpNode(ctx.NOT());
} else if (ctx.IS() != null) {
- comp = new CompNode(ctx.IS());
+ comp = new CompOpNode(ctx.IS());
}
return comp;
@@ -396,6 +396,14 @@ public class Python3VisitorImpl extends Python3ParserBaseVisitor<Node> {
op = ctx.NOT().toString();
}
+ if (ctx.AND() != null) {
+ op = ctx.AND().toString();
+ }
+
+ if (ctx.OR() != null) {
+ op = ctx.OR().toString();
+ }
+
if (ctx.STAR() != null) {
op = ctx.STAR().toString();
}
@@ -404,6 +412,10 @@ public class Python3VisitorImpl extends Python3ParserBaseVisitor<Node> {
op = ctx.DIV().toString();
}
+ if (ctx.MOD() != null) {
+ op = ctx.MOD().toString();
+ }
+
if (ctx.atom() != null) {
atom = visit(ctx.atom());
}
diff --git a/src/ast/nodes/ArglistNode.java b/src/ast/nodes/ArglistNode.java
index a0ea25b..5da7e2c 100644
--- a/src/ast/nodes/ArglistNode.java
+++ b/src/ast/nodes/ArglistNode.java
@@ -18,16 +18,16 @@ public class ArglistNode 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<>();
for (var arg : arguments) {
if (arg instanceof ExprNode) {
ExprNode argExpr = (ExprNode) arg;
String argName = argExpr.getId();
+ errors.addAll(arg.checkSemantics(ST, _nesting, ft));
- // TODO: check fucking IntType for params
- // TODO: remove fucking comments
+ // TODO: check IntType for params
if (argName != null) {
if (Arrays.asList(bif).contains(argName)) {
continue;
@@ -40,8 +40,6 @@ public class ArglistNode implements Node {
if (ST.nslookup(argName) < 0 && argExpr.typeCheck() instanceof AtomType) {
errors.add(new SemanticError("name '" + argName + "' is not defined."));
}
- } else {
- errors.addAll(arg.checkSemantics(ST, _nesting));
}
}
}
@@ -58,10 +56,13 @@ public class ArglistNode implements Node {
return new VoidType();
}
- // TODO: add code generation for arglist node
@Override
public String codeGeneration() {
- return "";
+ String str = "";
+ for (Node arg : arguments) {
+ str += arg.codeGeneration() + "pushr A0\n";
+ }
+ return str;
}
@Override
diff --git a/src/ast/nodes/AssignmentNode.java b/src/ast/nodes/AssignmentNode.java
index c4a44dc..358d497 100644
--- a/src/ast/nodes/AssignmentNode.java
+++ b/src/ast/nodes/AssignmentNode.java
@@ -2,6 +2,8 @@ package ast.nodes;
import ast.types.*;
import java.util.ArrayList;
+
+import semanticanalysis.STentry;
import semanticanalysis.SemanticError;
import semanticanalysis.SymbolTable;
@@ -14,35 +16,45 @@ public class AssignmentNode implements Node {
private final Node assign;
private final ExprListNode rhr;
+ // Useful for code gen
+ private int offset;
+ private boolean alreadyDef;
+
public AssignmentNode(Node lhr, Node assign, Node rhr) {
this.lhr = (ExprListNode) lhr;
this.assign = assign;
this.rhr = (ExprListNode) rhr;
+ this.alreadyDef = false;
}
@Override
- public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting, FunctionType ft) {
ArrayList<SemanticError> errors = new ArrayList<>();
- // errors.addAll(lhr.checkSemantics(ST, _nesting));
- errors.addAll(assign.checkSemantics(ST, _nesting));
- errors.addAll(rhr.checkSemantics(ST, _nesting));
+ // DO NOT CHECK lhr
+ errors.addAll(assign.checkSemantics(ST, _nesting, ft));
+ errors.addAll(rhr.checkSemantics(ST, _nesting, ft));
int lsize = lhr.getSize();
- // FIXME: unused variable
- // int rsize = rhr.getSize();
- // if (lsize == rsize) {
for (int i = 0; i < lsize; i++) {
- ExprNode latom = (ExprNode) lhr.getElem(i);
- ST.insert(latom.getId(), new AtomType(), _nesting, "");
- // ExprNode ratom = (ExprNode) rhr.getElem(i);
- }
- // } else {
- // FIX: sgravata da piĆ¹ problemi che altro
- // errors.add(new SemanticError("ValueError: different size of left or right side assignment"));
- // }
+ ExprNode leftAtom = (ExprNode) lhr.getElem(i);
+ STentry e = ST.lookup(leftAtom.getId());
+ if (ft != null) {
+ ft.addLocalVar();
+ }
+ if (e == null) {
+ ST.insert(leftAtom.getId(), new AtomType(), _nesting, "");
+ e = ST.lookup(leftAtom.getId());
+ } else {
+ int ns = e.getNesting();
+ if (_nesting == ns) {
+ this.alreadyDef = true;
+ }
+ }
+ offset = e.getOffset();
+ }
return errors;
}
@@ -52,10 +64,29 @@ public class AssignmentNode implements Node {
return rhr.typeCheck();
}
- // TODO: add code generation for assignment
@Override
public String codeGeneration() {
- return "";
+ String rhrString = rhr.codeGeneration();
+
+ String lhrString = "";
+ ExprNode leftAtom = (ExprNode) lhr.getElem(0);
+
+ // The code generation for the left atom returns a `store A0 0(T1)` at
+ // the end but we do not want that command.
+ // So, we'll have a string with the substring + the offset.
+ String leftAtomCode = leftAtom.codeGeneration();
+ lhrString += leftAtomCode.substring(0, leftAtomCode.length() - 17) + offset;
+
+ // If the variable name is previously defined it'll load the variable
+ // from the `0(T1)`, otherwise it'll push the `A0` register at the top
+ // of the stack.
+ if (!this.alreadyDef) {
+ lhrString += "\npushr A0\n";
+ } else {
+ lhrString += "\nload A0 0(T1)\n";
+ }
+
+ return rhrString + lhrString;
}
@Override
diff --git a/src/ast/nodes/AtomNode.java b/src/ast/nodes/AtomNode.java
index 37d4d79..ea99808 100644
--- a/src/ast/nodes/AtomNode.java
+++ b/src/ast/nodes/AtomNode.java
@@ -2,6 +2,7 @@ package ast.nodes;
import ast.types.*;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import semanticanalysis.SemanticError;
@@ -15,6 +16,10 @@ public class AtomNode implements Node {
protected String val;
protected TestlistCompNode exprlist;
+ // very scatchy
+ protected int ns;
+ protected int offset;
+
public AtomNode(String val, Node exprlist) {
this.val = val;
this.exprlist = (TestlistCompNode) exprlist;
@@ -25,23 +30,29 @@ public class AtomNode implements Node {
* returns `null`.
*/
public String getId() {
- return this.val;
+ return val;
}
@Override
- public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting, FunctionType ft) {
ArrayList<SemanticError> errors = new ArrayList<>();
if (val != null) {
- if ((this.typeCheck() instanceof AtomType) && ST.nslookup(this.getId()) < 0) {
- errors.add(new SemanticError("name '" + this.getId() + "' is not defined."));
- } else {
- // System.out.println("exist " + this.typeCheck());
+ if (!Arrays.asList(bif).contains(getId())) {
+ if ((typeCheck() instanceof AtomType) && ST.nslookup(getId()) < 0) {
+ errors.add(new SemanticError("name '" + getId() + "' is not defined."));
+ } else {
+ if ((typeCheck() instanceof AtomType)) {
+ int varNs = ST.lookup(getId()).getNesting();
+ this.ns = _nesting - varNs;
+ offset = ST.lookup(getId()).getOffset();
+ }
+ }
}
}
if (exprlist != null) {
- errors.addAll(exprlist.checkSemantics(ST, _nesting));
+ errors.addAll(exprlist.checkSemantics(ST, _nesting, ft));
}
return errors;
@@ -50,29 +61,34 @@ public class AtomNode implements Node {
// ENHANCE: return more specific types
@Override
public Type typeCheck() {
- if (this.val == null) {
+ if (val == null) {
return new VoidType();
}
Pattern noneVariable = Pattern.compile("^(None)$");
Pattern booleanVariable = Pattern.compile("^(True|False)$");
+ Pattern integerVariable = Pattern.compile("^[0-9]+$");
Pattern reservedWords = Pattern.compile("^(continue|break|int|float)$");
// this regex should match every possible atom name written in this format: CHAR
// (CHAR | DIGIT)*
Pattern simpleVariable = Pattern.compile("^[a-zA-Z][a-zA-Z0-9]*$", Pattern.CASE_INSENSITIVE);
- Matcher noneVariableMatcher = noneVariable.matcher(this.val);
- Matcher booleanVariableMatcher = booleanVariable.matcher(this.val);
- Matcher reservedWordsMatcher = reservedWords.matcher(this.val);
- Matcher simpleVariableMatcher = simpleVariable.matcher(this.val);
+ Matcher noneVariableMatcher = noneVariable.matcher(val);
+ Matcher booleanVariableMatcher = booleanVariable.matcher(val);
+ Matcher integerVariableMatcher = integerVariable.matcher(val);
+ Matcher reservedWordsMatcher = reservedWords.matcher(val);
+ Matcher simpleVariableMatcher = simpleVariable.matcher(val);
boolean matchFoundNone = noneVariableMatcher.find();
boolean matchFoundBoolean = booleanVariableMatcher.find();
+ boolean matchFoundInteger = integerVariableMatcher.find();
boolean matchFoundContinueBreak = reservedWordsMatcher.find();
boolean matchFoundSimpleVariable = simpleVariableMatcher.find();
if (matchFoundBoolean) {
return new BoolType();
+ } else if (matchFoundInteger) {
+ return new IntType();
} else if (matchFoundContinueBreak) {
return new ReservedWordsType();
} else if (matchFoundNone) {
@@ -84,10 +100,37 @@ public class AtomNode implements Node {
}
}
- // TODO: add code generation for atom node
@Override
public String codeGeneration() {
- return "";
+ if (exprlist != null) {
+ return exprlist.codeGeneration();
+ }
+
+ if (typeCheck() instanceof IntType) {
+ return "storei A0 " + getId() + "\n";
+ }
+
+ if (typeCheck() instanceof BoolType) {
+ return "storei A0 " + boolValue(getId()) + "\n";
+ }
+
+ if (typeCheck() instanceof AtomType) {
+ // We need to ascend the access-link chain to the top (or bottom,
+ // who knows).
+ String str = "move AL T1\n";
+ for (int i = 0; i < this.ns; i++) {
+ str += "store T1 0(T1)\n";
+ }
+
+ str += "subi T1 " + offset + "\nstore A0 0(T1)\n";
+ return str;
+ }
+
+ return "Error: could not parse an atom\n";
+ }
+
+ public static String boolValue(String id) {
+ return id.equals("True") ? "1" : "0";
}
@Override
diff --git a/src/ast/nodes/AugassignNode.java b/src/ast/nodes/AugassignNode.java
index aef60cc..906dcd7 100644
--- a/src/ast/nodes/AugassignNode.java
+++ b/src/ast/nodes/AugassignNode.java
@@ -20,19 +20,18 @@ public class AugassignNode implements Node {
}
@Override
- public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting, FunctionType ft) {
return new ArrayList<>();
}
- // FIXME: use the right type
@Override
public Type typeCheck() {
return new VoidType();
}
- // TODO: add code generation for augassign node
@Override
public String codeGeneration() {
+ // We're just considering the `=` operation for this language.
return "";
}
diff --git a/src/ast/nodes/BlockNode.java b/src/ast/nodes/BlockNode.java
index 732e89b..2ea0a47 100644
--- a/src/ast/nodes/BlockNode.java
+++ b/src/ast/nodes/BlockNode.java
@@ -15,12 +15,12 @@ public class BlockNode extends RootNode {
}
@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 semantics for each child
for (Node child : childs) {
- errors.addAll(child.checkSemantics(ST, _nesting));
+ errors.addAll(child.checkSemantics(ST, _nesting, ft));
}
return errors;
@@ -32,6 +32,17 @@ public class BlockNode extends RootNode {
}
@Override
+ public String codeGeneration() {
+ String str = "";
+
+ for (Node child : childs) {
+ str += child.codeGeneration();
+ }
+
+ return str;
+ }
+
+ @Override
public String toPrint(String prefix) {
String str = prefix + "Block\n";
diff --git a/src/ast/nodes/CompForNode.java b/src/ast/nodes/CompForNode.java
index 405a400..1f51af5 100644
--- a/src/ast/nodes/CompForNode.java
+++ b/src/ast/nodes/CompForNode.java
@@ -22,13 +22,13 @@ public class CompForNode 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<>();
- errors.addAll(exprlist.checkSemantics(ST, _nesting));
- errors.addAll(single_expr.checkSemantics(ST, _nesting));
+ errors.addAll(exprlist.checkSemantics(ST, _nesting, ft));
+ errors.addAll(single_expr.checkSemantics(ST, _nesting, ft));
if (comp_iter != null) {
- errors.addAll(comp_iter.checkSemantics(ST, _nesting));
+ errors.addAll(comp_iter.checkSemantics(ST, _nesting, ft));
}
return errors;
}
@@ -38,7 +38,9 @@ public class CompForNode implements Node {
return new VoidType();
}
- // TODO: add code generation for arglist node
+ /**
+ * We do not want to provide the code generation for the for list comprehension.
+ */
@Override
public String codeGeneration() {
return "";
diff --git a/src/ast/nodes/CompIterNode.java b/src/ast/nodes/CompIterNode.java
index 1cc8a9b..de443fa 100644
--- a/src/ast/nodes/CompIterNode.java
+++ b/src/ast/nodes/CompIterNode.java
@@ -11,18 +11,17 @@ import semanticanalysis.SymbolTable;
public class CompIterNode implements Node {
protected CompForNode comp_for;
- // protected CompIfNode compIfNode;
public CompIterNode(Node comp_for) {
this.comp_for = (CompForNode) comp_for;
}
@Override
- public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting, FunctionType ft) {
ArrayList<SemanticError> errors = new ArrayList<>();
if (comp_for != null) {
- errors.addAll(comp_for.checkSemantics(ST, _nesting));
+ errors.addAll(comp_for.checkSemantics(ST, _nesting, ft));
}
return errors;
}
@@ -32,7 +31,9 @@ public class CompIterNode implements Node {
return new VoidType();
}
- // TODO: add code generation for arglist node
+ /**
+ * We do not want to provide the code generation for this stuff.
+ */
@Override
public String codeGeneration() {
return "";
diff --git a/src/ast/nodes/CompNode.java b/src/ast/nodes/CompOpNode.java
index b6e0191..7997052 100644
--- a/src/ast/nodes/CompNode.java
+++ b/src/ast/nodes/CompOpNode.java
@@ -10,16 +10,20 @@ import org.antlr.v4.runtime.tree.TerminalNode;
/**
* Node for the `comp_op` statement of the grammar.
*/
-public class CompNode implements Node {
+public class CompOpNode implements Node {
private final TerminalNode op;
- public CompNode(TerminalNode op) {
+ public CompOpNode(TerminalNode op) {
this.op = op;
}
+ public String getOp() {
+ return op.toString();
+ }
+
@Override
- public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting, FunctionType ft) {
return new ArrayList<>();
}
@@ -29,7 +33,9 @@ public class CompNode implements Node {
return new VoidType();
}
- // TODO: add code generation for CompNode
+ /**
+ * The code generation for this operation is in `ExprNode`.
+ */
@Override
public String codeGeneration() {
return "";
@@ -37,6 +43,6 @@ public class CompNode implements Node {
@Override
public String toPrint(String prefix) {
- return prefix + "CompNode(" + op + ")\n";
+ return prefix + "CompOpNode(" + op + ")\n";
}
}
diff --git a/src/ast/nodes/CompoundNode.java b/src/ast/nodes/CompoundNode.java
index 2655f35..f0f63f2 100644
--- a/src/ast/nodes/CompoundNode.java
+++ b/src/ast/nodes/CompoundNode.java
@@ -23,23 +23,23 @@ public class CompoundNode 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<>();
if (ifNode != null) {
- errors.addAll(ifNode.checkSemantics(ST, _nesting));
+ errors.addAll(ifNode.checkSemantics(ST, _nesting, ft));
}
if (funcDef != null) {
- errors.addAll(funcDef.checkSemantics(ST, _nesting));
+ errors.addAll(funcDef.checkSemantics(ST, _nesting, ft));
}
if (forStmt != null) {
- errors.addAll(forStmt.checkSemantics(ST, _nesting));
+ errors.addAll(forStmt.checkSemantics(ST, _nesting, ft));
}
if (whileStmt != null) {
- errors.addAll(whileStmt.checkSemantics(ST, _nesting));
+ errors.addAll(whileStmt.checkSemantics(ST, _nesting, ft));
}
return errors;
@@ -50,10 +50,25 @@ public class CompoundNode implements Node {
return new VoidType();
}
- // TODO: add code generation for CompoundNode
@Override
public String codeGeneration() {
- return "";
+ if (ifNode != null) {
+ return ifNode.codeGeneration();
+ }
+
+ if (funcDef != null) {
+ return funcDef.codeGeneration();
+ }
+
+ if (forStmt != null) {
+ return forStmt.codeGeneration();
+ }
+
+ if (whileStmt != null) {
+ return whileStmt.codeGeneration();
+ }
+
+ return "Error: everything is null in Compound node\n";
}
@Override
diff --git a/src/ast/nodes/DottedNameNode.java b/src/ast/nodes/DottedNameNode.java
index 2698b1c..827945a 100644
--- a/src/ast/nodes/DottedNameNode.java
+++ b/src/ast/nodes/DottedNameNode.java
@@ -19,7 +19,7 @@ public class DottedNameNode 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<>();
for (int i = 0; i < names.size(); ++i) {
@@ -34,8 +34,10 @@ public class DottedNameNode implements Node {
return new ImportType();
}
- // NOTE: we do not provide code generation for this node in the same way
- // we do not want to do this for the import stm.
+ /**
+ * We do not provide code generation for this node in the same way
+ * we do not want to do this for the import stm.
+ */
@Override
public String codeGeneration() {
return "";
diff --git a/src/ast/nodes/ExprListNode.java b/src/ast/nodes/ExprListNode.java
index 4760db8..a3ac237 100644
--- a/src/ast/nodes/ExprListNode.java
+++ b/src/ast/nodes/ExprListNode.java
@@ -17,11 +17,11 @@ public class ExprListNode 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<>();
for (var expr : exprs) {
- errors.addAll(expr.checkSemantics(ST, _nesting));
+ errors.addAll(expr.checkSemantics(ST, _nesting, ft));
}
return errors;
@@ -47,10 +47,15 @@ public class ExprListNode implements Node {
return new VoidType();
}
- // TODO: code generation for expr list
@Override
public String codeGeneration() {
- return "";
+ String str = "";
+
+ for (var exp : exprs) {
+ str += exp.codeGeneration();
+ }
+
+ return str;
}
@Override
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";
+ }
+
}
diff --git a/src/ast/nodes/ForStmtNode.java b/src/ast/nodes/ForStmtNode.java
index 50574f0..507d314 100644
--- a/src/ast/nodes/ForStmtNode.java
+++ b/src/ast/nodes/ForStmtNode.java
@@ -33,7 +33,7 @@ public class ForStmtNode implements Node {
* an atom.
*/
@Override
- public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting, FunctionType ft) {
ArrayList<SemanticError> errors = new ArrayList<>();
// Save every atom in the expression's list, except the last one
@@ -52,8 +52,8 @@ public class ForStmtNode implements Node {
// ENHANCE: check that the comp_op is the `in` keyword
ST.insert(atomLeft.getId(), atomLeft.typeCheck(), _nesting, "");
- errors.addAll(exprList.checkSemantics(ST, _nesting));
- errors.addAll(block.checkSemantics(ST, _nesting));
+ errors.addAll(exprList.checkSemantics(ST, _nesting, ft));
+ errors.addAll(block.checkSemantics(ST, _nesting, ft));
return errors;
}
@@ -63,7 +63,10 @@ public class ForStmtNode implements Node {
return new VoidType();
}
- // TODO: add code generation for while
+ /**
+ * We do not provide the cgen for the `for_stm` because we do not have the
+ * iterators idea that the real Python has.
+ */
@Override
public String codeGeneration() {
return "";
diff --git a/src/ast/nodes/FuncdefNode.java b/src/ast/nodes/FuncdefNode.java
index 91231cc..c2671b2 100644
--- a/src/ast/nodes/FuncdefNode.java
+++ b/src/ast/nodes/FuncdefNode.java
@@ -8,6 +8,7 @@ import semanticanalysis.SemanticError;
import semanticanalysis.SymbolTable;
import ast.types.*;
import org.antlr.v4.runtime.tree.TerminalNode;
+import codegen.Label;
/**
* Node for the `funcdef` statement of the grammar.
@@ -17,38 +18,45 @@ public class FuncdefNode implements Node {
private final TerminalNode name;
private final Node paramlist;
private final Node block;
+ private final String funLabel;
public FuncdefNode(TerminalNode name, Node paramlist, Node block) {
this.name = name;
this.paramlist = paramlist;
this.block = block;
+ this.funLabel = Label.newFun("FUN");
}
@Override
- public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting, FunctionType ft) {
ArrayList<SemanticError> errors = new ArrayList<>();
- int paramNumber = ((ParamlistNode) paramlist).getParamNumber();
+ int paramNumber = 0;
+ if (paramlist != null) {
+ paramNumber = ((ParamlistNode) paramlist).getParamNumber();
+ }
Type returnType = this.block.typeCheck();
- FunctionType ft = new FunctionType(paramNumber, returnType);
+ FunctionType newFt = new FunctionType(paramNumber, returnType, funLabel);
- ST.insert(this.name.toString(), ft, _nesting, "");
+ String funName = this.name.toString();
+ ST.insert(funName, newFt, _nesting, "");
HashMap<String, STentry> HM = new HashMap<>();
ST.add(HM);
- ST.insert(this.name.toString(), ft, _nesting + 1, "");
+ ST.insert(funName, newFt, _nesting + 1, "");
+ ST.decreaseOffset();
if (paramlist != null) {
- errors.addAll(paramlist.checkSemantics(ST, _nesting + 1));
+ errors.addAll(paramlist.checkSemantics(ST, _nesting + 1, newFt));
}
- // TODO: think to the fucking offset
// Offset is increased for the possible return value
- ST.increaseoffset();
+ ST.increaseOffset();
- errors.addAll(block.checkSemantics(ST, _nesting + 1));
+ errors.addAll(block.checkSemantics(ST, _nesting + 1, newFt));
+ // return to the outer block
ST.remove();
return errors;
@@ -60,9 +68,18 @@ public class FuncdefNode implements Node {
return new VoidType();
}
- // TODO: code generation for funcdef
+ /**
+ * Taken from slide 56 of CodeGeneration.pdf
+ */
@Override
public String codeGeneration() {
+ String blockS = block.codeGeneration();
+ // The "return" which fix the RA is inside the block
+ String funS = funLabel + ":\n" +
+ "pushr RA\n" +
+ blockS;
+
+ Label.addFunDef(funS);
return "";
}
diff --git a/src/ast/nodes/IfNode.java b/src/ast/nodes/IfNode.java
index 223dffb..ca42b7a 100644
--- a/src/ast/nodes/IfNode.java
+++ b/src/ast/nodes/IfNode.java
@@ -4,6 +4,7 @@ import ast.types.*;
import java.util.ArrayList;
import semanticanalysis.SemanticError;
import semanticanalysis.SymbolTable;
+import codegen.Label;
/**
* Node for the `if` statement of the grammar.
@@ -11,23 +12,23 @@ import semanticanalysis.SymbolTable;
public class IfNode implements Node {
private final Node guard;
- private final Node thenbranch;
- private final Node elsebranch;
+ private final Node thenBranch;
+ private final Node elseBranch;
- public IfNode(Node guard, Node thenbranch, Node elsebranch) {
+ public IfNode(Node guard, Node thenBranch, Node elseBranch) {
this.guard = guard;
- this.thenbranch = thenbranch;
- this.elsebranch = elsebranch;
+ this.thenBranch = thenBranch;
+ this.elseBranch = elseBranch;
}
@Override
- public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting, FunctionType ft) {
ArrayList<SemanticError> errors = new ArrayList<>();
- errors.addAll(guard.checkSemantics(ST, _nesting));
- errors.addAll(thenbranch.checkSemantics(ST, _nesting));
- if (elsebranch != null) {
- errors.addAll(elsebranch.checkSemantics(ST, _nesting));
+ errors.addAll(guard.checkSemantics(ST, _nesting, ft));
+ errors.addAll(thenBranch.checkSemantics(ST, _nesting, ft));
+ if (elseBranch != null) {
+ errors.addAll(elseBranch.checkSemantics(ST, _nesting, ft));
}
return errors;
@@ -37,11 +38,11 @@ public class IfNode implements Node {
@Override
public Type typeCheck() {
if (guard.typeCheck() instanceof BoolType) {
- Type thenexp = thenbranch.typeCheck();
- Type elseexp = elsebranch.typeCheck();
+ Type thenexp = thenBranch.typeCheck();
+ Type elseexp = elseBranch.typeCheck();
if (thenexp.getClass().equals(elseexp.getClass())) {
- return thenexp;
- }else {
+ return thenexp;
+ } else {
System.out.println("Type Error: incompatible types in then and else branches.");
return new ErrorType();
}
@@ -51,18 +52,37 @@ public class IfNode implements Node {
}
}
- // TODO: add code generation for if
@Override
public String codeGeneration() {
- return "";
+ String thenLabel = Label.newBasic("then");
+ String endLabel = Label.newBasic("end");
+
+ String guardS = guard.codeGeneration();
+ String thenS = thenBranch.codeGeneration();
+ String elseS = "";
+ if (elseBranch != null) {
+ elseS = elseBranch.codeGeneration();
+ }
+
+ // We're assuming that the guard is boolean or an operation which puts a
+ // true (1) or false (0) into A0.
+ return guardS +
+ "storei T1 1\n" +
+ // Check if A0 = true
+ "beq A0 T1 " + thenLabel + "\n" +
+ elseS +
+ "b " + endLabel + "\n" +
+ thenLabel + ":\n" +
+ thenS +
+ endLabel + ":\n";
}
@Override
public String toPrint(String prefix) {
- String str = prefix + "If\n" + guard.toPrint(prefix + " ") + thenbranch.toPrint(prefix + " ");
+ String str = prefix + "If\n" + guard.toPrint(prefix + " ") + thenBranch.toPrint(prefix + " ");
- if (elsebranch != null) {
- str += elsebranch.toPrint(prefix + " ");
+ if (elseBranch != null) {
+ str += elseBranch.toPrint(prefix + " ");
}
return str;
diff --git a/src/ast/nodes/ImportNode.java b/src/ast/nodes/ImportNode.java
index f26c0d0..97e3404 100644
--- a/src/ast/nodes/ImportNode.java
+++ b/src/ast/nodes/ImportNode.java
@@ -26,7 +26,7 @@ public class ImportNode 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<>();
if (isFrom) {
@@ -34,7 +34,7 @@ public class ImportNode implements Node {
ST.insert(names.get(i), this.typeCheck(), _nesting, null);
}
} else {
- errors.addAll(dottedName.checkSemantics(ST, _nesting));
+ errors.addAll(dottedName.checkSemantics(ST, _nesting, ft));
}
if (importAs) {
@@ -49,7 +49,9 @@ public class ImportNode implements Node {
return new ImportType();
}
- // NOTE: we do not want to provide a code generation for this statement
+ /**
+ * NOTE: we do not want to provide a code generation for this statement
+ */
@Override
public String codeGeneration() {
return "";
diff --git a/src/ast/nodes/Node.java b/src/ast/nodes/Node.java
index 9fb58b8..0e58093 100644
--- a/src/ast/nodes/Node.java
+++ b/src/ast/nodes/Node.java
@@ -88,7 +88,7 @@ public interface Node {
* Checks semantics for a given node for a SymbolTable ST and a level of
* nesting. Returns a list of `SemanticError`.
*/
- ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting);
+ ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting, FunctionType ft);
/**
* Checks the type for a given node. If there's any error, returns an
diff --git a/src/ast/nodes/ParamdefNode.java b/src/ast/nodes/ParamdefNode.java
index e5694fa..4bba772 100644
--- a/src/ast/nodes/ParamdefNode.java
+++ b/src/ast/nodes/ParamdefNode.java
@@ -16,7 +16,7 @@ public class ParamdefNode extends AtomNode {
}
@Override
- public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting, FunctionType ft) {
ArrayList<SemanticError> errors = new ArrayList<>();
String paramName = this.getId();
diff --git a/src/ast/nodes/ParamlistNode.java b/src/ast/nodes/ParamlistNode.java
index e8c9a42..9e8d75c 100644
--- a/src/ast/nodes/ParamlistNode.java
+++ b/src/ast/nodes/ParamlistNode.java
@@ -12,16 +12,16 @@ public class ParamlistNode implements Node {
private final ArrayList<Node> params;
- public ParamlistNode(ArrayList<Node> _params) {
- params = _params;
+ public ParamlistNode(ArrayList<Node> params) {
+ this.params = params;
}
@Override
- public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting, FunctionType ft) {
ArrayList<SemanticError> errors = new ArrayList<>();
for (var param : params) {
- errors.addAll(param.checkSemantics(ST, _nesting));
+ errors.addAll(param.checkSemantics(ST, _nesting, ft));
}
return errors;
@@ -36,7 +36,6 @@ public class ParamlistNode implements Node {
return new VoidType();
}
- // TODO: code generation for param list
@Override
public String codeGeneration() {
return "";
diff --git a/src/ast/nodes/ReturnStmtNode.java b/src/ast/nodes/ReturnStmtNode.java
index bb49ded..15c8d69 100644
--- a/src/ast/nodes/ReturnStmtNode.java
+++ b/src/ast/nodes/ReturnStmtNode.java
@@ -1,7 +1,9 @@
package ast.nodes;
import ast.types.*;
+
import java.util.ArrayList;
+
import semanticanalysis.SemanticError;
import semanticanalysis.SymbolTable;
@@ -12,16 +14,23 @@ public class ReturnStmtNode implements Node {
private final Node exprList;
+ // VERY scatchy
+ private int localvar;
+ private int paramNumber;
+
public ReturnStmtNode(Node exprList) {
this.exprList = exprList;
}
@Override
- public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting, FunctionType ft) {
ArrayList<SemanticError> errors = new ArrayList<>();
+ // If I am in a "return", `ft` will be null.
+ this.localvar = ft.getLocalvarNum();
+ this.paramNumber = ft.getParamNumber();
if (this.exprList != null) {
- errors.addAll(this.exprList.checkSemantics(ST, _nesting));
+ errors.addAll(this.exprList.checkSemantics(ST, _nesting, ft));
}
return errors;
@@ -36,10 +45,21 @@ public class ReturnStmtNode implements Node {
return new VoidType();
}
- // TODO: add code generation for return stmt
@Override
public String codeGeneration() {
- return "";
+ String expS = exprList.codeGeneration();
+ for (int i = 0; i < localvar; i++) {
+ expS += "pop\n";
+ }
+ return expS +
+ "popr RA\n" +
+ "addi SP " + paramNumber + "\n" +
+ "pop\n" +
+ "store FP 0(FP)\n" +
+ "move FP AL\n" +
+ "subi AL 1\n" +
+ "pop\n" +
+ "rsub RA\n";
}
@Override
diff --git a/src/ast/nodes/RootNode.java b/src/ast/nodes/RootNode.java
index 26778f4..9cad871 100644
--- a/src/ast/nodes/RootNode.java
+++ b/src/ast/nodes/RootNode.java
@@ -1,6 +1,8 @@
package ast.nodes;
import ast.types.*;
+import codegen.Label;
+
import java.util.ArrayList;
import java.util.HashMap;
import semanticanalysis.*;
@@ -19,7 +21,7 @@ public class RootNode 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<>();
// Create a new HashMap for the current scope
@@ -30,7 +32,7 @@ public class RootNode implements Node {
// Check semantics for each child
for (Node child : childs) {
- errors.addAll(child.checkSemantics(ST, _nesting));
+ errors.addAll(child.checkSemantics(ST, _nesting, ft));
}
// Remove the HashMap from the SymbolTable
@@ -44,10 +46,16 @@ public class RootNode implements Node {
return new VoidType();
}
- // TODO: Code generation for RootNode
@Override
public String codeGeneration() {
- return "";
+ // Workaround per SP = MEM - 1
+ String str = "pushr FP\npushr AL\n";
+
+ for (Node child : childs) {
+ str += child.codeGeneration();
+ }
+
+ return str + "halt\n" + Label.getFunDef();
}
@Override
diff --git a/src/ast/nodes/SimpleStmtNode.java b/src/ast/nodes/SimpleStmtNode.java
index fbeeb1b..31a935f 100644
--- a/src/ast/nodes/SimpleStmtNode.java
+++ b/src/ast/nodes/SimpleStmtNode.java
@@ -23,23 +23,23 @@ public class SimpleStmtNode 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<>();
if (assignment != null) {
- errors.addAll(assignment.checkSemantics(ST, _nesting));
+ errors.addAll(assignment.checkSemantics(ST, _nesting, ft));
}
if (expr != null) {
- errors.addAll(expr.checkSemantics(ST, _nesting));
+ errors.addAll(expr.checkSemantics(ST, _nesting, ft));
}
if (returnStmt != null) {
- errors.addAll(returnStmt.checkSemantics(ST, _nesting));
+ errors.addAll(returnStmt.checkSemantics(ST, _nesting, ft));
}
if (importStmt != null) {
- errors.addAll(importStmt.checkSemantics(ST, _nesting));
+ errors.addAll(importStmt.checkSemantics(ST, _nesting, ft));
}
return errors;
@@ -50,10 +50,26 @@ public class SimpleStmtNode implements Node {
return new VoidType();
}
- // TODO: add code generation for SimpleStmtNode
@Override
public String codeGeneration() {
- return "";
+ if (assignment != null) {
+ return assignment.codeGeneration();
+ }
+
+ if (expr != null) {
+ return expr.codeGeneration();
+ }
+
+ if (returnStmt != null) {
+ return returnStmt.codeGeneration();
+ }
+
+ // Not supported
+ // if (importStmt != null) {
+ // return importStmt.codeGeneration();
+ // }
+
+ return "Error: everything is null in Compound node";
}
@Override
diff --git a/src/ast/nodes/SimpleStmtsNode.java b/src/ast/nodes/SimpleStmtsNode.java
index 5377c5d..8e5c924 100644
--- a/src/ast/nodes/SimpleStmtsNode.java
+++ b/src/ast/nodes/SimpleStmtsNode.java
@@ -17,11 +17,11 @@ public class SimpleStmtsNode 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<>();
for (Node stmt : stmts) {
- errors.addAll(stmt.checkSemantics(ST, _nesting));
+ errors.addAll(stmt.checkSemantics(ST, _nesting, ft));
}
return errors;
@@ -32,10 +32,15 @@ public class SimpleStmtsNode implements Node {
return new VoidType();
}
- // TODO: Code generation for SimpleStmtsNode
@Override
public String codeGeneration() {
- return "";
+ String str = "";
+
+ for (Node stmt : stmts) {
+ str += stmt.codeGeneration();
+ }
+
+ return str;
}
@Override
diff --git a/src/ast/nodes/TestlistCompNode.java b/src/ast/nodes/TestlistCompNode.java
index 32049f5..e55f854 100644
--- a/src/ast/nodes/TestlistCompNode.java
+++ b/src/ast/nodes/TestlistCompNode.java
@@ -19,22 +19,23 @@ public class TestlistCompNode 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<>();
if (comp != null) {
- // if comp is set, then we save the atom in the ST (we assume the first expr is
- // an atom)
+ // If comp is set, then we save the atom in the ST (we assume the first expr is
+ // an atom). We ignore the `comp.checkSemantics()`.
String id = ((ExprNode) exprs.get(0)).getId();
Type t = ((ExprNode) exprs.get(0)).typeCheck();
ST.insert(id, t, _nesting, "");
- // errors.addAll(comp.checkSemantics(ST, _nesting));
} else {
- // if comp is not set, then exprs is a list of 1 or more element
+ // If comp is not set, then exprs is a list of 1 or more element
for (var param : exprs) {
var exp = (ExprNode) param;
- ST.insert(exp.getId(), exp.typeCheck(), _nesting, "");
- errors.addAll(param.checkSemantics(ST, _nesting));
+ if (exp.getId() != null && !exp.isFunctionCall()) {
+ ST.insert(exp.getId(), exp.typeCheck(), _nesting, "");
+ }
+ errors.addAll(param.checkSemantics(ST, _nesting, ft));
}
}
@@ -61,10 +62,13 @@ public class TestlistCompNode implements Node {
return new VoidType();
}
- // TODO: code generation for expr list
@Override
public String codeGeneration() {
- return "";
+ String str = "";
+ for (var param : exprs) {
+ str += param.codeGeneration();
+ }
+ return str;
}
@Override
diff --git a/src/ast/nodes/TrailerNode.java b/src/ast/nodes/TrailerNode.java
index d8301b8..d70e962 100644
--- a/src/ast/nodes/TrailerNode.java
+++ b/src/ast/nodes/TrailerNode.java
@@ -28,15 +28,15 @@ public class TrailerNode 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<>();
if (arglist != null) {
- errors.addAll(arglist.checkSemantics(ST, _nesting));
+ errors.addAll(arglist.checkSemantics(ST, _nesting, ft));
}
for (var expr : exprs) {
- errors.addAll(expr.checkSemantics(ST, _nesting));
+ errors.addAll(expr.checkSemantics(ST, _nesting, ft));
}
return errors;
@@ -59,9 +59,11 @@ public class TrailerNode implements Node {
return new VoidType();
}
- // TODO: add code generation for trailer node
@Override
public String codeGeneration() {
+ if (arglist != null) {
+ return arglist.codeGeneration();
+ }
return "";
}
diff --git a/src/ast/nodes/WhileStmtNode.java b/src/ast/nodes/WhileStmtNode.java
index 352cbc0..d371046 100644
--- a/src/ast/nodes/WhileStmtNode.java
+++ b/src/ast/nodes/WhileStmtNode.java
@@ -19,11 +19,11 @@ public class WhileStmtNode 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<>();
- errors.addAll(expr.checkSemantics(ST, _nesting));
- errors.addAll(block.checkSemantics(ST, _nesting));
+ errors.addAll(expr.checkSemantics(ST, _nesting, ft));
+ errors.addAll(block.checkSemantics(ST, _nesting, ft));
return errors;
}
@@ -33,7 +33,7 @@ public class WhileStmtNode implements Node {
return new VoidType();
}
- // TODO: add code generation for while
+ // TODO: add cgen per while (but it's not requested from the exercise)
@Override
public String codeGeneration() {
return "";
diff --git a/src/ast/types/FunctionType.java b/src/ast/types/FunctionType.java
index 5e6adaa..1a04bb6 100644
--- a/src/ast/types/FunctionType.java
+++ b/src/ast/types/FunctionType.java
@@ -7,13 +7,25 @@ public class FunctionType extends Type {
private final int paramNumber;
private final Type returnType;
+ private final String label;
+ private int localvarNum;
- public FunctionType(int paramNumber, Type returnType) {
+ public FunctionType(int paramNumber, Type returnType, String label) {
this.paramNumber = paramNumber;
this.returnType = returnType;
+ this.label = label;
+ this.localvarNum = 0;
}
- // Return the length of the parameters
+ public void addLocalVar() {
+ localvarNum++;
+ }
+
+ public int getLocalvarNum() {
+ return localvarNum;
+ }
+
+ // Return the number of the parameters
public int getParamNumber() {
return paramNumber;
}
@@ -22,8 +34,17 @@ public class FunctionType extends Type {
return returnType;
}
+ public String getLabel() {
+ return label;
+ }
+
@Override
public String toPrint(String prefix) {
return prefix + "Function\n";
}
+
+ @Override
+ public String toString() {
+ return "NP: " + paramNumber + " RT: " + returnType + " L: " + label;
+ }
}
diff --git a/src/ast/types/Type.java b/src/ast/types/Type.java
index 6190106..c5b8312 100644
--- a/src/ast/types/Type.java
+++ b/src/ast/types/Type.java
@@ -20,7 +20,7 @@ public class Type implements Node {
}
@Override
- public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting, FunctionType ft) {
// It is never invoked
return null;
}