From 8e7089a5d6ba1f4f50a90133bb50bc5c6c554aff Mon Sep 17 00:00:00 2001
From: Santo Cariotti <santo@dcariotti.me>
Date: Thu, 13 Jun 2024 11:00:06 +0200
Subject: Set up visitor (#3)

Co-authored-by: geno <gabriele.genovese2@studio.unibo.it>
---
 src/Main.java                             |  87 +++--
 src/ast/Python3VisitorImpl.java           | 530 ++++++++++++++++++++++++++++++
 src/ast/nodes/ArglistNode.java            |  53 +++
 src/ast/nodes/AssignmentNode.java         |  52 +++
 src/ast/nodes/AtomNode.java               |  45 +++
 src/ast/nodes/AugassignNode.java          |  42 +++
 src/ast/nodes/BlockNode.java              |  38 +++
 src/ast/nodes/CompNode.java               |  41 +++
 src/ast/nodes/CompoundNode.java           |  84 +++++
 src/ast/nodes/DottedNameNode.java         |  51 +++
 src/ast/nodes/ExprNode.java               |  90 +++++
 src/ast/nodes/ForStmtNode.java            |  47 +++
 src/ast/nodes/FuncdefNode.java            |  63 ++++
 src/ast/nodes/IfNode.java                 |  71 ++++
 src/ast/nodes/ImportNode.java             |  76 +++++
 src/ast/nodes/Node.java                   |  36 ++
 src/ast/nodes/ParamdefNode.java           |  29 ++
 src/ast/nodes/ParamlistNode.java          |  53 +++
 src/ast/nodes/ReturnStmtNode.java         |  57 ++++
 src/ast/nodes/RootNode.java               |  64 ++++
 src/ast/nodes/SimpleStmtNode.java         |  84 +++++
 src/ast/nodes/SimpleStmtsNode.java        |  54 +++
 src/ast/nodes/TrailerNode.java            |  78 +++++
 src/ast/nodes/WhileStmtNode.java          |  46 +++
 src/ast/types/AtomType.java               |  11 +
 src/ast/types/BoolType.java               |  10 +
 src/ast/types/ErrorType.java              |  10 +
 src/ast/types/IntType.java                |  10 +
 src/ast/types/Type.java                   |  41 +++
 src/ast/types/VoidType.java               |  10 +
 src/parser/Python3Lexer.java              |   8 +-
 src/parser/Python3Parser.java             |   2 +-
 src/parser/Python3ParserBaseListener.java |   2 +-
 src/parser/Python3ParserBaseVisitor.java  |   2 +-
 src/parser/Python3ParserListener.java     |   2 +-
 src/parser/Python3ParserVisitor.java      |   2 +-
 src/semanticanalysis/STentry.java         |  55 ++++
 src/semanticanalysis/SemanticError.java   |  16 +
 src/semanticanalysis/SymbolTable.java     | 153 +++++++++
 39 files changed, 2169 insertions(+), 36 deletions(-)
 create mode 100644 src/ast/Python3VisitorImpl.java
 create mode 100644 src/ast/nodes/ArglistNode.java
 create mode 100644 src/ast/nodes/AssignmentNode.java
 create mode 100644 src/ast/nodes/AtomNode.java
 create mode 100644 src/ast/nodes/AugassignNode.java
 create mode 100644 src/ast/nodes/BlockNode.java
 create mode 100644 src/ast/nodes/CompNode.java
 create mode 100644 src/ast/nodes/CompoundNode.java
 create mode 100644 src/ast/nodes/DottedNameNode.java
 create mode 100644 src/ast/nodes/ExprNode.java
 create mode 100644 src/ast/nodes/ForStmtNode.java
 create mode 100644 src/ast/nodes/FuncdefNode.java
 create mode 100644 src/ast/nodes/IfNode.java
 create mode 100644 src/ast/nodes/ImportNode.java
 create mode 100644 src/ast/nodes/Node.java
 create mode 100644 src/ast/nodes/ParamdefNode.java
 create mode 100644 src/ast/nodes/ParamlistNode.java
 create mode 100644 src/ast/nodes/ReturnStmtNode.java
 create mode 100644 src/ast/nodes/RootNode.java
 create mode 100644 src/ast/nodes/SimpleStmtNode.java
 create mode 100644 src/ast/nodes/SimpleStmtsNode.java
 create mode 100644 src/ast/nodes/TrailerNode.java
 create mode 100644 src/ast/nodes/WhileStmtNode.java
 create mode 100644 src/ast/types/AtomType.java
 create mode 100644 src/ast/types/BoolType.java
 create mode 100644 src/ast/types/ErrorType.java
 create mode 100644 src/ast/types/IntType.java
 create mode 100644 src/ast/types/Type.java
 create mode 100644 src/ast/types/VoidType.java
 create mode 100644 src/semanticanalysis/STentry.java
 create mode 100644 src/semanticanalysis/SemanticError.java
 create mode 100644 src/semanticanalysis/SymbolTable.java

(limited to 'src')

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);
+    }
+
+}
-- 
cgit v1.2.3-18-g5258