summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSanto Cariotti <santo@dcariotti.me>2024-06-13 11:00:06 +0200
committerGitHub <noreply@github.com>2024-06-13 11:00:06 +0200
commit8e7089a5d6ba1f4f50a90133bb50bc5c6c554aff (patch)
treed4a627e56a199720f7d811af5756402e76628864
parent1c8761901b26c0be4d61f3aed5ec0495a558a0e7 (diff)
Set up visitor (#3)
Co-authored-by: geno <gabriele.genovese2@studio.unibo.it>
-rw-r--r--Makefile7
-rw-r--r--README.md3
-rw-r--r--progs/test.py11
-rw-r--r--progs/test2.py3
-rw-r--r--src/Main.java87
-rw-r--r--src/ast/Python3VisitorImpl.java530
-rw-r--r--src/ast/nodes/ArglistNode.java53
-rw-r--r--src/ast/nodes/AssignmentNode.java52
-rw-r--r--src/ast/nodes/AtomNode.java45
-rw-r--r--src/ast/nodes/AugassignNode.java42
-rw-r--r--src/ast/nodes/BlockNode.java38
-rw-r--r--src/ast/nodes/CompNode.java41
-rw-r--r--src/ast/nodes/CompoundNode.java84
-rw-r--r--src/ast/nodes/DottedNameNode.java51
-rw-r--r--src/ast/nodes/ExprNode.java90
-rw-r--r--src/ast/nodes/ForStmtNode.java47
-rw-r--r--src/ast/nodes/FuncdefNode.java63
-rw-r--r--src/ast/nodes/IfNode.java71
-rw-r--r--src/ast/nodes/ImportNode.java76
-rw-r--r--src/ast/nodes/Node.java36
-rw-r--r--src/ast/nodes/ParamdefNode.java29
-rw-r--r--src/ast/nodes/ParamlistNode.java53
-rw-r--r--src/ast/nodes/ReturnStmtNode.java57
-rw-r--r--src/ast/nodes/RootNode.java64
-rw-r--r--src/ast/nodes/SimpleStmtNode.java84
-rw-r--r--src/ast/nodes/SimpleStmtsNode.java54
-rw-r--r--src/ast/nodes/TrailerNode.java78
-rw-r--r--src/ast/nodes/WhileStmtNode.java46
-rw-r--r--src/ast/types/AtomType.java11
-rw-r--r--src/ast/types/BoolType.java10
-rw-r--r--src/ast/types/ErrorType.java10
-rw-r--r--src/ast/types/IntType.java10
-rw-r--r--src/ast/types/Type.java41
-rw-r--r--src/ast/types/VoidType.java10
-rw-r--r--src/parser/Python3Lexer.java8
-rw-r--r--src/parser/Python3Parser.java2
-rw-r--r--src/parser/Python3ParserBaseListener.java2
-rw-r--r--src/parser/Python3ParserBaseVisitor.java2
-rw-r--r--src/parser/Python3ParserListener.java2
-rw-r--r--src/parser/Python3ParserVisitor.java2
-rw-r--r--src/semanticanalysis/STentry.java55
-rw-r--r--src/semanticanalysis/SemanticError.java16
-rw-r--r--src/semanticanalysis/SymbolTable.java153
43 files changed, 2188 insertions, 41 deletions
diff --git a/Makefile b/Makefile
index d080098..d04c40e 100644
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,7 @@ PARSER_DIR = src/parser
BIN_DIR = out
MAIN_CLASS = com.clp.project.Main
PARSEALL_CLASS = com.clp.project.ParseAll
-SOURCES = $(wildcard $(SRC_DIR)/*.java)
+SOURCES = $(wildcard $(SRC_DIR)/*.java $(SRC_DIR)/*/*.java $(SRC_DIR)/*/*/*.java)
GRAMMARS = $(PARSER_DIR)/Python3Lexer.g4 $(PARSER_DIR)/Python3Parser.g4
ANTLR_OUTPUT = $(PARSER_DIR)/*.java
DATE = $(shell date +%Y%m%d-%H%M%S)
@@ -18,6 +18,9 @@ all: $(SOURCES) $(ANTLR_OUTPUT)
$(ANTLR_OUTPUT): $(GRAMMARS)
java -jar lib/antlr-4.13.1-complete.jar $^
+build:
+ $(JAVAC) $(JAVAC_FLAGS) $(SOURCES)
+
run:
java -cp $(ANTLR_COMPLETE):$(BIN_DIR) $(MAIN_CLASS) $(ARGS)
@@ -30,4 +33,4 @@ clean:
release: clean
zip -r ../python3-miniparser-$(DATE).zip .
-.PHONY: all run clean release runall
+.PHONY: all build run clean release runall
diff --git a/README.md b/README.md
index 3c7e80b..d8b2780 100644
--- a/README.md
+++ b/README.md
@@ -6,5 +6,8 @@ Project for the AA 2023/2024 **Complementi di programmazione**'s course of the M
```shell
make
+make run
make runall
```
+
+For archlinux users, add the following env variable to visualize the window: `export _JAVA_AWT_WM_NONREPARENTING=1`
diff --git a/progs/test.py b/progs/test.py
index f168c9b..718885d 100644
--- a/progs/test.py
+++ b/progs/test.py
@@ -1,12 +1,17 @@
-def find_first_duplicate(nums):
+import math
+from re import f4, r3
+
+from abs import *
+
+
+def find_first_duplicate(nums, x):
num_set = set()
no_duplicate = -1
for i in range(len(nums)):
-
if nums[i] in num_set:
return nums[i]
else:
num_set.add(nums[i])
- return no_duplicate \ No newline at end of file
+ return no_duplicate
diff --git a/progs/test2.py b/progs/test2.py
new file mode 100644
index 0000000..c62d44a
--- /dev/null
+++ b/progs/test2.py
@@ -0,0 +1,3 @@
+x = 1
+if y == 1:
+ print("a")
diff --git a/src/Main.java b/src/Main.java
index e773b07..c672e19 100644
--- a/src/Main.java
+++ b/src/Main.java
@@ -4,6 +4,7 @@ import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;
import javax.swing.*;
@@ -11,41 +12,71 @@ import org.antlr.v4.gui.TreeViewer;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.*;
+import com.clp.project.ast.*;
+import com.clp.project.ast.nodes.*;
import com.clp.project.parser.*;
+import com.clp.project.semanticanalysis.*;
public class Main {
- public static void main(String[] args) {
- for (File file : Objects.requireNonNull(new File("./progs/").listFiles())) {
- try {
- String fileStr = file.getPath();
- // FIXME: use the fileStr above
- fileStr = "./progs/test.py";
- System.out.println(fileStr);
- System.out.println(readFile(fileStr));
+ public static void main(String[] args) {
- CharStream cs = CharStreams.fromFileName(fileStr);
- Python3Lexer lexer = new Python3Lexer(cs);
- CommonTokenStream tokenStream = new CommonTokenStream(lexer);
- Python3Parser parser = new Python3Parser(tokenStream);
- Python3Parser.RootContext tree = parser.root();
- // String treeStr = tree.toString();
- // System.out.println(treeStr);
- // Visualize the parse tree
- JFrame frame = new JFrame("Parse Tree");
- JPanel panel = new JPanel();
- TreeViewer viewer = new TreeViewer(Arrays.asList(parser.getRuleNames()), tree);
- viewer.setScale(1.5); // Zoom factor
- panel.add(viewer);
- frame.add(panel);
- frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- frame.setSize(800, 600);
- frame.setVisible(true);
- break;
- } catch (Exception e) {
- e.printStackTrace();
+ // for (File file : Objects.requireNonNull(new File("./progs/").listFiles())) {
+ try {
+ // String fileStr = file.getPath();
+ // FIXME: use the fileStr above
+ String fileStr = "./progs/test.py";
+ System.out.println(fileStr);
+ System.out.println(readFile(fileStr));
+ CharStream cs = CharStreams.fromFileName(fileStr);
+ Python3Lexer lexer = new Python3Lexer(cs);
+ CommonTokenStream tokens = new CommonTokenStream(lexer);
+ Python3Parser parser = new Python3Parser(tokens);
+ Python3Parser.RootContext tree = parser.root();
+ // DEBUG
+ // {
+ // tokens.fill();
+ // for (Token token : tokens.getTokens()) {
+ // System.out.println(token.toString());
+ // }
+ //
+ // System.out.println("Tree: " + tree);
+ // }
+ JFrame frame = new JFrame("Parse Tree");
+ JPanel panel = new JPanel();
+ TreeViewer viewer = new TreeViewer(Arrays.asList(parser.getRuleNames()),
+ tree);
+ viewer.setScale(1.5); // Zoom factor
+ panel.add(viewer);
+ frame.add(panel);
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ frame.setSize(800, 600);
+ frame.setVisible(true);
+ if (tree == null) {
+ System.err.println("The tree is null.");
+ return;
+ }
+ if (parser.getNumberOfSyntaxErrors() > 0) {
+ System.err.println("Error on program parsing.");
+ return;
+ }
+ Python3VisitorImpl visitor = new Python3VisitorImpl();
+ SymbolTable ST = new SymbolTable();
+ Node ast = visitor.visit(tree);
+ ArrayList<SemanticError> errors = ast.checkSemantics(ST, 0);
+ if (errors.size() > 0) {
+ System.out.println("You had: " + errors.size() + " errors:");
+ for (SemanticError e : errors) {
+ System.out.println("\t" + e);
+ }
+ } else {
+ System.out.println("Visualizing AST...");
+ System.out.println(ast.toPrint(""));
}
+ } catch (Exception e) {
+ e.printStackTrace();
}
+ // }
}
private static String readFile(String filePath) throws IOException {
diff --git a/src/ast/Python3VisitorImpl.java b/src/ast/Python3VisitorImpl.java
new file mode 100644
index 0000000..0783409
--- /dev/null
+++ b/src/ast/Python3VisitorImpl.java
@@ -0,0 +1,530 @@
+package com.clp.project.ast;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.clp.project.ast.*;
+import com.clp.project.ast.nodes.*;
+import com.clp.project.ast.types.*;
+import com.clp.project.parser.Python3ParserBaseVisitor;
+import com.clp.project.parser.Python3Parser.*;
+import org.antlr.v4.runtime.tree.TerminalNode;
+
+/**
+ * Implementation for the `Python3ParserBaseVisitor` class for the `Node` type.
+ * Overrides each `visitNODE` method from the base class.
+ */
+public class Python3VisitorImpl extends Python3ParserBaseVisitor<Node> {
+ /**
+ * Since a root can be a simple_stmts or a compound_stmt, this method
+ * returns a new `RootNode` with a list of them.
+ *
+ * ```
+ * root : NEWLINE* (simple_stmts | compound_stmt)* EOF;
+ * ```
+ */
+ public Node visitRoot(RootContext ctx) {
+ ArrayList<Node> stmts = new ArrayList<Node>();
+ ArrayList<Node> compStmts = new ArrayList<Node>();
+
+ for (Simple_stmtsContext stm : ctx.simple_stmts()) {
+ stmts.add(visit(stm));
+ }
+ for (Compound_stmtContext stm : ctx.compound_stmt()) {
+ compStmts.add(visit(stm));
+ }
+
+ return new RootNode(stmts, compStmts);
+ }
+
+ /**
+ * Returns a `SimpleStmtsNode`, made by an array of SimpleStmtNode
+ *
+ * ```
+ * simple_stmts : simple_stmt (';' simple_stmt)* ';'? NEWLINE ;
+ * ```
+ */
+ public Node visitSimple_stmts(Simple_stmtsContext ctx) {
+ ArrayList<Node> stmts = new ArrayList<Node>();
+
+ for (Simple_stmtContext stm : ctx.simple_stmt()) {
+ stmts.add(visit(stm));
+ }
+
+ return new SimpleStmtsNode(stmts);
+ }
+
+ /**
+ * Returns a `CompoundNode`. It can be built by a different kind of
+ * statements, so only one of theme won't be null.
+ *
+ * ```
+ * compound_stmt : if_stmt | while_stmt | for_stmt | funcdef ;
+ * ```
+ */
+ public Node visitCompound_stmt(Compound_stmtContext ctx) {
+ Node ifStmt = null;
+ Node funcDef = null;
+ Node forStmt = null;
+ Node whileStmt = null;
+
+ if (ctx.if_stmt() != null) {
+ ifStmt = visit(ctx.if_stmt());
+ }
+
+ if (ctx.funcdef() != null) {
+ funcDef = visit(ctx.funcdef());
+ }
+
+ if (ctx.for_stmt() != null) {
+ forStmt = visit(ctx.for_stmt());
+ }
+
+ if (ctx.while_stmt() != null) {
+ whileStmt = visit(ctx.while_stmt());
+ }
+
+ return new CompoundNode(ifStmt, funcDef, forStmt, whileStmt);
+ }
+
+ /**
+ * Returns a `SimpleStmtNode`. It can be built by a different kind of
+ * statements, so only one of theme won't be null.
+ *
+ * ```
+ * simple_stmt : assignment | expr | return_stmt | import_stm ;
+ * ```
+ */
+ public Node visitSimple_stmt(Simple_stmtContext ctx) {
+ Node assignment = null;
+ Node expr = null;
+ Node returnStmt = null;
+ Node importStmt = null;
+
+ if (ctx.assignment() != null) {
+ assignment = visit(ctx.assignment());
+ }
+
+ if (ctx.expr() != null) {
+ expr = visit(ctx.expr());
+ }
+
+ if (ctx.return_stmt() != null) {
+ returnStmt = visit(ctx.return_stmt());
+ }
+
+ if (ctx.import_stm() != null) {
+ importStmt = visit(ctx.import_stm());
+ }
+
+ return new SimpleStmtNode(assignment, expr, returnStmt, importStmt);
+ }
+
+ /**
+ * Returns an `AssignmentNode`. It's made by left side, an assignment and a
+ * right side.
+ *
+ * ```
+ * assignment : exprlist augassign exprlist ;
+ * ```
+ */
+ public Node visitAssignment(AssignmentContext ctx) {
+ Node lhr = visit(ctx.exprlist(0));
+ Node assign = visit(ctx.augassign());
+ Node rhr = visit(ctx.exprlist(1));
+
+ return new AssignmentNode(lhr, assign, rhr);
+ }
+
+ /**
+ * Returns a `ReturnStmtNode`. The returned exprlist can be null.
+ *
+ * ```
+ * return_stmt : 'return' exprlist? ;
+ * ```
+ */
+ public Node visitReturn_stmt(Return_stmtContext ctx) {
+ Node exprList = null;
+ if (ctx.exprlist() != null) {
+ exprList = visit(ctx.exprlist());
+ }
+
+ return new ReturnStmtNode(exprList);
+ }
+
+ /**
+ * Returns a `ImportNode`. An import can be made in different ways so we
+ * check the way in a module is imported (by from, by alias or by star).
+ *
+ * ```
+ * import_stm : 'import' dotted_name ('as' NAME)?
+ * | 'from' dotted_name 'import' (NAME (',' NAME)* | '*') ;
+ * ```
+ */
+ public Node visitImport_stm(Import_stmContext ctx) {
+ boolean isFrom = ctx.FROM() != null;
+ boolean importAs = ctx.AS() != null;
+ boolean importAll = ctx.STAR() != null;
+
+ Node dottedName = visit(ctx.dotted_name());
+
+ ArrayList<String> names = new ArrayList<String>();
+
+ for (var s : ctx.NAME()) {
+ names.add(s.toString());
+ }
+
+ return new ImportNode(dottedName, isFrom, importAs, importAll, names);
+ }
+
+ /**
+ * Returns a `DottedNameNode` used in `import_stm`.
+ *
+ * ```
+ * dotted_name : NAME ('.' NAME)* ;
+ * ```
+ */
+ public Node visitDotted_name(Dotted_nameContext ctx) {
+ ArrayList<TerminalNode> names = new ArrayList<TerminalNode>();
+
+ for (var name : ctx.NAME()) {
+ names.add(name);
+ }
+
+ return new DottedNameNode(names);
+ }
+
+ /**
+ * Returns a `FuncdefNode`. A paramlist can be null.
+ *
+ * ```
+ * funcdef : 'def' NAME '(' paramlist? ')' ':' block ;
+ * ```
+ */
+ public Node visitFuncdef(FuncdefContext ctx) {
+ Node paramlist = null;
+
+ if (ctx.paramlist() != null) {
+ paramlist = visit(ctx.paramlist());
+ }
+
+ Node block = visit(ctx.block());
+
+ return new FuncdefNode(ctx.NAME(), paramlist, block);
+ }
+
+ /**
+ * Returns a `ParamlistNode`. We ignore the paramdef with default values
+ * (eg: is_used=False) because there is no test which uses this feature.
+ *
+ * ```
+ * paramlist : paramdef ('=' expr)? (',' paramdef ('=' expr)?)* ;
+ *
+ * ```
+ */
+ public Node visitParamlist(ParamlistContext ctx) {
+ ArrayList<Node> params = new ArrayList<Node>();
+
+ for (ParamdefContext s : ctx.paramdef()) {
+ params.add(visit(s));
+ }
+
+ return new ParamlistNode(params);
+ }
+
+ /**
+ * Returns a `ParamdefNode`. We ignore the paramdef with type annotation
+ * (eg: x : int) because there is no test which uses this feature.
+ *
+ * ```
+ * paramdef : NAME (':' expr)? ;
+ * ```
+ */
+ public Node visitParamdef(ParamdefContext ctx) {
+ return new ParamdefNode(ctx.NAME().toString());
+ }
+
+ /**
+ * Returns an `AugassignNode`. We don't provide all kinds of assignment
+ * below.
+ *
+ * ```
+ * augassign : '=' | '+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' |
+ * '^=' | '<<=' | '>>=' | '**=' | '//='
+ * ;
+ * ```
+ */
+ public Node visitAugassign(AugassignContext ctx) {
+ Node x = null;
+
+ if (ctx.ASSIGN() != null) {
+ x = new AugassignNode(ctx.ASSIGN());
+ } else if (ctx.ADD_ASSIGN() != null) {
+ x = new AugassignNode(ctx.ADD_ASSIGN());
+ } else if (ctx.SUB_ASSIGN() != null) {
+ x = new AugassignNode(ctx.SUB_ASSIGN());
+ } else if (ctx.MULT_ASSIGN() != null) {
+ x = new AugassignNode(ctx.MULT_ASSIGN());
+ } else if (ctx.DIV_ASSIGN() != null) {
+ x = new AugassignNode(ctx.DIV_ASSIGN());
+ }
+
+ return x;
+ }
+
+ /**
+ * Returns a `IfNode`.
+ * FIXME: add support for elif statement.
+ *
+ * ```
+ * if_stmt : 'if' expr ':' block ('elif' expr ':' block)* ('else' ':' block)? ;
+ * ```
+ */
+ public Node visitIf_stmt(If_stmtContext ctx) {
+ var blocks = ctx.block();
+ Node condExp = visit(ctx.expr(0));
+ Node thenExp = visit(blocks.get(0));
+ Node elseExp = null;
+ if (blocks.size() > 1) {
+ elseExp = visit(blocks.get(1));
+ }
+
+ return new IfNode(condExp, thenExp, elseExp);
+ }
+
+ /**
+ * Returns a `WhileStmtNode`. We do not provide 'else' branch.
+ *
+ * ```
+ * while_stmt : 'while' expr ':' block ('else' ':' block)? ;
+ * ```
+ */
+ public Node visitWhile_stmt(While_stmtContext ctx) {
+ Node expr = visit(ctx.expr());
+
+ // Block 1 is for the while-else statement
+ Node block = visit(ctx.block(0));
+
+ return new WhileStmtNode(expr, block);
+ }
+
+ /**
+ * Returns a `ForSmtNode`. We do not provide 'else' branch.
+ *
+ * ```
+ * for_stmt : 'for' exprlist ':' block ('else' ':' block)? ;
+ * ```
+ */
+ public Node visitFor_stmt(For_stmtContext ctx) {
+ Node exprList = visit(ctx.exprlist());
+
+ // Block 1 is for the for-else statement
+ Node block = visit(ctx.block(0));
+
+ return new ForStmtNode(exprList, block);
+ }
+
+ /**
+ * Returns a `BlockNode`. A block can be be a simple_stmts or a list of
+ * simple_stms and/or compound_stmt, so we just use a list for each kind.
+ *
+ * ```
+ * block : simple_stmts
+ * | NEWLINE INDENT (simple_stmts | compound_stmt)+ DEDENT ;
+ * ```
+ */
+ public Node visitBlock(BlockContext ctx) {
+ ArrayList<Node> stmts = new ArrayList<Node>();
+ ArrayList<Node> compStmts = new ArrayList<Node>();
+
+ for (Simple_stmtsContext s : ctx.simple_stmts()) {
+ stmts.add(visit(s));
+ }
+ for (Compound_stmtContext s : ctx.compound_stmt()) {
+ compStmts.add(visit(s));
+ }
+
+ return new BlockNode(stmts, compStmts);
+ }
+
+ /**
+ * Returns a `CompNode`. It should never be null.
+ *
+ * ```
+ * comp_op : '<' | '>' | '==' | '>=' | '<=' | '<>' | '!=' | 'in' | 'not' 'in' |
+ * 'is' | 'is' 'not' ;
+ * ```
+ */
+ public Node visitComp_op(Comp_opContext ctx) {
+ Node comp = null;
+ if (ctx.LESS_THAN() != null) {
+ comp = new CompNode(ctx.LESS_THAN());
+ } else if (ctx.GREATER_THAN() != null) {
+ comp = new CompNode(ctx.GREATER_THAN());
+ } else if (ctx.EQUALS() != null) {
+ comp = new CompNode(ctx.EQUALS());
+ } else if (ctx.GT_EQ() != null) {
+ comp = new CompNode(ctx.GT_EQ());
+ } else if (ctx.LT_EQ() != null) {
+ comp = new CompNode(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());
+ } else if (ctx.IN() != null) {
+ comp = new CompNode(ctx.IN());
+ } else if (ctx.NOT() != null) {
+ comp = new CompNode(ctx.NOT());
+ } else if (ctx.IS() != null) {
+ comp = new CompNode(ctx.IS());
+ }
+
+ return comp;
+ }
+
+ /**
+ * Returns an `ExprNode`. An expession can be a different kind of
+ * sub-expression. We do not provide all kinds of expr(s).
+ *
+ * ```
+ * expr : atom trailer* | expr '**' expr | ('+' | '-' | '~')+ expr | expr ('*' |
+ * '@' | '/' | '%' | '//') expr | expr ('+' | '-') expr | expr ('<<' | '>>')
+ * expr | expr '&' expr | expr '^' expr | expr '|' expr | 'not' expr | expr
+ * comp_op expr | expr 'and' expr | expr 'or' expr | expr 'if' expr 'else' expr
+ * ;
+ * ```
+ */
+ public Node visitExpr(ExprContext ctx) {
+ Node atom = null;
+ Node compOp = null;
+ ArrayList<Node> exprs = new ArrayList<Node>();
+ ArrayList<Node> trailers = new ArrayList<Node>();
+ String op = null;
+
+ if (ctx.ADD(0) != null) {
+ op = ctx.ADD(0).toString();
+ }
+
+ if (ctx.MINUS(0) != null) {
+ op = ctx.MINUS(0).toString();
+ }
+
+ if (ctx.NOT() != null) {
+ op = ctx.NOT().toString();
+ }
+
+ if (ctx.STAR() != null) {
+ op = ctx.STAR().toString();
+ }
+
+ if (ctx.DIV() != null) {
+ op = ctx.DIV().toString();
+ }
+
+ if (ctx.atom() != null) {
+ atom = visit(ctx.atom());
+ }
+
+ if (ctx.comp_op() != null) {
+ compOp = visit(ctx.comp_op());
+ }
+
+ for (ExprContext s : ctx.expr()) {
+ exprs.add(visit(s));
+ }
+
+ for (TrailerContext s : ctx.trailer()) {
+ trailers.add(visit(s));
+ }
+
+ return new ExprNode(atom, compOp, exprs, op, trailers);
+ }
+
+ /**
+ * Returns an `AtomNode`.
+ * FIXME: add support for testlist_comp
+ *
+ * ```
+ * atom : '(' testlist_comp? ')' | '[' testlist_comp? ']' | '{' testlist_comp?
+ * '}' | NAME | NUMBER | STRING+ | '...' | 'None' | 'True' | 'False' ;
+ * ```
+ */
+ public Node visitAtom(AtomContext ctx) {
+ if (ctx.NUMBER() != null) {
+ return new AtomNode(ctx.NUMBER().toString());
+ } else if (ctx.TRUE() != null) {
+ return new AtomNode(ctx.TRUE().toString());
+ } else if (ctx.FALSE() != null) {
+ return new AtomNode(ctx.FALSE().toString());
+ } else if (ctx.NAME() != null) {
+ return new AtomNode(ctx.NAME().toString());
+ } else if (ctx.STRING() != null) {
+
+ var varName = "";
+ for (var x : ctx.STRING()) {
+ varName += x;
+ }
+
+ return new AtomNode(varName);
+ }
+ return new AtomNode(ctx.NONE().toString());
+ }
+
+ /**
+ * Returns an `TrailerNode`.
+ *
+ * ```
+ * trailer : '(' arglist? ')' | '[' expr (',' expr)* ','? ']' | '.' NAME | '['
+ * expr? ':' expr? (':' expr? )? ']' ;
+ * ```
+ */
+ public Node visitTrailer(TrailerContext ctx) {
+ Node arglist = null;
+ if (ctx.arglist() != null) {
+ arglist = visit(ctx.arglist());
+ }
+
+ ArrayList<Node> exprs = new ArrayList<Node>();
+ for (ExprContext expr : ctx.expr()) {
+ exprs.add(visit(expr));
+ }
+
+ // A trailer could be `.methodName()`.
+ TerminalNode methodCall = null;
+ if (ctx.DOT() != null) {
+ methodCall = ctx.NAME();
+ }
+
+ return new TrailerNode(arglist, exprs, methodCall);
+ }
+
+ /**
+ * Returns a `Node`.
+ * FIXME: what to do in case of list??
+ *
+ * ```
+ * exprlist : expr (',' expr )* ','? ;
+ * ```
+ */
+ public Node visitExprlist(ExprlistContext ctx) {
+ Node exp = visit(ctx.expr(0));
+
+ return exp;
+ }
+
+ /**
+ * Returns a `ArglistNode`.
+ *
+ * ```
+ * arglist : argument (',' argument)* ','? ;
+ * ```
+ */
+ public Node visitArglist(ArglistContext ctx) {
+ ArrayList<Node> arguments = new ArrayList<Node>();
+
+ for (ArgumentContext c : ctx.argument()) {
+ arguments.add(visit(c));
+ }
+
+ return new ArglistNode(arguments);
+ }
+}
diff --git a/src/ast/nodes/ArglistNode.java b/src/ast/nodes/ArglistNode.java
new file mode 100644
index 0000000..8a5b4b9
--- /dev/null
+++ b/src/ast/nodes/ArglistNode.java
@@ -0,0 +1,53 @@
+package com.clp.project.ast.nodes;
+
+import java.util.ArrayList;
+
+import com.clp.project.semanticanalysis.SemanticError;
+import com.clp.project.semanticanalysis.SymbolTable;
+import com.clp.project.ast.types.*;
+
+/**
+ * Node for the `arglist` statement of the grammar.
+ */
+public class ArglistNode implements Node {
+ protected ArrayList<Node> arguments;
+
+ public ArglistNode(ArrayList<Node> arguments) {
+ this.arguments = arguments;
+ }
+
+ @Override
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ ArrayList<SemanticError> errors = new ArrayList<SemanticError>();
+
+ for (var arg : arguments) {
+ errors.addAll(arg.checkSemantics(ST, _nesting));
+ }
+
+ return errors;
+ }
+
+ @Override
+ public Type typeCheck() {
+ return new VoidType();
+ }
+
+ // TODO: add code generation for arglist node
+ @Override
+ public String codeGeneration() {
+ return "";
+ }
+
+ @Override
+ public String toPrint(String prefix) {
+ String str = prefix + "ArglistNode\n";
+
+ prefix += " ";
+ for (Node arg : arguments) {
+ str += arg.toPrint(prefix);
+ }
+
+ return str;
+ }
+
+}
diff --git a/src/ast/nodes/AssignmentNode.java b/src/ast/nodes/AssignmentNode.java
new file mode 100644
index 0000000..d722f41
--- /dev/null
+++ b/src/ast/nodes/AssignmentNode.java
@@ -0,0 +1,52 @@
+package com.clp.project.ast.nodes;
+
+import java.util.ArrayList;
+
+import com.clp.project.semanticanalysis.SemanticError;
+import com.clp.project.semanticanalysis.SymbolTable;
+import com.clp.project.ast.types.*;
+
+/**
+ * Node for the `assignment` statement of the grammar.
+ */
+public class AssignmentNode implements Node {
+ private Node lhr;
+ private Node assign;
+ private Node rhr;
+
+ public AssignmentNode(Node lhr, Node assign, Node rhr) {
+ this.lhr = lhr;
+ this.assign = assign;
+ this.rhr = rhr;
+ }
+
+ @Override
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ ArrayList<SemanticError> errors = new ArrayList<SemanticError>();
+
+ errors.addAll(lhr.checkSemantics(ST, _nesting));
+ errors.addAll(assign.checkSemantics(ST, _nesting));
+ errors.addAll(rhr.checkSemantics(ST, _nesting));
+
+ return errors;
+ }
+
+ // TODO: check it out for this type
+ @Override
+ public Type typeCheck() {
+ return rhr.typeCheck();
+ }
+
+ // TODO: add code generation for assignment
+ @Override
+ public String codeGeneration() {
+ return "";
+ }
+
+ @Override
+ public String toPrint(String prefix) {
+ return prefix + "Assignment\n" + lhr.toPrint(prefix + " ") + assign.toPrint(prefix + " ")
+ + rhr.toPrint(prefix + " ");
+ }
+
+}
diff --git a/src/ast/nodes/AtomNode.java b/src/ast/nodes/AtomNode.java
new file mode 100644
index 0000000..fa81f92
--- /dev/null
+++ b/src/ast/nodes/AtomNode.java
@@ -0,0 +1,45 @@
+package com.clp.project.ast.nodes;
+
+import java.util.ArrayList;
+
+import com.clp.project.semanticanalysis.SemanticError;
+import com.clp.project.semanticanalysis.SymbolTable;
+import com.clp.project.ast.types.*;
+
+/**
+ * Node for the `atom` statement of the grammar.
+ */
+public class AtomNode implements Node {
+ protected String val;
+
+ public AtomNode(String val) {
+ this.val = val;
+ }
+
+ @Override
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ return new ArrayList<SemanticError>();
+ }
+
+ // FIXME: this type for atom
+ @Override
+ public Type typeCheck() {
+ return new AtomType();
+ }
+
+ // TODO: add code generation for atom node
+ @Override
+ public String codeGeneration() {
+ return "";
+ }
+
+ @Override
+ public String toPrint(String prefix) {
+ if (val != null) {
+ return prefix + "Atom(" + val + ")\n";
+ }
+
+ return prefix + "Atom(null)\n";
+
+ }
+}
diff --git a/src/ast/nodes/AugassignNode.java b/src/ast/nodes/AugassignNode.java
new file mode 100644
index 0000000..3519b50
--- /dev/null
+++ b/src/ast/nodes/AugassignNode.java
@@ -0,0 +1,42 @@
+package com.clp.project.ast.nodes;
+
+import java.util.ArrayList;
+
+import com.clp.project.semanticanalysis.SemanticError;
+import com.clp.project.semanticanalysis.SymbolTable;
+
+import com.clp.project.ast.types.*;
+import org.antlr.v4.runtime.tree.TerminalNode;
+
+/**
+ * Node for the `augassign` statement of the grammar.
+ */
+public class AugassignNode implements Node {
+ private TerminalNode val;
+
+ public AugassignNode(TerminalNode val) {
+ this.val = val;
+ }
+
+ @Override
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ return new ArrayList<SemanticError>();
+ }
+
+ // FIXME: use the right type
+ @Override
+ public Type typeCheck() {
+ return new VoidType();
+ }
+
+ // TODO: add code generation for augassign node
+ @Override
+ public String codeGeneration() {
+ return "";
+ }
+
+ @Override
+ public String toPrint(String prefix) {
+ return prefix + "Augassign(" + val + ")\n";
+ }
+}
diff --git a/src/ast/nodes/BlockNode.java b/src/ast/nodes/BlockNode.java
new file mode 100644
index 0000000..1fdfcc3
--- /dev/null
+++ b/src/ast/nodes/BlockNode.java
@@ -0,0 +1,38 @@
+package com.clp.project.ast.nodes;
+
+import java.util.ArrayList;
+
+import com.clp.project.semanticanalysis.SemanticError;
+import com.clp.project.semanticanalysis.SymbolTable;
+import com.clp.project.ast.types.*;
+
+/**
+ * Node for `block` statement of the grammar.
+ * It extends the `RootNode`.
+ */
+public class BlockNode extends RootNode implements Node {
+ public BlockNode(ArrayList<Node> stmts, ArrayList<Node> compoundStmts) {
+ super(stmts, compoundStmts);
+ }
+
+ @Override
+ public Type typeCheck() {
+ return new VoidType();
+ }
+
+ @Override
+ public String toPrint(String prefix) {
+ String str = prefix + "Block\n";
+
+ prefix += " ";
+ for (Node stmt : stmts) {
+ str += stmt.toPrint(prefix);
+ }
+ for (Node stmt : compoundStmts) {
+ str += stmt.toPrint(prefix);
+ }
+
+ return str;
+ }
+
+}
diff --git a/src/ast/nodes/CompNode.java b/src/ast/nodes/CompNode.java
new file mode 100644
index 0000000..6deb51c
--- /dev/null
+++ b/src/ast/nodes/CompNode.java
@@ -0,0 +1,41 @@
+package com.clp.project.ast.nodes;
+
+import java.util.ArrayList;
+
+import com.clp.project.semanticanalysis.SemanticError;
+import com.clp.project.semanticanalysis.SymbolTable;
+import com.clp.project.ast.types.*;
+import org.antlr.v4.runtime.tree.TerminalNode;
+
+/**
+ * Node for the `comp_op` statement of the grammar.
+ */
+public class CompNode implements Node {
+ private TerminalNode op;
+
+ public CompNode(TerminalNode op) {
+ this.op = op;
+ }
+
+ @Override
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ return new ArrayList<SemanticError>();
+ }
+
+ // TODO: it should be boolean, right?
+ @Override
+ public Type typeCheck() {
+ return new VoidType();
+ }
+
+ // TODO: add code generation for CompNode
+ @Override
+ public String codeGeneration() {
+ return "";
+ }
+
+ @Override
+ public String toPrint(String prefix) {
+ return prefix + "CompNode(" + op + ")\n";
+ }
+}
diff --git a/src/ast/nodes/CompoundNode.java b/src/ast/nodes/CompoundNode.java
new file mode 100644
index 0000000..bfa0523
--- /dev/null
+++ b/src/ast/nodes/CompoundNode.java
@@ -0,0 +1,84 @@
+package com.clp.project.ast.nodes;
+
+import java.util.ArrayList;
+
+import com.clp.project.semanticanalysis.SemanticError;
+import com.clp.project.semanticanalysis.SymbolTable;
+import com.clp.project.ast.types.*;
+
+/**
+ * Node for the `compound_node` statement of the grammar.
+ */
+public class CompoundNode implements Node {
+ private Node ifNode;
+ private Node funcDef;
+ private Node forStmt;
+ private Node whileStmt;
+
+ public CompoundNode(Node ifNode, Node funcDef, Node forStmt, Node whileStmt) {
+ this.ifNode = ifNode;
+ this.funcDef = funcDef;
+ this.forStmt = forStmt;
+ this.whileStmt = whileStmt;
+ }
+
+ @Override
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ ArrayList<SemanticError> errors = new ArrayList<SemanticError>();
+
+ if (ifNode != null) {
+ errors.addAll(ifNode.checkSemantics(ST, _nesting));
+ }
+
+ if (funcDef != null) {
+ errors.addAll(funcDef.checkSemantics(ST, _nesting));
+ }
+
+ if (forStmt != null) {
+ errors.addAll(forStmt.checkSemantics(ST, _nesting));
+ }
+
+ if (whileStmt != null) {
+ errors.addAll(whileStmt.checkSemantics(ST, _nesting));
+ }
+
+ return errors;
+ }
+
+ @Override
+ public Type typeCheck() {
+ return new VoidType();
+ }
+
+ // TODO: add code generation for CompoundNode
+ @Override
+ public String codeGeneration() {
+ return "";
+ }
+
+ @Override
+ public String toPrint(String prefix) {
+ String str = prefix + "CompoundNode\n";
+
+ prefix += " ";
+
+ if (ifNode != null) {
+ str += ifNode.toPrint(prefix);
+ }
+
+ if (funcDef != null) {
+ str += funcDef.toPrint(prefix);
+ }
+
+ if (forStmt != null) {
+ str += forStmt.toPrint(prefix);
+ }
+
+ if (whileStmt != null) {
+ str += whileStmt.toPrint(prefix);
+ }
+
+ return str;
+ }
+
+}
diff --git a/src/ast/nodes/DottedNameNode.java b/src/ast/nodes/DottedNameNode.java
new file mode 100644
index 0000000..342950a
--- /dev/null
+++ b/src/ast/nodes/DottedNameNode.java
@@ -0,0 +1,51 @@
+package com.clp.project.ast.nodes;
+
+import java.util.ArrayList;
+
+import com.clp.project.semanticanalysis.SemanticError;
+import com.clp.project.semanticanalysis.SymbolTable;
+import com.clp.project.ast.types.*;
+import org.antlr.v4.runtime.tree.TerminalNode;
+
+/**
+ * Node for the `dooted_name` statement of the grammar.
+ */
+public class DottedNameNode implements Node {
+ protected ArrayList<TerminalNode> names;
+
+ public DottedNameNode(ArrayList<TerminalNode> names) {
+ this.names = names;
+ }
+
+ @Override
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ ArrayList<SemanticError> errors = new ArrayList<SemanticError>();
+
+ return errors;
+ }
+
+ @Override
+ public Type typeCheck() {
+ return new VoidType();
+ }
+
+ // 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.
+ @Override
+ public String codeGeneration() {
+ return "";
+ }
+
+ @Override
+ public String toPrint(String prefix) {
+ String str = prefix + "DottedName\n";
+
+ prefix += " ";
+ for (var name : names) {
+ str += prefix + name.toString() + "\n";
+ }
+
+ return str;
+ }
+
+}
diff --git a/src/ast/nodes/ExprNode.java b/src/ast/nodes/ExprNode.java
new file mode 100644
index 0000000..3aa112f
--- /dev/null
+++ b/src/ast/nodes/ExprNode.java
@@ -0,0 +1,90 @@
+package com.clp.project.ast.nodes;
+
+import java.util.ArrayList;
+
+import com.clp.project.semanticanalysis.SemanticError;
+import com.clp.project.semanticanalysis.SymbolTable;
+import com.clp.project.ast.types.*;
+
+/**
+ * Node for the `expr` statement of the grammar.
+ */
+public class ExprNode implements Node {
+ private Node atom;
+ private Node compOp;
+ private String op;
+ private ArrayList<Node> exprs;
+ private ArrayList<Node> trailers;
+
+ public ExprNode(Node atom, Node compOp, ArrayList<Node> exprs, String op, ArrayList<Node> trailers) {
+ this.atom = atom;
+ this.compOp = compOp;
+ this.exprs = exprs;
+ this.op = op;
+ this.trailers = trailers;
+ }
+
+ @Override
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ ArrayList<SemanticError> errors = new ArrayList<SemanticError>();
+
+ if (atom != null) {
+ errors.addAll(atom.checkSemantics(ST, _nesting));
+ }
+
+ if (compOp != null) {
+ errors.addAll(compOp.checkSemantics(ST, _nesting));
+ }
+
+ for (var expr : exprs) {
+ errors.addAll(expr.checkSemantics(ST, _nesting));
+ }
+
+ for (var trailer : trailers) {
+ errors.addAll(trailer.checkSemantics(ST, _nesting));
+ }
+
+ return errors;
+ }
+
+ // FIXME: type for the expr
+ @Override
+ public Type typeCheck() {
+ return new VoidType();
+ }
+
+ // TODO: add code generation for expr
+ @Override
+ public String codeGeneration() {
+ return "";
+ }
+
+ @Override
+ public String toPrint(String prefix) {
+ String str = prefix + "Expr\n";
+
+ prefix += " ";
+ if (atom != null) {
+ str += atom.toPrint(prefix);
+ }
+
+ if (compOp != null) {
+ str += compOp.toPrint(prefix);
+ }
+
+ for (var expr : exprs) {
+ str += expr.toPrint(prefix);
+ }
+
+ for (var trailer : trailers) {
+ str += trailer.toPrint(prefix);
+ }
+
+ if (op != null) {
+ str += prefix + "Op(" + op + ")\n";
+ }
+
+ return str;
+ }
+
+}
diff --git a/src/ast/nodes/ForStmtNode.java b/src/ast/nodes/ForStmtNode.java
new file mode 100644
index 0000000..69dee74
--- /dev/null
+++ b/src/ast/nodes/ForStmtNode.java
@@ -0,0 +1,47 @@
+package com.clp.project.ast.nodes;
+
+import java.util.ArrayList;
+
+import com.clp.project.semanticanalysis.SemanticError;
+import com.clp.project.semanticanalysis.SymbolTable;
+import com.clp.project.ast.types.*;
+
+/**
+ * Node for the `for_stmt` statement of the grammar.
+ */
+public class ForStmtNode implements Node {
+ private Node exprList;
+ private Node block;
+
+ public ForStmtNode(Node exprList, Node block) {
+ this.exprList = exprList;
+ this.block = block;
+ }
+
+ @Override
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ ArrayList<SemanticError> errors = new ArrayList<SemanticError>();
+
+ errors.addAll(exprList.checkSemantics(ST, _nesting));
+ errors.addAll(block.checkSemantics(ST, _nesting));
+
+ return errors;
+ }
+
+ @Override
+ public Type typeCheck() {
+ return new VoidType();
+ }
+
+ // TODO: add code generation for while
+ @Override
+ public String codeGeneration() {
+ return "";
+ }
+
+ @Override
+ public String toPrint(String prefix) {
+ return prefix + "For\n" + exprList.toPrint(prefix + " ") + block.toPrint(prefix + " ");
+ }
+
+}
diff --git a/src/ast/nodes/FuncdefNode.java b/src/ast/nodes/FuncdefNode.java
new file mode 100644
index 0000000..c48eb1c
--- /dev/null
+++ b/src/ast/nodes/FuncdefNode.java
@@ -0,0 +1,63 @@
+package com.clp.project.ast.nodes;
+
+import java.util.ArrayList;
+
+import com.clp.project.semanticanalysis.SemanticError;
+import com.clp.project.semanticanalysis.SymbolTable;
+import com.clp.project.ast.types.*;
+import org.antlr.v4.runtime.tree.TerminalNode;
+
+/**
+ * Node for the `funcdef` statement of the grammar.
+ */
+public class FuncdefNode implements Node {
+ private TerminalNode name;
+ private Node paramlist;
+ private Node block;
+
+ public FuncdefNode(TerminalNode name, Node paramlist, Node block) {
+ this.name = name;
+ this.paramlist = paramlist;
+ this.block = block;
+ }
+
+ @Override
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ ArrayList<SemanticError> errors = new ArrayList<SemanticError>();
+
+ if (paramlist != null) {
+ errors.addAll(paramlist.checkSemantics(ST, _nesting));
+ }
+
+ errors.addAll(block.checkSemantics(ST, _nesting));
+
+ return errors;
+ }
+
+ // FIXME: this type must be the same of the return stmt variable
+ @Override
+ public Type typeCheck() {
+ return new VoidType();
+ }
+
+ // TODO: code generation for funcdef
+ @Override
+ public String codeGeneration() {
+ return "";
+ }
+
+ public String toPrint(String prefix) {
+ String str = prefix + "Funcdef(" + name + ")\n";
+
+ prefix += " ";
+
+ if (paramlist != null) {
+ str += paramlist.toPrint(prefix);
+ }
+
+ str += block.toPrint(prefix);
+
+ return str;
+ }
+
+}
diff --git a/src/ast/nodes/IfNode.java b/src/ast/nodes/IfNode.java
new file mode 100644
index 0000000..a4f160d
--- /dev/null
+++ b/src/ast/nodes/IfNode.java
@@ -0,0 +1,71 @@
+package com.clp.project.ast.nodes;
+
+import java.util.ArrayList;
+
+import com.clp.project.semanticanalysis.SemanticError;
+import com.clp.project.semanticanalysis.SymbolTable;
+import com.clp.project.ast.types.*;
+
+/**
+ * Node for the `if` statement of the grammar.
+ */
+public class IfNode implements Node {
+ private Node guard;
+ private Node thenbranch;
+ private Node elsebranch;
+
+ public IfNode(Node guard, Node thenbranch, Node elsebranch) {
+ this.guard = guard;
+ this.thenbranch = thenbranch;
+ this.elsebranch = elsebranch;
+ }
+
+ @Override
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ ArrayList<SemanticError> errors = new ArrayList<SemanticError>();
+
+ errors.addAll(guard.checkSemantics(ST, _nesting));
+ errors.addAll(thenbranch.checkSemantics(ST, _nesting));
+ if (elsebranch != null) {
+ errors.addAll(elsebranch.checkSemantics(ST, _nesting));
+ }
+
+ return errors;
+ }
+
+ // FIXME: fix the if statement
+ @Override
+ public Type typeCheck() {
+ if (guard.typeCheck() instanceof BoolType) {
+ Type thenexp = thenbranch.typeCheck();
+ Type elseexp = elsebranch.typeCheck();
+ if (thenexp.getClass().equals(elseexp.getClass()))
+ return thenexp;
+ else {
+ System.out.println("Type Error: incompatible types in then and else branches");
+ return new ErrorType();
+ }
+ } else {
+ System.out.println("Type Error: non boolean condition in if");
+ return new ErrorType();
+ }
+ }
+
+ // TODO: add code generation for if
+ @Override
+ public String codeGeneration() {
+ return "";
+ }
+
+ @Override
+ public String toPrint(String prefix) {
+ String str = prefix + "If\n" + guard.toPrint(prefix + " ") + thenbranch.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
new file mode 100644
index 0000000..e6ac8c7
--- /dev/null
+++ b/src/ast/nodes/ImportNode.java
@@ -0,0 +1,76 @@
+package com.clp.project.ast.nodes;
+
+import java.util.ArrayList;
+
+import com.clp.project.semanticanalysis.SemanticError;
+import com.clp.project.semanticanalysis.SymbolTable;
+import com.clp.project.ast.types.*;
+
+/**
+ * Node for the `import_stmt` statement of the grammar.
+ */
+public class ImportNode implements Node {
+ private Node dottedName;
+ private boolean isFrom;
+ private boolean importAs;
+ private boolean importAll;
+ private ArrayList<String> names;
+
+ public ImportNode(Node dottedName, boolean isFrom, boolean importAs, boolean importAll,
+ ArrayList<String> names) {
+ this.dottedName = dottedName;
+ this.isFrom = isFrom;
+ this.importAs = importAs;
+ this.importAll = importAll;
+ this.names = names;
+ }
+
+ @Override
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ ArrayList<SemanticError> errors = new ArrayList<SemanticError>();
+
+ return errors;
+ }
+
+ @Override
+ public Type typeCheck() {
+ return new VoidType();
+ }
+
+ // NOTE: we do not want to provide a code generation for this statement
+ @Override
+ public String codeGeneration() {
+ return "";
+ }
+
+ @Override
+ public String toPrint(String prefix) {
+ String str = prefix + "Import\n";
+
+ prefix += " ";
+ if (isFrom) {
+ str += prefix + " From\n" + dottedName.toPrint(prefix + " ");
+ } else {
+ str += dottedName.toPrint(prefix);
+ }
+
+ if (importAs) {
+ str += prefix + " As " + names.get(0) + "\n";
+ }
+
+ if (importAll) {
+ str += prefix + " All\n";
+ }
+
+ for (int i = 0; i < names.size(); ++i) {
+ if (i == 0 && importAs)
+ continue;
+
+ str += prefix + names.get(i) + "\n";
+ }
+
+ str += "\n";
+ return str;
+ }
+
+}
diff --git a/src/ast/nodes/Node.java b/src/ast/nodes/Node.java
new file mode 100644
index 0000000..f807745
--- /dev/null
+++ b/src/ast/nodes/Node.java
@@ -0,0 +1,36 @@
+package com.clp.project.ast.nodes;
+
+import java.util.ArrayList;
+
+import com.clp.project.semanticanalysis.SemanticError;
+import com.clp.project.semanticanalysis.SymbolTable;
+import com.clp.project.ast.types.*;
+
+/**
+ * Base interface for a Node.
+ */
+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);
+
+ /**
+ * Checks the type for a given node. If there's any error, returns an
+ * `ErrorType`.
+ */
+ Type typeCheck();
+
+ /**
+ * Returns a string for the Python Virtual Machine.
+ */
+ String codeGeneration();
+
+ /**
+ * Returns a string for a given node with a prefix.
+ * It used when an AST wants to be visualized on screen.
+ */
+ String toPrint(String prefix);
+}
diff --git a/src/ast/nodes/ParamdefNode.java b/src/ast/nodes/ParamdefNode.java
new file mode 100644
index 0000000..d8e04f7
--- /dev/null
+++ b/src/ast/nodes/ParamdefNode.java
@@ -0,0 +1,29 @@
+package com.clp.project.ast.nodes;
+
+import java.util.ArrayList;
+
+import com.clp.project.semanticanalysis.SemanticError;
+import com.clp.project.semanticanalysis.SymbolTable;
+
+import com.clp.project.ast.types.*;
+
+/**
+ * Node for the `paramdef` statement of the grammar. Extends the `AtomNode`
+ * class.
+ */
+public class ParamdefNode extends AtomNode implements Node {
+ public ParamdefNode(String val) {
+ super(val);
+ }
+
+ // FIXME: it should returns the param' type
+ @Override
+ public Type typeCheck() {
+ return new VoidType();
+ }
+
+ @Override
+ public String toPrint(String prefix) {
+ return prefix + "Paramdef(" + val + ")\n";
+ }
+}
diff --git a/src/ast/nodes/ParamlistNode.java b/src/ast/nodes/ParamlistNode.java
new file mode 100644
index 0000000..d4f40b8
--- /dev/null
+++ b/src/ast/nodes/ParamlistNode.java
@@ -0,0 +1,53 @@
+package com.clp.project.ast.nodes;
+
+import java.util.ArrayList;
+
+import com.clp.project.semanticanalysis.SemanticError;
+import com.clp.project.semanticanalysis.SymbolTable;
+import com.clp.project.ast.types.*;
+
+/**
+ * Node for the `param_list` statement of the grammar.
+ */
+public class ParamlistNode implements Node {
+ private ArrayList<Node> params;
+
+ public ParamlistNode(ArrayList<Node> _params) {
+ params = _params;
+ }
+
+ @Override
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ ArrayList<SemanticError> errors = new ArrayList<SemanticError>();
+
+ for (var param : params) {
+ errors.addAll(param.checkSemantics(ST, _nesting));
+ }
+
+ return errors;
+ }
+
+ @Override
+ public Type typeCheck() {
+ return new VoidType();
+ }
+
+ // TODO: code generation for param list
+ @Override
+ public String codeGeneration() {
+ return "";
+ }
+
+ @Override
+ public String toPrint(String prefix) {
+ String str = prefix + "Paramlist\n";
+
+ prefix += " ";
+ for (var param : params) {
+ str += param.toPrint(prefix);
+ }
+
+ return str;
+ }
+
+}
diff --git a/src/ast/nodes/ReturnStmtNode.java b/src/ast/nodes/ReturnStmtNode.java
new file mode 100644
index 0000000..0cfd2b4
--- /dev/null
+++ b/src/ast/nodes/ReturnStmtNode.java
@@ -0,0 +1,57 @@
+package com.clp.project.ast.nodes;
+
+import java.util.ArrayList;
+
+import com.clp.project.semanticanalysis.SemanticError;
+import com.clp.project.semanticanalysis.SymbolTable;
+import com.clp.project.ast.types.*;
+
+/**
+ * Node for the `return_stmt` statement of the grammar.
+ */
+public class ReturnStmtNode implements Node {
+ private Node exprList;
+
+ public ReturnStmtNode(Node exprList) {
+ this.exprList = exprList;
+ }
+
+ @Override
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ ArrayList<SemanticError> errors = new ArrayList<SemanticError>();
+
+ if (this.exprList != null) {
+ errors.addAll(this.exprList.checkSemantics(ST, _nesting));
+ }
+
+ return errors;
+ }
+
+ @Override
+ public Type typeCheck() {
+ if (this.exprList != null) {
+ return this.exprList.typeCheck();
+ }
+
+ return new VoidType();
+ }
+
+ // TODO: add code generation for return stmt
+ @Override
+ public String codeGeneration() {
+ return "";
+ }
+
+ @Override
+ public String toPrint(String prefix) {
+ String str = prefix + "ReturnStmt\n";
+
+ prefix += " ";
+ if (this.exprList != null) {
+ str += this.exprList.toPrint(prefix);
+ }
+
+ return str;
+ }
+
+}
diff --git a/src/ast/nodes/RootNode.java b/src/ast/nodes/RootNode.java
new file mode 100644
index 0000000..12d2f22
--- /dev/null
+++ b/src/ast/nodes/RootNode.java
@@ -0,0 +1,64 @@
+package com.clp.project.ast.nodes;
+
+import java.util.ArrayList;
+
+import com.clp.project.semanticanalysis.SemanticError;
+import com.clp.project.semanticanalysis.SymbolTable;
+import com.clp.project.ast.types.*;
+
+/**
+ * Node for the `root` statement of the grammar.
+ */
+public class RootNode implements Node {
+ // stms and compundStmts are protected because they are reused for a
+ // BlockNode
+ protected ArrayList<Node> stmts;
+ protected ArrayList<Node> compoundStmts;
+
+ public RootNode(ArrayList<Node> stmts, ArrayList<Node> compoundStmts) {
+ this.stmts = stmts;
+ this.compoundStmts = compoundStmts;
+ }
+
+ @Override
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ ArrayList<SemanticError> errors = new ArrayList<SemanticError>();
+
+ for (Node stmt : stmts) {
+ errors.addAll(stmt.checkSemantics(ST, _nesting));
+ }
+ for (Node stmt : compoundStmts) {
+ errors.addAll(stmt.checkSemantics(ST, _nesting));
+ }
+
+ return errors;
+ }
+
+ @Override
+ public Type typeCheck() {
+ return new VoidType();
+ }
+
+ // TODO: Code generation for RootNode
+ @Override
+ public String codeGeneration() {
+ return "";
+ }
+
+ @Override
+ public String toPrint(String prefix) {
+ String str = "Root\n";
+
+ prefix += " ";
+
+ for (Node stmt : stmts) {
+ str += stmt.toPrint(prefix);
+ }
+ for (Node stmt : compoundStmts) {
+ str += stmt.toPrint(prefix);
+ }
+
+ return str;
+ }
+
+}
diff --git a/src/ast/nodes/SimpleStmtNode.java b/src/ast/nodes/SimpleStmtNode.java
new file mode 100644
index 0000000..3f4dec3
--- /dev/null
+++ b/src/ast/nodes/SimpleStmtNode.java
@@ -0,0 +1,84 @@
+package com.clp.project.ast.nodes;
+
+import java.util.ArrayList;
+
+import com.clp.project.semanticanalysis.SemanticError;
+import com.clp.project.semanticanalysis.SymbolTable;
+import com.clp.project.ast.types.*;
+
+/**
+ * Node for the `simple_stmt` statement of the grammar.
+ */
+public class SimpleStmtNode implements Node {
+ private Node assignment;
+ private Node expr;
+ private Node returnStmt;
+ private Node importStmt;
+
+ public SimpleStmtNode(Node assignment, Node expr, Node returnStmt, Node importStmt) {
+ this.assignment = assignment;
+ this.expr = expr;
+ this.returnStmt = returnStmt;
+ this.importStmt = importStmt;
+ }
+
+ @Override
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ ArrayList<SemanticError> errors = new ArrayList<SemanticError>();
+
+ if (assignment != null) {
+ errors.addAll(assignment.checkSemantics(ST, _nesting));
+ }
+
+ if (expr != null) {
+ errors.addAll(expr.checkSemantics(ST, _nesting));
+ }
+
+ if (returnStmt != null) {
+ errors.addAll(returnStmt.checkSemantics(ST, _nesting));
+ }
+
+ if (importStmt != null) {
+ errors.addAll(importStmt.checkSemantics(ST, _nesting));
+ }
+
+ return errors;
+ }
+
+ @Override
+ public Type typeCheck() {
+ return new VoidType();
+ }
+
+ // TODO: add code generation for SimpleStmtNode
+ @Override
+ public String codeGeneration() {
+ return "";
+ }
+
+ @Override
+ public String toPrint(String prefix) {
+ String str = prefix + "SimpleStmt\n";
+
+ prefix += " ";
+
+ if (assignment != null) {
+ str += assignment.toPrint(prefix);
+ }
+
+ if (expr != null) {
+ str += expr.toPrint(prefix);
+ }
+
+ if (returnStmt != null) {
+ str += returnStmt.toPrint(prefix);
+ }
+
+ if (importStmt != null) {
+ str += importStmt.toPrint(prefix);
+ }
+
+ return str;
+ }
+
+}
diff --git a/src/ast/nodes/SimpleStmtsNode.java b/src/ast/nodes/SimpleStmtsNode.java
new file mode 100644
index 0000000..c8013a3
--- /dev/null
+++ b/src/ast/nodes/SimpleStmtsNode.java
@@ -0,0 +1,54 @@
+package com.clp.project.ast.nodes;
+
+import java.util.ArrayList;
+
+import com.clp.project.semanticanalysis.SemanticError;
+import com.clp.project.semanticanalysis.SymbolTable;
+import com.clp.project.ast.types.*;
+
+/**
+ * Node for the `simple_stmts` statement of the grammar.
+ */
+public class SimpleStmtsNode implements Node {
+ private ArrayList<Node> stmts;
+
+ public SimpleStmtsNode(ArrayList<Node> stmts) {
+ this.stmts = stmts;
+ }
+
+ @Override
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ ArrayList<SemanticError> errors = new ArrayList<SemanticError>();
+
+ for (Node stmt : stmts) {
+ errors.addAll(stmt.checkSemantics(ST, _nesting));
+ }
+
+ return errors;
+ }
+
+ @Override
+ public Type typeCheck() {
+ return new VoidType();
+ }
+
+ // TODO: Code generation for SimpleStmtsNode
+ @Override
+ public String codeGeneration() {
+ return "";
+ }
+
+ @Override
+ public String toPrint(String prefix) {
+ String str = prefix + "SimpleStmts\n";
+
+ prefix += " ";
+
+ for (Node stmt : stmts) {
+ str += stmt.toPrint(prefix);
+ }
+
+ return str;
+ }
+
+}
diff --git a/src/ast/nodes/TrailerNode.java b/src/ast/nodes/TrailerNode.java
new file mode 100644
index 0000000..fa7e1ed
--- /dev/null
+++ b/src/ast/nodes/TrailerNode.java
@@ -0,0 +1,78 @@
+package com.clp.project.ast.nodes;
+
+import java.util.ArrayList;
+
+import com.clp.project.semanticanalysis.SemanticError;
+import com.clp.project.semanticanalysis.SymbolTable;
+import com.clp.project.ast.types.*;
+import org.antlr.v4.runtime.tree.TerminalNode;
+
+/**
+ * Node for the `trailer` statement of the grammar.
+ */
+public class TrailerNode implements Node {
+ private Node arglist;
+ private ArrayList<Node> exprs;
+ private TerminalNode methodCall;
+ private boolean isEmpty;
+
+ public TrailerNode(Node arglist, ArrayList<Node> exprs, TerminalNode methodCall) {
+ this.arglist = arglist;
+ this.exprs = exprs;
+ this.methodCall = methodCall;
+
+ this.isEmpty = (this.arglist == null && this.exprs.size() == 0 && this.methodCall == null);
+ }
+
+ @Override
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ ArrayList<SemanticError> errors = new ArrayList<SemanticError>();
+
+ if (arglist != null) {
+ errors.addAll(arglist.checkSemantics(ST, _nesting));
+ }
+
+ for (var expr : exprs) {
+ errors.addAll(expr.checkSemantics(ST, _nesting));
+ }
+
+ return errors;
+ }
+
+ @Override
+ public Type typeCheck() {
+ return new VoidType();
+ }
+
+ // TODO: add code generation for trailer node
+ @Override
+ public String codeGeneration() {
+ return "";
+ }
+
+ @Override
+ public String toPrint(String prefix) {
+ String str = prefix + "TrailerNode\n";
+
+ prefix += " ";
+
+ if (arglist != null) {
+ str += arglist.toPrint(prefix);
+ }
+
+ for (var expr : exprs) {
+ str += expr.toPrint(prefix);
+ }
+
+ if (methodCall != null) {
+ str += prefix + "Method(" + methodCall + ")\n";
+ }
+
+ if (isEmpty) {
+ str += prefix + "()\n";
+ }
+
+ return str;
+ }
+
+}
diff --git a/src/ast/nodes/WhileStmtNode.java b/src/ast/nodes/WhileStmtNode.java
new file mode 100644
index 0000000..a84d60e
--- /dev/null
+++ b/src/ast/nodes/WhileStmtNode.java
@@ -0,0 +1,46 @@
+package com.clp.project.ast.nodes;
+
+import java.util.ArrayList;
+
+import com.clp.project.semanticanalysis.SemanticError;
+import com.clp.project.semanticanalysis.SymbolTable;
+import com.clp.project.ast.types.*;
+
+/**
+ * Node for the `while_stmt` statement of the grammar.
+ */
+public class WhileStmtNode implements Node {
+ private Node expr;
+ private Node block;
+
+ public WhileStmtNode(Node expr, Node block) {
+ this.expr = expr;
+ this.block = block;
+ }
+
+ @Override
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ ArrayList<SemanticError> errors = new ArrayList<SemanticError>();
+
+ errors.addAll(expr.checkSemantics(ST, _nesting));
+ errors.addAll(block.checkSemantics(ST, _nesting));
+
+ return errors;
+ }
+
+ @Override
+ public Type typeCheck() {
+ return new VoidType();
+ }
+
+ // TODO: add code generation for while
+ @Override
+ public String codeGeneration() {
+ return "";
+ }
+
+ @Override
+ public String toPrint(String prefix) {
+ return prefix + "While\n" + expr.toPrint(prefix + " ") + block.toPrint(prefix + " ");
+ }
+}
diff --git a/src/ast/types/AtomType.java b/src/ast/types/AtomType.java
new file mode 100644
index 0000000..a44a06c
--- /dev/null
+++ b/src/ast/types/AtomType.java
@@ -0,0 +1,11 @@
+package com.clp.project.ast.types;
+
+/**
+ * An tom type.
+ * TODO: do I need to use this one?
+ */
+public class AtomType extends Type {
+ public String toPrint(String prefix) {
+ return prefix + "Atom\n";
+ }
+}
diff --git a/src/ast/types/BoolType.java b/src/ast/types/BoolType.java
new file mode 100644
index 0000000..7fc28ee
--- /dev/null
+++ b/src/ast/types/BoolType.java
@@ -0,0 +1,10 @@
+package com.clp.project.ast.types;
+
+/**
+ * A boolean type. A bool is True or False.
+ */
+public class BoolType extends Type {
+ public String toPrint(String prefix) {
+ return prefix + "Bool\n";
+ }
+}
diff --git a/src/ast/types/ErrorType.java b/src/ast/types/ErrorType.java
new file mode 100644
index 0000000..30cb70e
--- /dev/null
+++ b/src/ast/types/ErrorType.java
@@ -0,0 +1,10 @@
+package com.clp.project.ast.types;
+
+/**
+ * Error type.
+ */
+public class ErrorType extends Type {
+ public String toPrint(String prefix) {
+ return prefix + "Error\n";
+ }
+}
diff --git a/src/ast/types/IntType.java b/src/ast/types/IntType.java
new file mode 100644
index 0000000..9f4b250
--- /dev/null
+++ b/src/ast/types/IntType.java
@@ -0,0 +1,10 @@
+package com.clp.project.ast.types;
+
+/**
+ * An integer type.
+ */
+public class IntType extends Type {
+ public String toPrint(String prefix) {
+ return prefix + "Int\n";
+ }
+}
diff --git a/src/ast/types/Type.java b/src/ast/types/Type.java
new file mode 100644
index 0000000..4756255
--- /dev/null
+++ b/src/ast/types/Type.java
@@ -0,0 +1,41 @@
+package com.clp.project.ast.types;
+
+import java.util.ArrayList;
+
+import com.clp.project.semanticanalysis.SemanticError;
+import com.clp.project.semanticanalysis.SymbolTable;
+import com.clp.project.ast.nodes.*;
+
+/**
+ * A node which represents a type class.
+ */
+public class Type implements Node {
+ public boolean isEqual(Type A, Type B) {
+ if (A.getClass().equals(B.getClass()))
+ return true;
+ else
+ return false;
+ }
+
+ public String toPrint(String s) {
+ return s;
+ }
+
+ public ArrayList<SemanticError> checkSemantics(SymbolTable ST, int _nesting) {
+ // It is never invoked
+ return null;
+ }
+
+ @Override
+ public Type typeCheck() {
+ // It is never invoked
+ return null;
+ }
+
+ @Override
+ public String codeGeneration() {
+ // It is never invoked
+ return "";
+ }
+
+}
diff --git a/src/ast/types/VoidType.java b/src/ast/types/VoidType.java
new file mode 100644
index 0000000..766aee2
--- /dev/null
+++ b/src/ast/types/VoidType.java
@@ -0,0 +1,10 @@
+package com.clp.project.ast.types;
+
+/**
+ * A void type. Voids return nothing.
+ */
+public class VoidType extends Type {
+ public String toPrint(String prefix) {
+ return prefix + "Void\n";
+ }
+}
diff --git a/src/parser/Python3Lexer.java b/src/parser/Python3Lexer.java
index 9a48207..ae33e3d 100644
--- a/src/parser/Python3Lexer.java
+++ b/src/parser/Python3Lexer.java
@@ -1,8 +1,10 @@
package com.clp.project.parser;
-// import com.clp.project.parser.Python3LexerBase;
-
-// Generated from src/Python3Lexer.g4 by ANTLR 4.13.1
+// Generated from src/parser/Python3Lexer.g4 by ANTLR 4.13.1
+import org.antlr.v4.runtime.Lexer;
+import org.antlr.v4.runtime.CharStream;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.TokenStream;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.atn.*;
import org.antlr.v4.runtime.dfa.DFA;
diff --git a/src/parser/Python3Parser.java b/src/parser/Python3Parser.java
index 4965501..a407482 100644
--- a/src/parser/Python3Parser.java
+++ b/src/parser/Python3Parser.java
@@ -1,6 +1,6 @@
package com.clp.project.parser;
-// Generated from src/Python3Parser.g4 by ANTLR 4.13.1
+// Generated from src/parser/Python3Parser.g4 by ANTLR 4.13.1
import org.antlr.v4.runtime.atn.*;
import org.antlr.v4.runtime.dfa.DFA;
import org.antlr.v4.runtime.*;
diff --git a/src/parser/Python3ParserBaseListener.java b/src/parser/Python3ParserBaseListener.java
index 6fa323f..7191565 100644
--- a/src/parser/Python3ParserBaseListener.java
+++ b/src/parser/Python3ParserBaseListener.java
@@ -1,5 +1,5 @@
package com.clp.project.parser;
-// Generated from src/Python3Parser.g4 by ANTLR 4.13.1
+// Generated from src/parser/Python3Parser.g4 by ANTLR 4.13.1
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.tree.ErrorNode;
diff --git a/src/parser/Python3ParserBaseVisitor.java b/src/parser/Python3ParserBaseVisitor.java
index 4ad92a0..4fc355f 100644
--- a/src/parser/Python3ParserBaseVisitor.java
+++ b/src/parser/Python3ParserBaseVisitor.java
@@ -1,6 +1,6 @@
package com.clp.project.parser;
-// Generated from src/Python3Parser.g4 by ANTLR 4.13.1
+// Generated from src/parser/Python3Parser.g4 by ANTLR 4.13.1
import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;
/**
diff --git a/src/parser/Python3ParserListener.java b/src/parser/Python3ParserListener.java
index 248105d..f71a32d 100644
--- a/src/parser/Python3ParserListener.java
+++ b/src/parser/Python3ParserListener.java
@@ -1,6 +1,6 @@
package com.clp.project.parser;
-// Generated from src/Python3Parser.g4 by ANTLR 4.13.1
+// Generated from src/parser/Python3Parser.g4 by ANTLR 4.13.1
import org.antlr.v4.runtime.tree.ParseTreeListener;
/**
diff --git a/src/parser/Python3ParserVisitor.java b/src/parser/Python3ParserVisitor.java
index b286b61..88607ed 100644
--- a/src/parser/Python3ParserVisitor.java
+++ b/src/parser/Python3ParserVisitor.java
@@ -1,6 +1,6 @@
package com.clp.project.parser;
-// Generated from src/Python3Parser.g4 by ANTLR 4.13.1
+// Generated from src/parser/Python3Parser.g4 by ANTLR 4.13.1
import org.antlr.v4.runtime.tree.ParseTreeVisitor;
/**
diff --git a/src/semanticanalysis/STentry.java b/src/semanticanalysis/STentry.java
new file mode 100644
index 0000000..42990fa
--- /dev/null
+++ b/src/semanticanalysis/STentry.java
@@ -0,0 +1,55 @@
+package com.clp.project.semanticanalysis;
+
+import com.clp.project.ast.types.Type;
+
+/**
+ * Entry class for the symbol table.
+ */
+public class STentry {
+ private Type type;
+ private int offset;
+ private int nesting;
+ private String label;
+
+ public STentry(Type type, int offset, int nesting) {
+ this.type = type;
+ this.offset = offset;
+ this.nesting = nesting;
+ }
+
+ public STentry(Type type, int offset, int nesting, String label) {
+ this.type = type;
+ this.offset = offset;
+ this.nesting = nesting;
+ this.label = label;
+ }
+
+ /**
+ * Getter for `type`
+ */
+ public Type getType() {
+ return type;
+ }
+
+ /**
+ * Getter for `offset`
+ */
+ public int getOffset() {
+ return offset;
+ }
+
+ /**
+ * Getter for `nesting`
+ */
+ public int getNesting() {
+ return nesting;
+ }
+
+ /**
+ * Getter for `label`
+ */
+ public String getLabel() {
+ return label;
+ }
+
+}
diff --git a/src/semanticanalysis/SemanticError.java b/src/semanticanalysis/SemanticError.java
new file mode 100644
index 0000000..1df1ce9
--- /dev/null
+++ b/src/semanticanalysis/SemanticError.java
@@ -0,0 +1,16 @@
+package com.clp.project.semanticanalysis;
+
+/**
+ * Class respresents a semantic error.
+ */
+public class SemanticError {
+ private String msg;
+
+ public SemanticError(String msg) {
+ this.msg = msg;
+ }
+
+ public String toString() {
+ return msg;
+ }
+}
diff --git a/src/semanticanalysis/SymbolTable.java b/src/semanticanalysis/SymbolTable.java
new file mode 100644
index 0000000..d4fda37
--- /dev/null
+++ b/src/semanticanalysis/SymbolTable.java
@@ -0,0 +1,153 @@
+package com.clp.project.semanticanalysis;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import com.clp.project.ast.*;
+import com.clp.project.ast.types.*;
+
+/**
+ * Class representing a symbol table. It's a list of hash table symbol table. We
+ * keep track of a ArrayList of HashMap called `symbolTable` and an array of
+ * integer called `offset`.
+ */
+public class SymbolTable {
+
+ private ArrayList<HashMap<String, STentry>> symbolTable;
+ private ArrayList<Integer> offset;
+
+ public SymbolTable() {
+ this.symbolTable = new ArrayList<HashMap<String, STentry>>();
+ this.offset = new ArrayList<Integer>();
+ }
+
+ /**
+ * Returns the nesting level.
+ */
+ public Integer nesting() {
+ return this.symbolTable.size() - 1;
+ }
+
+ /**
+ * Check out if an `id` is into the symbol table. Returns an STentry object
+ * or null if the `id` is not found.
+ *
+ * @param id is the identifier of the STentry to find.
+ */
+ public STentry lookup(String id) {
+ int n = this.symbolTable.size() - 1;
+ boolean found = false;
+ STentry T = null;
+ while ((n >= 0) && !found) {
+ HashMap<String, STentry> H = this.symbolTable.get(n);
+ T = H.get(id);
+ if (T != null) {
+ found = true;
+ }else {
+ n = n - 1;
+ }
+ }
+ return T;
+ }
+
+ /**
+ * Return the position of a STentry given the `id`, if it exists. Otherwise
+ * return `-1`. We start the search from the last inserted hashmap.
+ *
+ * @param id is the identifier of the STentry to find.
+ */
+ public Integer nslookup(String id) {
+ int n = this.symbolTable.size() - 1;
+ boolean found = false;
+ while ((n >= 0) && !found) {
+ HashMap<String, STentry> H = this.symbolTable.get(n);
+ if (H.get(id) != null) {
+ found = true;
+ }else {
+ n = n - 1;
+ }
+ }
+ return n;
+ }
+
+ /**
+ * Add an hashmap to the given symbol table and increase the offset level.
+ * We start from 2 because we have FP and AL before all.
+ *
+ * @param H is an hashmap that is must be added into the symbol table
+ */
+ public void add(HashMap<String, STentry> H) {
+ this.symbolTable.add(H);
+ this.offset.add(1);
+ }
+
+ /**
+ * Remove the last level for the symbol table.
+ */
+ public void remove() {
+ int x = this.symbolTable.size();
+ this.symbolTable.remove(x - 1);
+ this.offset.remove(x - 1);
+ }
+
+ /**
+ * Return `true` if the `id` is present in the last inseted hashmap.
+ * Otherwise return `false`.
+ *
+ * @param id is the identifier of the STentry to find.
+ */
+ public boolean top_lookup(String id) {
+ int n = symbolTable.size() - 1;
+ STentry T = null;
+ HashMap<String, STentry> H = symbolTable.get(n);
+ T = H.get(id);
+ return (T != null);
+ }
+
+ /**
+ * Insert a new entry into the symbol table.
+ *
+ * @param id
+ * @param type
+ * @param _nesting
+ * @param _label
+ */
+ public void insert(String id, Type type, int _nesting, String _label) {
+ int n = symbolTable.size() - 1;
+ HashMap<String, STentry> H = this.symbolTable.get(n);
+ this.symbolTable.remove(n);
+
+ int offs = this.offset.get(n);
+ this.offset.remove(n);
+
+ STentry idtype = new STentry(type, offs, _nesting, _label);
+ H.put(id, idtype);
+
+ this.symbolTable.add(H);
+
+ // We always increment the offset by 1 otherwise we need ad-hoc bytecode
+ // operations
+ if (type.getClass().equals((new BoolType()).getClass())) {
+ offs = offs + 1;
+ } else if (type.getClass().equals((new IntType()).getClass())) {
+ offs = offs + 1;
+ } else {
+ offs = offs + 1;
+ }
+
+ this.offset.add(offs);
+ }
+
+ /**
+ * Increase the offset level.
+ */
+ public void increaseoffset() {
+ int n = this.offset.size() - 1;
+ int offs = this.offset.get(n);
+ this.offset.remove(n);
+
+ offs = offs + 1;
+
+ this.offset.add(offs);
+ }
+
+}