diff --git a/src/ast/ArithmeticExpressionNode.cpp b/src/ast/ArithmeticExpressionNode.cpp index a0bb44a..ad1ad25 100644 --- a/src/ast/ArithmeticExpressionNode.cpp +++ b/src/ast/ArithmeticExpressionNode.cpp @@ -1,36 +1,2 @@ #include "ast/ArithmeticExpressionNode.hpp" -#include "ir/ArithmeticTac.hpp" - -Operand PlusNode::generateIR(CFG &graph, SymbolTable &st) { - auto lhs_name = left->generateIR(graph, st); - auto rhs_name = right->generateIR(graph, st); - auto name = graph.getTemporaryName(); - st.addIntegerVariable(name); - graph.addInstruction(new AddTac(name, lhs_name, rhs_name)); - return name; -} -Operand MinusNode::generateIR(CFG &graph, SymbolTable &st) { - auto lhs_name = left->generateIR(graph, st); - auto rhs_name = right->generateIR(graph, st); - auto name = graph.getTemporaryName(); - st.addIntegerVariable(name); - graph.addInstruction(new SubtractTac(name, lhs_name, rhs_name)); - return name; -} -Operand MultiplicationNode::generateIR(CFG &graph, SymbolTable &st) { - auto lhs_name = left->generateIR(graph, st); - auto rhs_name = right->generateIR(graph, st); - auto name = graph.getTemporaryName(); - st.addIntegerVariable(name); - graph.addInstruction(new MultiplyTac(name, lhs_name, rhs_name)); - return name; -} -Operand DivisionNode::generateIR(CFG &graph, SymbolTable &st) { - auto lhs_name = left->generateIR(graph, st); - auto rhs_name = right->generateIR(graph, st); - auto name = graph.getTemporaryName(); - st.addIntegerVariable(name); - graph.addInstruction(new DivideTac(name, lhs_name, rhs_name)); - return name; -} diff --git a/src/ast/ArithmeticExpressionNode.hpp b/src/ast/ArithmeticExpressionNode.hpp index 66108b1..dd2d46e 100644 --- a/src/ast/ArithmeticExpressionNode.hpp +++ b/src/ast/ArithmeticExpressionNode.hpp @@ -22,7 +22,6 @@ class PlusNode : public ArithmeticExpressionNode { PlusNode(std::unique_ptr left, std::unique_ptr right, int l) : ArithmeticExpressionNode("Plus", std::move(left), std::move(right), l) {} - Operand generateIR(CFG &graph, SymbolTable &st) override; }; class MinusNode : public ArithmeticExpressionNode { @@ -31,7 +30,6 @@ class MinusNode : public ArithmeticExpressionNode { MinusNode(std::unique_ptr left, std::unique_ptr right, int l) : ArithmeticExpressionNode("Minus", std::move(left), std::move(right), l) {} - Operand generateIR(CFG &graph, SymbolTable &st) override; }; class MultiplicationNode : public ArithmeticExpressionNode { @@ -41,7 +39,6 @@ class MultiplicationNode : public ArithmeticExpressionNode { int l) : ArithmeticExpressionNode("Multiplication", std::move(left), std::move(right), l) {} - Operand generateIR(CFG &graph, SymbolTable &st) override; }; class DivisionNode : public ArithmeticExpressionNode { @@ -50,7 +47,6 @@ class DivisionNode : public ArithmeticExpressionNode { DivisionNode(std::unique_ptr left, std::unique_ptr right, int l) : ArithmeticExpressionNode("Division", std::move(left), std::move(right), l) {} - Operand generateIR(CFG &graph, SymbolTable &st) override; }; #endif diff --git a/src/ast/ArrayAccessNode.cpp b/src/ast/ArrayAccessNode.cpp index 81f0f29..fe2c10f 100644 --- a/src/ast/ArrayAccessNode.cpp +++ b/src/ast/ArrayAccessNode.cpp @@ -1,11 +1,2 @@ #include "ast/ArrayAccessNode.hpp" -#include "ir/Tac.hpp" -Operand ArrayAccessNode::generateIR(CFG &graph, SymbolTable &st) { - auto arrayName = array->generateIR(graph, st); - auto indexName = index->generateIR(graph, st); - auto name = graph.getTemporaryName(); - st.addIntegerVariable(name); - graph.addInstruction(new ArrayAccessTac(name, arrayName, indexName)); - return name; -} diff --git a/src/ast/ArrayAccessNode.hpp b/src/ast/ArrayAccessNode.hpp index 1953e12..7f5fb3a 100644 --- a/src/ast/ArrayAccessNode.hpp +++ b/src/ast/ArrayAccessNode.hpp @@ -13,7 +13,6 @@ class ArrayAccessNode : public Node { array = append_child(std::move(array_)); index = append_child(std::move(index_)); } - Operand generateIR(CFG &graph, SymbolTable &st) override; }; #endif // ARRAYACCESSNODE_HPP diff --git a/src/ast/ArrayLengthNode.cpp b/src/ast/ArrayLengthNode.cpp index 6996c10..0d8698a 100644 --- a/src/ast/ArrayLengthNode.cpp +++ b/src/ast/ArrayLengthNode.cpp @@ -1,10 +1,2 @@ #include "ast/ArrayLengthNode.hpp" -#include "ir/Tac.hpp" -Operand ArrayLengthNode::generateIR(CFG &graph, SymbolTable &st) { - auto name = graph.getTemporaryName(); - st.addIntegerVariable(name); - auto arrayName = array->generateIR(graph, st); - graph.addInstruction(new ArrayLengthTac(name, arrayName)); - return name; -} diff --git a/src/ast/ArrayLengthNode.hpp b/src/ast/ArrayLengthNode.hpp index bd07564..af07654 100644 --- a/src/ast/ArrayLengthNode.hpp +++ b/src/ast/ArrayLengthNode.hpp @@ -10,7 +10,6 @@ class ArrayLengthNode : public Node { ArrayLengthNode(std::unique_ptr array_, int l) : Node("Array length", l), array(std::move(array_)) {} [[nodiscard]] const Node &getArrayNode() const { return *array; } - Operand generateIR(CFG &graph, SymbolTable &st) override; }; #endif // ARRAYLENGTHNODE_HPP diff --git a/src/ast/BooleanExpressionNode.cpp b/src/ast/BooleanExpressionNode.cpp index 39400dd..ca213fe 100644 --- a/src/ast/BooleanExpressionNode.cpp +++ b/src/ast/BooleanExpressionNode.cpp @@ -1,76 +1,2 @@ #include "ast/BooleanExpressionNode.hpp" -#include "ir/Tac.hpp" -Operand AndNode::generateIR(CFG &graph, SymbolTable &st) { - auto lhsName = left->generateIR(graph, st); - auto name = graph.getTemporaryName(); - st.addBooleanVariable(name); - - auto *rhsEvalBlock = graph.newBlock(); - auto *trueBlock = graph.newBlock(); - auto *falseBlock = graph.newBlock(); - auto *joinBlock = graph.newBlock(); - - auto *entryBlock = graph.getCurrentBlock(); - graph.addInstruction(new CondJumpTac(falseBlock->getName(), lhsName)); - graph.addInstruction(new JumpTac(rhsEvalBlock->getName())); - entryBlock->setTrueBlock(rhsEvalBlock); - entryBlock->setFalseBlock(falseBlock); - - graph.setCurrentBlock(rhsEvalBlock); - auto rhsName = right->generateIR(graph, st); - graph.addInstruction(new CondJumpTac(falseBlock->getName(), rhsName)); - graph.addInstruction(new JumpTac(trueBlock->getName())); - rhsEvalBlock->setTrueBlock(trueBlock); - rhsEvalBlock->setFalseBlock(falseBlock); - - graph.setCurrentBlock(trueBlock); - graph.addInstruction(new CopyTac(1, name)); - graph.addInstruction(new JumpTac(joinBlock->getName())); - trueBlock->setTrueBlock(joinBlock); - - graph.setCurrentBlock(falseBlock); - graph.addInstruction(new CopyTac(0, name)); - graph.addInstruction(new JumpTac(joinBlock->getName())); - falseBlock->setTrueBlock(joinBlock); - - graph.setCurrentBlock(joinBlock); - return name; -} - -Operand OrNode::generateIR(CFG &graph, SymbolTable &st) { - auto lhsName = left->generateIR(graph, st); - auto name = graph.getTemporaryName(); - st.addBooleanVariable(name); - - auto *rhsEvalBlock = graph.newBlock(); - auto *trueBlock = graph.newBlock(); - auto *falseBlock = graph.newBlock(); - auto *joinBlock = graph.newBlock(); - - auto *entryBlock = graph.getCurrentBlock(); - graph.addInstruction(new CondJumpTac(rhsEvalBlock->getName(), lhsName)); - graph.addInstruction(new JumpTac(trueBlock->getName())); - entryBlock->setTrueBlock(trueBlock); - entryBlock->setFalseBlock(rhsEvalBlock); - - graph.setCurrentBlock(rhsEvalBlock); - auto rhsName = right->generateIR(graph, st); - graph.addInstruction(new CondJumpTac(falseBlock->getName(), rhsName)); - graph.addInstruction(new JumpTac(trueBlock->getName())); - rhsEvalBlock->setTrueBlock(trueBlock); - rhsEvalBlock->setFalseBlock(falseBlock); - - graph.setCurrentBlock(trueBlock); - graph.addInstruction(new CopyTac(1, name)); - graph.addInstruction(new JumpTac(joinBlock->getName())); - trueBlock->setTrueBlock(joinBlock); - - graph.setCurrentBlock(falseBlock); - graph.addInstruction(new CopyTac(0, name)); - graph.addInstruction(new JumpTac(joinBlock->getName())); - falseBlock->setTrueBlock(joinBlock); - - graph.setCurrentBlock(joinBlock); - return name; -} diff --git a/src/ast/BooleanExpressionNode.hpp b/src/ast/BooleanExpressionNode.hpp index 5cd50e9..39bd34c 100644 --- a/src/ast/BooleanExpressionNode.hpp +++ b/src/ast/BooleanExpressionNode.hpp @@ -20,14 +20,12 @@ class AndNode : public BooleanExpressionNode { public: AndNode(std::unique_ptr left, std::unique_ptr right, int l) : BooleanExpressionNode("AND", std::move(left), std::move(right), l) {} - Operand generateIR(CFG &graph, SymbolTable &st) override; }; class OrNode : public BooleanExpressionNode { public: OrNode(std::unique_ptr left, std::unique_ptr right, int l) : BooleanExpressionNode("OR", std::move(left), std::move(right), l) {} - Operand generateIR(CFG &graph, SymbolTable &st) override; }; #endif diff --git a/src/ast/BooleanNode.cpp b/src/ast/BooleanNode.cpp index 3891a09..e7142f7 100644 --- a/src/ast/BooleanNode.cpp +++ b/src/ast/BooleanNode.cpp @@ -1,4 +1,2 @@ #include "ast/BooleanNode.hpp" -#include "ir/Tac.hpp" -Operand TrueNode::generateIR(CFG &graph, SymbolTable &st) { return true; } -Operand FalseNode::generateIR(CFG &graph, SymbolTable &st) { return false; } + diff --git a/src/ast/BooleanNode.hpp b/src/ast/BooleanNode.hpp index 0a2da69..3e45605 100644 --- a/src/ast/BooleanNode.hpp +++ b/src/ast/BooleanNode.hpp @@ -6,12 +6,10 @@ class TrueNode : public Node { public: TrueNode(int l) : Node("TRUE", l) {}; - Operand generateIR(CFG &graph, SymbolTable &st) override; }; class FalseNode : public Node { public: FalseNode(int l) : Node("FALSE", l) {}; - Operand generateIR(CFG &graph, SymbolTable &st) override; }; #endif // BOOLEANNODE_HPP diff --git a/src/ast/ClassAllocationNode.cpp b/src/ast/ClassAllocationNode.cpp index 7f7802d..029ab5c 100644 --- a/src/ast/ClassAllocationNode.cpp +++ b/src/ast/ClassAllocationNode.cpp @@ -1,9 +1,2 @@ #include "ast/ClassAllocationNode.hpp" -#include "ir/Tac.hpp" -Operand ClassAllocationNode::generateIR(CFG &graph, SymbolTable &st) { - auto name = graph.getTemporaryName(); - st.addVariable(id, name); - graph.addInstruction(new NewTac(name, id)); - return name; -} diff --git a/src/ast/ClassAllocationNode.hpp b/src/ast/ClassAllocationNode.hpp index afdf845..8d2ab58 100644 --- a/src/ast/ClassAllocationNode.hpp +++ b/src/ast/ClassAllocationNode.hpp @@ -9,7 +9,6 @@ class ClassAllocationNode : public Node { public: ClassAllocationNode(std::unique_ptr object, int l) : Node("Class allocation", object->value, l), id{object->value} {} - Operand generateIR(CFG &graph, SymbolTable &st) override; }; #endif // CLASSALLOCATIONNODE_HPP diff --git a/src/ast/ClassNode.cpp b/src/ast/ClassNode.cpp index fb7059d..8393d74 100644 --- a/src/ast/ClassNode.cpp +++ b/src/ast/ClassNode.cpp @@ -3,11 +3,3 @@ #include "ast/AstVisitor.hpp" void ClassNode::accept(AstVisitor &visitor) const { visitor.visit(*this); } - -Operand ClassNode::generateIR(CFG &graph, SymbolTable &st) { - auto *currentClass = st.lookupClass(className); - st.enterClassScope(currentClass); - body->generateIR(graph, st); - st.exitScope(); - return ""; -} diff --git a/src/ast/ClassNode.hpp b/src/ast/ClassNode.hpp index a246ed2..dbd21a9 100644 --- a/src/ast/ClassNode.hpp +++ b/src/ast/ClassNode.hpp @@ -18,8 +18,6 @@ class ClassNode : public Node { [[nodiscard]] const std::string &getClassName() const { return className; } [[nodiscard]] const Node &getBodyNode() const { return *body; } - - Operand generateIR(CFG &graph, SymbolTable &st) override; }; #endif diff --git a/src/ast/ControlStatementNode.cpp b/src/ast/ControlStatementNode.cpp index 6f11051..08e96e9 100644 --- a/src/ast/ControlStatementNode.cpp +++ b/src/ast/ControlStatementNode.cpp @@ -1,87 +1,2 @@ #include "ast/ControlStatementNode.hpp" -#include "ir/Tac.hpp" -Operand IfNode::generateIR(CFG &graph, SymbolTable &st) { - auto *trueBlock = graph.newBlock(); - auto *joinBlock = graph.newBlock(); - const auto &joinLabel = joinBlock->getName(); - const auto &trueLabel = trueBlock->getName(); - - const auto &condName = cond->generateIR(graph, st); - graph.addInstruction(new CondJumpTac(joinLabel, condName)); - graph.addInstruction(new JumpTac(trueLabel)); - - auto *currentBlock = graph.getCurrentBlock(); - currentBlock->setTrueBlock(trueBlock); - currentBlock->setFalseBlock(joinBlock); - - graph.setCurrentBlock(trueBlock); - stmt->generateIR(graph, st); - graph.addInstruction(new JumpTac(joinLabel)); - graph.getCurrentBlock()->setTrueBlock(joinBlock); - - graph.setCurrentBlock(joinBlock); - - return "placeholder ifnode::generateir"; -} - -Operand IfElseNode::generateIR(CFG &graph, SymbolTable &st) { - auto *trueBlock = graph.newBlock(); - auto *falseBlock = graph.newBlock(); - auto *joinBlock = graph.newBlock(); - - const auto &falseLabel = falseBlock->getName(); - const auto &joinLabel = joinBlock->getName(); - - const auto &condName = cond->generateIR(graph, st); - graph.addInstruction(new CondJumpTac(falseLabel, condName)); - graph.addInstruction(new JumpTac(trueBlock->getName())); - - auto *currentBlock = graph.getCurrentBlock(); - currentBlock->setTrueBlock(trueBlock); - currentBlock->setFalseBlock(falseBlock); - - graph.setCurrentBlock(trueBlock); - stmt->generateIR(graph, st); - graph.addInstruction(new JumpTac(joinLabel)); - graph.getCurrentBlock()->setTrueBlock(joinBlock); - - graph.setCurrentBlock(falseBlock); - elseStmt->generateIR(graph, st); - graph.addInstruction(new JumpTac(joinLabel)); - graph.getCurrentBlock()->setTrueBlock(joinBlock); - - graph.setCurrentBlock(joinBlock); - - return "placeholder ifelsenode::generateir"; -} - -Operand WhileNode::generateIR(CFG &graph, SymbolTable &st) { - auto *headerBlock = graph.newBlock(); - const auto &headerLabel = headerBlock->getName(); - auto *bodyBlock = graph.newBlock(); - bodyBlock->setTrueBlock(headerBlock); - auto *joinBlock = graph.newBlock(); - - auto *currentBlock = graph.getCurrentBlock(); - currentBlock->setTrueBlock(headerBlock); - graph.addInstruction(new JumpTac(headerLabel)); - - graph.setCurrentBlock(headerBlock); - const auto &condName = cond->generateIR(graph, st); - auto *conditionBlock = graph.getCurrentBlock(); - graph.addInstruction(new CondJumpTac(joinBlock->getName(), condName)); - graph.addInstruction(new JumpTac(bodyBlock->getName())); - - graph.setCurrentBlock(bodyBlock); - stmt->generateIR(graph, st); - graph.getCurrentBlock()->setTrueBlock(headerBlock); - graph.addInstruction(new JumpTac(headerLabel)); - - conditionBlock->setTrueBlock(bodyBlock); - conditionBlock->setFalseBlock(joinBlock); - - graph.setCurrentBlock(joinBlock); - - return "placeholder whilenode::generateir"; -} diff --git a/src/ast/ControlStatementNode.hpp b/src/ast/ControlStatementNode.hpp index e84fb33..d3dbb46 100644 --- a/src/ast/ControlStatementNode.hpp +++ b/src/ast/ControlStatementNode.hpp @@ -25,7 +25,6 @@ class IfNode : public ControlStatementNode { ++it; stmt = it->get(); } - Operand generateIR(CFG &graph, SymbolTable &st) override; }; class IfElseNode : public ControlStatementNode { Node *cond, *stmt, *elseStmt; @@ -41,7 +40,6 @@ class IfElseNode : public ControlStatementNode { stmt = it->get(); elseStmt = append_child(std::move(elseStmt_)); } - Operand generateIR(CFG &graph, SymbolTable &st) override; }; class WhileNode : public ControlStatementNode { Node *cond, *stmt; @@ -54,7 +52,6 @@ class WhileNode : public ControlStatementNode { ++it; stmt = it->get(); } - Operand generateIR(CFG &graph, SymbolTable &st) override; }; #endif diff --git a/src/ast/IdentifierNode.cpp b/src/ast/IdentifierNode.cpp index caf0aff..63b98b3 100644 --- a/src/ast/IdentifierNode.cpp +++ b/src/ast/IdentifierNode.cpp @@ -1,5 +1,2 @@ #include "ast/IdentifierNode.hpp" -Operand IdentifierNode::generateIR(CFG &graph, SymbolTable &st) { - return value; -} diff --git a/src/ast/IdentifierNode.hpp b/src/ast/IdentifierNode.hpp index afd1e35..5373ad6 100644 --- a/src/ast/IdentifierNode.hpp +++ b/src/ast/IdentifierNode.hpp @@ -10,8 +10,6 @@ class IdentifierNode : public Node { public: IdentifierNode(const std::string &value_, int l) : Node("Identifier", value_, l), value{value_} {} - - Operand generateIR(CFG &graph, SymbolTable &st) override; }; #endif diff --git a/src/ast/IntegerArrayAllocationNode.cpp b/src/ast/IntegerArrayAllocationNode.cpp index d2c3dfc..e4de5d2 100644 --- a/src/ast/IntegerArrayAllocationNode.cpp +++ b/src/ast/IntegerArrayAllocationNode.cpp @@ -1,10 +1,2 @@ #include "ast/IntegerArrayAllocationNode.hpp" -#include "ir/Tac.hpp" -Operand IntegerArrayAllocationNode::generateIR(CFG &graph, SymbolTable &st) { - auto name = graph.getTemporaryName(); - st.addVariable("int[]", name); - auto lengthName = length->generateIR(graph, st); - graph.addInstruction(new NewArrayTac(name, lengthName)); - return name; -} diff --git a/src/ast/IntegerArrayAllocationNode.hpp b/src/ast/IntegerArrayAllocationNode.hpp index 1a662f2..5749ea0 100644 --- a/src/ast/IntegerArrayAllocationNode.hpp +++ b/src/ast/IntegerArrayAllocationNode.hpp @@ -10,7 +10,6 @@ class IntegerArrayAllocationNode : public Node { IntegerArrayAllocationNode(std::unique_ptr length_, int l) : Node("Integer array allocation", l), length(std::move(length_)) {} [[nodiscard]] const Node &getLengthNode() const { return *length; } - Operand generateIR(CFG &graph, SymbolTable &st) override; }; #endif // INTEGERARRAYALLOCATIONNODE_HPP diff --git a/src/ast/IntegerNode.cpp b/src/ast/IntegerNode.cpp index fa90831..2a6d512 100644 --- a/src/ast/IntegerNode.cpp +++ b/src/ast/IntegerNode.cpp @@ -1,3 +1,2 @@ #include "ast/IntegerNode.hpp" -Operand IntegerNode::generateIR(CFG &graph, SymbolTable &st) { return value; } diff --git a/src/ast/IntegerNode.hpp b/src/ast/IntegerNode.hpp index 81c755b..1c7c188 100644 --- a/src/ast/IntegerNode.hpp +++ b/src/ast/IntegerNode.hpp @@ -12,8 +12,6 @@ class IntegerNode : public Node { public: IntegerNode(const std::string &value_, int l) : Node("Integer", value_, l), value{std::stoi(value_)} {} - - Operand generateIR(CFG &graph, SymbolTable &st) override; }; #endif diff --git a/src/ast/LogicalExpressionNode.cpp b/src/ast/LogicalExpressionNode.cpp index 5231d8a..f97f5c8 100644 --- a/src/ast/LogicalExpressionNode.cpp +++ b/src/ast/LogicalExpressionNode.cpp @@ -1,27 +1,2 @@ #include "ast/LogicalExpressionNode.hpp" -#include "ir/LogicalTac.hpp" -Operand LessThanNode::generateIR(CFG &graph, SymbolTable &st) { - auto lhs_name = left->generateIR(graph, st); - auto rhs_name = right->generateIR(graph, st); - auto name = graph.getTemporaryName(); - st.addBooleanVariable(name); - graph.addInstruction(new LessThanTac(name, lhs_name, rhs_name)); - return name; -} -Operand GreaterThanNode::generateIR(CFG &graph, SymbolTable &st) { - auto lhs_name = left->generateIR(graph, st); - auto rhs_name = right->generateIR(graph, st); - auto name = graph.getTemporaryName(); - st.addBooleanVariable(name); - graph.addInstruction(new GreaterThanTac(name, lhs_name, rhs_name)); - return name; -} -Operand EqualToNode::generateIR(CFG &graph, SymbolTable &st) { - auto lhs_name = left->generateIR(graph, st); - auto rhs_name = right->generateIR(graph, st); - auto name = graph.getTemporaryName(); - st.addBooleanVariable(name); - graph.addInstruction(new EqualToTac(name, lhs_name, rhs_name)); - return name; -} diff --git a/src/ast/LogicalExpressionNode.hpp b/src/ast/LogicalExpressionNode.hpp index 89a6b11..3776014 100644 --- a/src/ast/LogicalExpressionNode.hpp +++ b/src/ast/LogicalExpressionNode.hpp @@ -21,7 +21,6 @@ class LessThanNode : public LogicalExpressionNode { LessThanNode(std::unique_ptr left, std::unique_ptr right, int l) : LogicalExpressionNode("Less-than", std::move(left), std::move(right), l) {} - Operand generateIR(CFG &graph, SymbolTable &st) override; }; class GreaterThanNode : public LogicalExpressionNode { @@ -30,7 +29,6 @@ class GreaterThanNode : public LogicalExpressionNode { int l) : LogicalExpressionNode("Greater-than", std::move(left), std::move(right), l) {} - Operand generateIR(CFG &graph, SymbolTable &st) override; }; class EqualToNode : public Node { @@ -43,7 +41,6 @@ class EqualToNode : public Node { left = append_child(std::move(left_)); right = append_child(std::move(right_)); } - Operand generateIR(CFG &graph, SymbolTable &st) override; }; #endif diff --git a/src/ast/MainClassNode.cpp b/src/ast/MainClassNode.cpp index 8cddf9f..63b1b52 100644 --- a/src/ast/MainClassNode.cpp +++ b/src/ast/MainClassNode.cpp @@ -3,13 +3,3 @@ #include "ast/AstVisitor.hpp" void MainClassNode::accept(AstVisitor &visitor) const { visitor.visit(*this); } - -Operand MainClassNode::generateIR(CFG &graph, SymbolTable &st) { - st.enterClassScope(mainClassName); - st.enterMethodScope("main"); - graph.setCurrentBlock(graph.addMethodRootBlock(mainClassName, "main")); - body->generateIR(graph, st); - st.exitScope(); - st.exitScope(); - return graph.getCurrentBlock()->getName(); -} diff --git a/src/ast/MainClassNode.hpp b/src/ast/MainClassNode.hpp index b2072b5..3a6fcc3 100644 --- a/src/ast/MainClassNode.hpp +++ b/src/ast/MainClassNode.hpp @@ -27,8 +27,6 @@ class MainClassNode : public Node { return mainMethodArgumentName; } [[nodiscard]] const Node &getBodyNode() const { return *body; } - - Operand generateIR(CFG &graph, SymbolTable &st) override; }; #endif diff --git a/src/ast/MethodBodyNode.cpp b/src/ast/MethodBodyNode.cpp index 1f88612..fbf9fdb 100644 --- a/src/ast/MethodBodyNode.cpp +++ b/src/ast/MethodBodyNode.cpp @@ -1,14 +1,2 @@ #include "ast/MethodBodyNode.hpp" -Operand MethodBodyNode::generateIR(CFG &graph, SymbolTable &st) { - body->generateIR(graph, st); - const auto &name = returnValue->generateIR(graph, st); - graph.addInstruction(new ReturnTac(name)); - return name; -} - -Operand ReturnOnlyMethodBodyNode::generateIR(CFG &graph, SymbolTable &st) { - const auto &name = returnValue->generateIR(graph, st); - graph.addInstruction(new ReturnTac(name)); - return name; -} diff --git a/src/ast/MethodBodyNode.hpp b/src/ast/MethodBodyNode.hpp index c281214..e292a9c 100644 --- a/src/ast/MethodBodyNode.hpp +++ b/src/ast/MethodBodyNode.hpp @@ -13,7 +13,6 @@ class MethodBodyNode : public Node { body = append_child(std::move(body_)); returnValue = append_child(std::move(returnValue_)); } - Operand generateIR(CFG &graph, SymbolTable &st) override; }; class ReturnOnlyMethodBodyNode : public Node { Node *returnValue; @@ -23,6 +22,5 @@ class ReturnOnlyMethodBodyNode : public Node { : Node("Method body", l) { returnValue = append_child(std::move(returnValue_)); } - Operand generateIR(CFG &graph, SymbolTable &st) override; }; #endif diff --git a/src/ast/MethodCallNode.cpp b/src/ast/MethodCallNode.cpp index dae74f0..868076c 100644 --- a/src/ast/MethodCallNode.cpp +++ b/src/ast/MethodCallNode.cpp @@ -1,42 +1,2 @@ #include "ast/MethodCallNode.hpp" -#include - -#include "ir/Tac.hpp" - -Operand MethodCallNode::generateIR(CFG &graph, SymbolTable &st) { - const auto *caller_type = graph.typeOf(*object); - assert(caller_type != nullptr && - "Type information missing for method call receiver"); - if (caller_type == nullptr || caller_type->empty()) { - return ""; - } - - auto *callingClass = st.lookupClass(*caller_type); - if (callingClass == nullptr) { - return ""; - } - - auto const *method = callingClass->lookupMethod(id->value); - if (method == nullptr) { - return ""; - } - - const auto &methodType = method->getType(); - const auto receiver = object->generateIR(graph, st); - - for (const auto &arg : exprList->children) { - const auto &argName = arg->generateIR(graph, st); - graph.addInstruction(new ParamTac(argName)); - } - - const auto &name = graph.getTemporaryName(); - st.addVariable(methodType, name); - - const auto &methodName = id->value; - const auto methodTarget = *caller_type + "." + methodName; - const auto argCount = static_cast(exprList->children.size()); - graph.addInstruction( - new MethodCallTac(name, receiver, methodTarget, argCount)); - return name; -} diff --git a/src/ast/MethodCallNode.hpp b/src/ast/MethodCallNode.hpp index c90a133..ff6b2a9 100644 --- a/src/ast/MethodCallNode.hpp +++ b/src/ast/MethodCallNode.hpp @@ -16,7 +16,6 @@ class MethodCallNode : public Node { id = append_child(std::move(id_)); exprList = append_child(std::move(exprList_)); } - Operand generateIR(CFG &graph, SymbolTable &st) override; }; #endif diff --git a/src/ast/MethodCallWithoutArgumentsNode.cpp b/src/ast/MethodCallWithoutArgumentsNode.cpp index a7ce897..e70bf3a 100644 --- a/src/ast/MethodCallWithoutArgumentsNode.cpp +++ b/src/ast/MethodCallWithoutArgumentsNode.cpp @@ -1,32 +1,2 @@ #include "ast/MethodCallWithoutArgumentsNode.hpp" -#include -Operand MethodCallWithoutArgumentsNode::generateIR(CFG &graph, - SymbolTable &st) { - const auto *caller_type = graph.typeOf(*object); - assert(caller_type != nullptr && - "Type information missing for method call receiver"); - if (caller_type == nullptr || caller_type->empty()) { - return ""; - } - - auto *callingClass = st.lookupClass(*caller_type); - if (callingClass == nullptr) { - return ""; - } - - auto const *method = callingClass->lookupMethod(id->value); - if (method == nullptr) { - return ""; - } - - const auto &methodType = method->getType(); - const auto receiver = object->generateIR(graph, st); - - const auto &name = graph.getTemporaryName(); - st.addVariable(methodType, name); - const auto &methodName = id->value; - const auto methodTarget = *caller_type + "." + methodName; - graph.addInstruction(new MethodCallTac(name, receiver, methodTarget, 0)); - return name; -} diff --git a/src/ast/MethodCallWithoutArgumentsNode.hpp b/src/ast/MethodCallWithoutArgumentsNode.hpp index c4064d4..52d3ba7 100644 --- a/src/ast/MethodCallWithoutArgumentsNode.hpp +++ b/src/ast/MethodCallWithoutArgumentsNode.hpp @@ -12,7 +12,6 @@ class MethodCallWithoutArgumentsNode : public Node { object = append_child(std::move(object_)); id = append_child(std::move(id_)); } - Operand generateIR(CFG &graph, SymbolTable &st) override; }; #endif diff --git a/src/ast/MethodNode.cpp b/src/ast/MethodNode.cpp index a5cd3ec..ee6241e 100644 --- a/src/ast/MethodNode.cpp +++ b/src/ast/MethodNode.cpp @@ -3,14 +3,3 @@ #include "ast/AstVisitor.hpp" void MethodNode::accept(AstVisitor &visitor) const { visitor.visit(*this); } - -Operand MethodNode::generateIR(CFG &graph, SymbolTable &st) { - auto *currentClass = dynamic_cast(st.getCurrentRecord()); - auto *currentMethod = st.lookupMethod(methodName); - st.enterMethodScope(currentMethod); - graph.setCurrentBlock( - graph.addMethodRootBlock(currentClass->getID(), methodName)); - body->generateIR(graph, st); - st.exitScope(); - return graph.getCurrentBlock()->getName(); -} diff --git a/src/ast/MethodNode.hpp b/src/ast/MethodNode.hpp index 7fc6727..bdb7370 100644 --- a/src/ast/MethodNode.hpp +++ b/src/ast/MethodNode.hpp @@ -30,8 +30,6 @@ class MethodNode : public Node { } [[nodiscard]] const Node &getParametersNode() const { return *params; } [[nodiscard]] const Node &getBodyNode() const { return *body; } - - Operand generateIR(CFG &graph, SymbolTable &st) override; }; #endif diff --git a/src/ast/MethodWithoutParametersNode.cpp b/src/ast/MethodWithoutParametersNode.cpp index d01e271..a249c88 100644 --- a/src/ast/MethodWithoutParametersNode.cpp +++ b/src/ast/MethodWithoutParametersNode.cpp @@ -5,13 +5,3 @@ void MethodWithoutParametersNode::accept(AstVisitor &visitor) const { visitor.visit(*this); } - -Operand MethodWithoutParametersNode::generateIR(CFG &graph, SymbolTable &st) { - auto *currentClass = dynamic_cast(st.getCurrentRecord()); - st.enterMethodScope(id->value); - graph.setCurrentBlock( - graph.addMethodRootBlock(currentClass->getID(), id->value)); - body->generateIR(graph, st); - st.exitScope(); - return graph.getCurrentBlock()->getName(); -} diff --git a/src/ast/MethodWithoutParametersNode.hpp b/src/ast/MethodWithoutParametersNode.hpp index ea81ed7..e203e6a 100644 --- a/src/ast/MethodWithoutParametersNode.hpp +++ b/src/ast/MethodWithoutParametersNode.hpp @@ -23,8 +23,6 @@ class MethodWithoutParametersNode : public Node { return type->value; } [[nodiscard]] const Node &getBodyNode() const { return *body; } - - Operand generateIR(CFG &graph, SymbolTable &st) override; }; #endif diff --git a/src/ast/Node.cpp b/src/ast/Node.cpp index b4d55e9..c0fe6d4 100644 --- a/src/ast/Node.cpp +++ b/src/ast/Node.cpp @@ -8,13 +8,6 @@ bool Node::buildTable(SymbolTable &st) const { return build_symbol_table(*this, st).ok(); } -Operand Node::generateIR(CFG &graph, SymbolTable &st) { - for (auto &child : children) { - child->generateIR(graph, st); - } - return "foobar"; -} - void Node::accept(AstVisitor &visitor) const { visitor.visit(*this); } void Node::print(int depth = 0) const { diff --git a/src/ast/Node.h b/src/ast/Node.h index aa18358..38a2d4a 100644 --- a/src/ast/Node.h +++ b/src/ast/Node.h @@ -10,9 +10,8 @@ #include #include -#include "ir/CFG.hpp" - class AstVisitor; +class SymbolTable; class Node { public: @@ -30,8 +29,6 @@ class Node { virtual bool buildTable(SymbolTable &st) const; - virtual Operand generateIR(CFG &graph, SymbolTable &st); - virtual void accept(AstVisitor &visitor) const; void print(int depth) const; diff --git a/src/ast/NotNode.cpp b/src/ast/NotNode.cpp index cb42f20..8c6f18e 100644 --- a/src/ast/NotNode.cpp +++ b/src/ast/NotNode.cpp @@ -1,10 +1,2 @@ #include "ast/NotNode.hpp" -#include "ir/Tac.hpp" -Operand NotNode::generateIR(CFG &graph, SymbolTable &st) { - auto rhsName = expr->generateIR(graph, st); - auto name = graph.getTemporaryName(); - st.addBooleanVariable(name); - graph.addInstruction(new NotTac(name, rhsName)); - return name; -} diff --git a/src/ast/NotNode.hpp b/src/ast/NotNode.hpp index 4928b0a..8884f6c 100644 --- a/src/ast/NotNode.hpp +++ b/src/ast/NotNode.hpp @@ -11,7 +11,6 @@ class NotNode : public Node { : Node("Negated expression", l) { expr = append_child(std::move(expr_)); } - Operand generateIR(CFG &graph, SymbolTable &st) override; }; #endif // NOTNODE_HPP diff --git a/src/ast/StatementNode.cpp b/src/ast/StatementNode.cpp index a32031e..cfc9956 100644 --- a/src/ast/StatementNode.cpp +++ b/src/ast/StatementNode.cpp @@ -1,23 +1,2 @@ #include "ast/StatementNode.hpp" -#include "ir/Tac.hpp" -Operand AssignNode::generateIR(CFG &graph, SymbolTable &st) { - auto rhsName = expr->generateIR(graph, st); - auto lhsName = id->value; - graph.addInstruction(new CopyTac(rhsName, lhsName)); - return lhsName; -} - -Operand ArrayAssignNode::generateIR(CFG &graph, SymbolTable &st) { - auto indexName = indexExpr->generateIR(graph, st); - auto rhsName = rightExpr->generateIR(graph, st); - auto arrayName = id->value; - graph.addInstruction(new ArrayCopyTac(arrayName, indexName, rhsName)); - return arrayName; -} - -Operand PrintNode::generateIR(CFG &graph, SymbolTable &st) { - const auto &value = expr->generateIR(graph, st); - graph.addInstruction(new PrintTac(value)); - return ""; -} diff --git a/src/ast/StatementNode.hpp b/src/ast/StatementNode.hpp index b55177f..6551c54 100644 --- a/src/ast/StatementNode.hpp +++ b/src/ast/StatementNode.hpp @@ -13,7 +13,6 @@ class AssignNode : public Node { id = append_child(std::move(id_)); expr = append_child(std::move(expr_)); } - Operand generateIR(CFG &graph, SymbolTable &st) override; }; class ArrayAssignNode : public Node { @@ -29,7 +28,6 @@ class ArrayAssignNode : public Node { indexExpr = append_child(std::move(indexExpr_)); } [[nodiscard]] const Node &getRightExprNode() const { return *rightExpr; } - Operand generateIR(CFG &graph, SymbolTable &st) override; }; class PrintNode : public Node { @@ -39,7 +37,6 @@ class PrintNode : public Node { PrintNode(std::unique_ptr expr_, int l) : Node("Print", l) { expr = append_child(std::move(expr_)); } - Operand generateIR(CFG &graph, SymbolTable &st) override; }; #endif diff --git a/src/ast/ThisNode.cpp b/src/ast/ThisNode.cpp index dd94062..f30197d 100644 --- a/src/ast/ThisNode.cpp +++ b/src/ast/ThisNode.cpp @@ -1,4 +1,2 @@ #include "ast/ThisNode.hpp" -#include "ir/Tac.hpp" -Operand ThisNode::generateIR(CFG &graph, SymbolTable &st) { return value; } diff --git a/src/ast/ThisNode.hpp b/src/ast/ThisNode.hpp index 27c401b..9e73a11 100644 --- a/src/ast/ThisNode.hpp +++ b/src/ast/ThisNode.hpp @@ -8,7 +8,6 @@ class ThisNode : public Node { public: ThisNode(int l) : Node("this", l) {} - Operand generateIR(CFG &graph, SymbolTable &st) override; }; #endif // THISNODE_HPP diff --git a/src/ir/IRGenerationVisitor.cpp b/src/ir/IRGenerationVisitor.cpp new file mode 100644 index 0000000..83f59ed --- /dev/null +++ b/src/ir/IRGenerationVisitor.cpp @@ -0,0 +1,828 @@ +#include "ir/IRGenerationVisitor.hpp" + +#include +#include +#include +#include +#include +#include + +#include "ast/ArithmeticExpressionNode.hpp" +#include "ast/ArrayAccessNode.hpp" +#include "ast/ArrayLengthNode.hpp" +#include "ast/BooleanExpressionNode.hpp" +#include "ast/BooleanNode.hpp" +#include "ast/ClassAllocationNode.hpp" +#include "ast/ClassNode.hpp" +#include "ast/ControlStatementNode.hpp" +#include "ast/IdentifierNode.hpp" +#include "ast/IntegerArrayAllocationNode.hpp" +#include "ast/IntegerNode.hpp" +#include "ast/LogicalExpressionNode.hpp" +#include "ast/MainClassNode.hpp" +#include "ast/MethodBodyNode.hpp" +#include "ast/MethodCallNode.hpp" +#include "ast/MethodCallWithoutArgumentsNode.hpp" +#include "ast/MethodNode.hpp" +#include "ast/MethodWithoutParametersNode.hpp" +#include "ast/Node.h" +#include "ast/NotNode.hpp" +#include "ast/StatementNode.hpp" +#include "ast/ThisNode.hpp" +#include "ir/ArithmeticTac.hpp" +#include "ir/CFG.hpp" +#include "ir/LogicalTac.hpp" +#include "ir/Tac.hpp" +#include "semantic/Class.hpp" +#include "semantic/Method.hpp" +#include "semantic/SymbolTable.hpp" + +namespace { + +[[nodiscard]] const Node *child_at(const Node &node, std::size_t index) { + if (index >= node.children.size()) { + return nullptr; + } + + auto it = node.children.cbegin(); + std::advance(it, static_cast(index)); + return it->get(); +} + +class ScopeExit { + public: + explicit ScopeExit(SymbolTable &table) : table_(&table) {} + + ~ScopeExit() { + if (table_ != nullptr) { + table_->exitScope(); + } + } + + ScopeExit(const ScopeExit &) = delete; + ScopeExit &operator=(const ScopeExit &) = delete; + + private: + SymbolTable *table_ = nullptr; +}; + +} // namespace + +void IRGenerationVisitor::emit_error(int line, std::string message) { + error_count_ += 1; + + if (sink_ == nullptr) { + return; + } + + const auto line_no = static_cast(std::max(line, 1)); + const lexing::SourceSpan span{ + .begin = {.offset = 0, .line = line_no, .column = 1}, + .end = {.offset = 0, .line = line_no, .column = 1}, + }; + + sink_->emit({.severity = lexing::Severity::Error, + .message = std::move(message), + .span = span}); +} + +Operand IRGenerationVisitor::eval(const Node &node) { + node.accept(*this); + + if (const auto it = values_.find(&node); it != values_.end()) { + return it->second; + } + + return std::string{}; +} + +void IRGenerationVisitor::set_value(const Node &node, Operand value) { + values_[&node] = std::move(value); +} + +void IRGenerationVisitor::visit_generic(const Node &node) { + for (const auto &child : node.children) { + (void)eval(*child); + } + + set_value(node, std::string{}); +} + +void IRGenerationVisitor::visit(const ClassNode &node) { + auto *current_class = table_.lookupClass(node.getClassName()); + if (current_class == nullptr) { + emit_error(node.lineno, "Error: (line " + std::to_string(node.lineno) + + ") IR generation could not find class '" + + node.getClassName() + "'.\n"); + set_value(node, std::string{}); + return; + } + + table_.enterClassScope(current_class); + ScopeExit exit_scope(table_); + + (void)eval(node.getBodyNode()); + set_value(node, std::string{}); +} + +void IRGenerationVisitor::visit(const MainClassNode &node) { + table_.enterClassScope(node.getMainClassName()); + ScopeExit exit_class_scope(table_); + + table_.enterMethodScope("main"); + ScopeExit exit_method_scope(table_); + + graph_.setCurrentBlock( + graph_.addMethodRootBlock(node.getMainClassName(), "main")); + + (void)eval(node.getBodyNode()); + + auto *current_block = graph_.getCurrentBlock(); + set_value(node, current_block != nullptr ? Operand{current_block->getName()} + : Operand{std::string{}}); +} + +void IRGenerationVisitor::visit(const MethodNode &node) { + auto *current_class = dynamic_cast(table_.getCurrentRecord()); + if (current_class == nullptr) { + emit_error(node.lineno, + "Error: (line " + std::to_string(node.lineno) + + ") IR generation expected class scope for method '" + + node.getMethodName() + "'.\n"); + set_value(node, std::string{}); + return; + } + + auto *current_method = table_.lookupMethod(node.getMethodName()); + if (current_method == nullptr) { + emit_error(node.lineno, "Error: (line " + std::to_string(node.lineno) + + ") IR generation could not find method '" + + node.getMethodName() + "'.\n"); + set_value(node, std::string{}); + return; + } + + table_.enterMethodScope(current_method); + ScopeExit exit_scope(table_); + + graph_.setCurrentBlock(graph_.addMethodRootBlock(current_class->getID(), + node.getMethodName())); + + (void)eval(node.getBodyNode()); + + auto *current_block = graph_.getCurrentBlock(); + set_value(node, current_block != nullptr ? Operand{current_block->getName()} + : Operand{std::string{}}); +} + +void IRGenerationVisitor::visit(const MethodWithoutParametersNode &node) { + auto *current_class = dynamic_cast(table_.getCurrentRecord()); + if (current_class == nullptr) { + emit_error(node.lineno, + "Error: (line " + std::to_string(node.lineno) + + ") IR generation expected class scope for method '" + + node.getMethodName() + "'.\n"); + set_value(node, std::string{}); + return; + } + + auto *current_method = table_.lookupMethod(node.getMethodName()); + if (current_method == nullptr) { + emit_error(node.lineno, "Error: (line " + std::to_string(node.lineno) + + ") IR generation could not find method '" + + node.getMethodName() + "'.\n"); + set_value(node, std::string{}); + return; + } + + table_.enterMethodScope(current_method); + ScopeExit exit_scope(table_); + + graph_.setCurrentBlock(graph_.addMethodRootBlock(current_class->getID(), + node.getMethodName())); + + (void)eval(node.getBodyNode()); + + auto *current_block = graph_.getCurrentBlock(); + set_value(node, current_block != nullptr ? Operand{current_block->getName()} + : Operand{std::string{}}); +} + +void IRGenerationVisitor::visit(const Node &node) { + if (const auto *class_node = dynamic_cast(&node)) { + visit(*class_node); + return; + } + if (const auto *main_class_node = + dynamic_cast(&node)) { + visit(*main_class_node); + return; + } + if (const auto *method_node = dynamic_cast(&node)) { + visit(*method_node); + return; + } + if (const auto *method_without_parameters_node = + dynamic_cast(&node)) { + visit(*method_without_parameters_node); + return; + } + + if (const auto *plus_node = dynamic_cast(&node)) { + const auto *lhs = child_at(*plus_node, 0); + const auto *rhs = child_at(*plus_node, 1); + if (lhs == nullptr || rhs == nullptr) { + set_value(node, std::string{}); + return; + } + + const auto lhs_name = eval(*lhs); + const auto rhs_name = eval(*rhs); + const auto name = graph_.getTemporaryName(); + table_.addIntegerVariable(name); + graph_.addInstruction(new AddTac(name, lhs_name, rhs_name)); + set_value(node, name); + return; + } + + if (const auto *minus_node = dynamic_cast(&node)) { + const auto *lhs = child_at(*minus_node, 0); + const auto *rhs = child_at(*minus_node, 1); + if (lhs == nullptr || rhs == nullptr) { + set_value(node, std::string{}); + return; + } + + const auto lhs_name = eval(*lhs); + const auto rhs_name = eval(*rhs); + const auto name = graph_.getTemporaryName(); + table_.addIntegerVariable(name); + graph_.addInstruction(new SubtractTac(name, lhs_name, rhs_name)); + set_value(node, name); + return; + } + + if (const auto *multiplication_node = + dynamic_cast(&node)) { + const auto *lhs = child_at(*multiplication_node, 0); + const auto *rhs = child_at(*multiplication_node, 1); + if (lhs == nullptr || rhs == nullptr) { + set_value(node, std::string{}); + return; + } + + const auto lhs_name = eval(*lhs); + const auto rhs_name = eval(*rhs); + const auto name = graph_.getTemporaryName(); + table_.addIntegerVariable(name); + graph_.addInstruction(new MultiplyTac(name, lhs_name, rhs_name)); + set_value(node, name); + return; + } + + if (const auto *division_node = dynamic_cast(&node)) { + const auto *lhs = child_at(*division_node, 0); + const auto *rhs = child_at(*division_node, 1); + if (lhs == nullptr || rhs == nullptr) { + set_value(node, std::string{}); + return; + } + + const auto lhs_name = eval(*lhs); + const auto rhs_name = eval(*rhs); + const auto name = graph_.getTemporaryName(); + table_.addIntegerVariable(name); + graph_.addInstruction(new DivideTac(name, lhs_name, rhs_name)); + set_value(node, name); + return; + } + + if (const auto *less_than_node = + dynamic_cast(&node)) { + const auto *lhs = child_at(*less_than_node, 0); + const auto *rhs = child_at(*less_than_node, 1); + if (lhs == nullptr || rhs == nullptr) { + set_value(node, std::string{}); + return; + } + + const auto lhs_name = eval(*lhs); + const auto rhs_name = eval(*rhs); + const auto name = graph_.getTemporaryName(); + table_.addBooleanVariable(name); + graph_.addInstruction(new LessThanTac(name, lhs_name, rhs_name)); + set_value(node, name); + return; + } + + if (const auto *greater_than_node = + dynamic_cast(&node)) { + const auto *lhs = child_at(*greater_than_node, 0); + const auto *rhs = child_at(*greater_than_node, 1); + if (lhs == nullptr || rhs == nullptr) { + set_value(node, std::string{}); + return; + } + + const auto lhs_name = eval(*lhs); + const auto rhs_name = eval(*rhs); + const auto name = graph_.getTemporaryName(); + table_.addBooleanVariable(name); + graph_.addInstruction(new GreaterThanTac(name, lhs_name, rhs_name)); + set_value(node, name); + return; + } + + if (const auto *equal_to_node = dynamic_cast(&node)) { + const auto *lhs = child_at(*equal_to_node, 0); + const auto *rhs = child_at(*equal_to_node, 1); + if (lhs == nullptr || rhs == nullptr) { + set_value(node, std::string{}); + return; + } + + const auto lhs_name = eval(*lhs); + const auto rhs_name = eval(*rhs); + const auto name = graph_.getTemporaryName(); + table_.addBooleanVariable(name); + graph_.addInstruction(new EqualToTac(name, lhs_name, rhs_name)); + set_value(node, name); + return; + } + + if (const auto *not_node = dynamic_cast(&node)) { + const auto *rhs = child_at(*not_node, 0); + if (rhs == nullptr) { + set_value(node, std::string{}); + return; + } + + const auto rhs_name = eval(*rhs); + const auto name = graph_.getTemporaryName(); + table_.addBooleanVariable(name); + graph_.addInstruction(new NotTac(name, rhs_name)); + set_value(node, name); + return; + } + + if (const auto *and_node = dynamic_cast(&node)) { + const auto *lhs = child_at(*and_node, 0); + const auto *rhs = child_at(*and_node, 1); + if (lhs == nullptr || rhs == nullptr) { + set_value(node, std::string{}); + return; + } + + const auto lhs_name = eval(*lhs); + const auto name = graph_.getTemporaryName(); + table_.addBooleanVariable(name); + + auto *rhs_eval_block = graph_.newBlock(); + auto *true_block = graph_.newBlock(); + auto *false_block = graph_.newBlock(); + auto *join_block = graph_.newBlock(); + + auto *entry_block = graph_.getCurrentBlock(); + graph_.addInstruction( + new CondJumpTac(false_block->getName(), lhs_name)); + graph_.addInstruction(new JumpTac(rhs_eval_block->getName())); + entry_block->setTrueBlock(rhs_eval_block); + entry_block->setFalseBlock(false_block); + + graph_.setCurrentBlock(rhs_eval_block); + const auto rhs_name = eval(*rhs); + graph_.addInstruction( + new CondJumpTac(false_block->getName(), rhs_name)); + graph_.addInstruction(new JumpTac(true_block->getName())); + rhs_eval_block->setTrueBlock(true_block); + rhs_eval_block->setFalseBlock(false_block); + + graph_.setCurrentBlock(true_block); + graph_.addInstruction(new CopyTac(1, name)); + graph_.addInstruction(new JumpTac(join_block->getName())); + true_block->setTrueBlock(join_block); + + graph_.setCurrentBlock(false_block); + graph_.addInstruction(new CopyTac(0, name)); + graph_.addInstruction(new JumpTac(join_block->getName())); + false_block->setTrueBlock(join_block); + + graph_.setCurrentBlock(join_block); + set_value(node, name); + return; + } + + if (const auto *or_node = dynamic_cast(&node)) { + const auto *lhs = child_at(*or_node, 0); + const auto *rhs = child_at(*or_node, 1); + if (lhs == nullptr || rhs == nullptr) { + set_value(node, std::string{}); + return; + } + + const auto lhs_name = eval(*lhs); + const auto name = graph_.getTemporaryName(); + table_.addBooleanVariable(name); + + auto *rhs_eval_block = graph_.newBlock(); + auto *true_block = graph_.newBlock(); + auto *false_block = graph_.newBlock(); + auto *join_block = graph_.newBlock(); + + auto *entry_block = graph_.getCurrentBlock(); + graph_.addInstruction( + new CondJumpTac(rhs_eval_block->getName(), lhs_name)); + graph_.addInstruction(new JumpTac(true_block->getName())); + entry_block->setTrueBlock(true_block); + entry_block->setFalseBlock(rhs_eval_block); + + graph_.setCurrentBlock(rhs_eval_block); + const auto rhs_name = eval(*rhs); + graph_.addInstruction( + new CondJumpTac(false_block->getName(), rhs_name)); + graph_.addInstruction(new JumpTac(true_block->getName())); + rhs_eval_block->setTrueBlock(true_block); + rhs_eval_block->setFalseBlock(false_block); + + graph_.setCurrentBlock(true_block); + graph_.addInstruction(new CopyTac(1, name)); + graph_.addInstruction(new JumpTac(join_block->getName())); + true_block->setTrueBlock(join_block); + + graph_.setCurrentBlock(false_block); + graph_.addInstruction(new CopyTac(0, name)); + graph_.addInstruction(new JumpTac(join_block->getName())); + false_block->setTrueBlock(join_block); + + graph_.setCurrentBlock(join_block); + set_value(node, name); + return; + } + + if (const auto *identifier_node = + dynamic_cast(&node)) { + set_value(*identifier_node, + static_cast(*identifier_node).value); + return; + } + + if (const auto *integer_node = dynamic_cast(&node)) { + set_value(*integer_node, + std::stoi(static_cast(*integer_node).value)); + return; + } + + if (dynamic_cast(&node) != nullptr) { + set_value(node, 1); + return; + } + + if (dynamic_cast(&node) != nullptr) { + set_value(node, 0); + return; + } + + if (dynamic_cast(&node) != nullptr) { + set_value(node, std::string{"this"}); + return; + } + + if (const auto *class_allocation_node = + dynamic_cast(&node)) { + const auto name = graph_.getTemporaryName(); + table_.addVariable(class_allocation_node->value, name); + graph_.addInstruction(new NewTac(name, class_allocation_node->value)); + set_value(node, name); + return; + } + + if (const auto *array_allocation_node = + dynamic_cast(&node)) { + const auto name = graph_.getTemporaryName(); + table_.addVariable("int[]", name); + const auto length_name = eval(array_allocation_node->getLengthNode()); + graph_.addInstruction(new NewArrayTac(name, length_name)); + set_value(node, name); + return; + } + + if (const auto *array_access_node = + dynamic_cast(&node)) { + const auto *array = child_at(*array_access_node, 0); + const auto *index = child_at(*array_access_node, 1); + if (array == nullptr || index == nullptr) { + set_value(node, std::string{}); + return; + } + + const auto array_name = eval(*array); + const auto index_name = eval(*index); + const auto name = graph_.getTemporaryName(); + table_.addIntegerVariable(name); + graph_.addInstruction(new ArrayAccessTac(name, array_name, index_name)); + set_value(node, name); + return; + } + + if (const auto *array_length_node = + dynamic_cast(&node)) { + const auto name = graph_.getTemporaryName(); + table_.addIntegerVariable(name); + const auto array_name = eval(array_length_node->getArrayNode()); + graph_.addInstruction(new ArrayLengthTac(name, array_name)); + set_value(node, name); + return; + } + + if (const auto *method_call_node = + dynamic_cast(&node)) { + const auto *object = child_at(*method_call_node, 0); + const auto *identifier = child_at(*method_call_node, 1); + const auto *expr_list = child_at(*method_call_node, 2); + if (object == nullptr || identifier == nullptr || + expr_list == nullptr) { + set_value(node, std::string{}); + return; + } + + const auto *caller_type = graph_.typeOf(*object); + assert(caller_type != nullptr && + "Type information missing for method call receiver"); + if (caller_type == nullptr || caller_type->empty()) { + set_value(node, std::string{}); + return; + } + + auto *calling_class = table_.lookupClass(*caller_type); + if (calling_class == nullptr) { + set_value(node, std::string{}); + return; + } + + auto const *method = calling_class->lookupMethod(identifier->value); + if (method == nullptr) { + set_value(node, std::string{}); + return; + } + + const auto &method_type = method->getType(); + const auto receiver = eval(*object); + + for (const auto &arg : expr_list->children) { + const auto arg_name = eval(*arg); + graph_.addInstruction(new ParamTac(arg_name)); + } + + const auto name = graph_.getTemporaryName(); + table_.addVariable(method_type, name); + + const auto method_target = *caller_type + "." + identifier->value; + const auto arg_count = static_cast(expr_list->children.size()); + graph_.addInstruction( + new MethodCallTac(name, receiver, method_target, arg_count)); + set_value(node, name); + return; + } + + if (const auto *method_call_without_arguments_node = + dynamic_cast(&node)) { + const auto *object = child_at(*method_call_without_arguments_node, 0); + const auto *identifier = + child_at(*method_call_without_arguments_node, 1); + if (object == nullptr || identifier == nullptr) { + set_value(node, std::string{}); + return; + } + + const auto *caller_type = graph_.typeOf(*object); + assert(caller_type != nullptr && + "Type information missing for method call receiver"); + if (caller_type == nullptr || caller_type->empty()) { + set_value(node, std::string{}); + return; + } + + auto *calling_class = table_.lookupClass(*caller_type); + if (calling_class == nullptr) { + set_value(node, std::string{}); + return; + } + + auto const *method = calling_class->lookupMethod(identifier->value); + if (method == nullptr) { + set_value(node, std::string{}); + return; + } + + const auto &method_type = method->getType(); + const auto receiver = eval(*object); + + const auto name = graph_.getTemporaryName(); + table_.addVariable(method_type, name); + const auto method_target = *caller_type + "." + identifier->value; + graph_.addInstruction( + new MethodCallTac(name, receiver, method_target, 0)); + set_value(node, name); + return; + } + + if (const auto *assign_node = dynamic_cast(&node)) { + const auto *identifier = child_at(*assign_node, 0); + const auto *expr = child_at(*assign_node, 1); + if (identifier == nullptr || expr == nullptr) { + set_value(node, std::string{}); + return; + } + + const auto rhs_name = eval(*expr); + const auto &lhs_name = identifier->value; + graph_.addInstruction(new CopyTac(rhs_name, lhs_name)); + set_value(node, lhs_name); + return; + } + + if (const auto *array_assign_node = + dynamic_cast(&node)) { + const auto *identifier = child_at(*array_assign_node, 0); + const auto *index_expr = child_at(*array_assign_node, 1); + if (identifier == nullptr || index_expr == nullptr) { + set_value(node, std::string{}); + return; + } + + const auto index_name = eval(*index_expr); + const auto rhs_name = eval(array_assign_node->getRightExprNode()); + const auto &array_name = identifier->value; + graph_.addInstruction( + new ArrayCopyTac(array_name, index_name, rhs_name)); + set_value(node, array_name); + return; + } + + if (const auto *print_node = dynamic_cast(&node)) { + const auto *expr = child_at(*print_node, 0); + if (expr == nullptr) { + set_value(node, std::string{}); + return; + } + + const auto value = eval(*expr); + graph_.addInstruction(new PrintTac(value)); + set_value(node, std::string{}); + return; + } + + if (const auto *if_node = dynamic_cast(&node)) { + const auto *cond = child_at(*if_node, 0); + const auto *stmt = child_at(*if_node, 1); + if (cond == nullptr || stmt == nullptr) { + set_value(node, std::string{}); + return; + } + + auto *true_block = graph_.newBlock(); + auto *join_block = graph_.newBlock(); + const auto &join_label = join_block->getName(); + const auto &true_label = true_block->getName(); + + const auto cond_name = eval(*cond); + graph_.addInstruction(new CondJumpTac(join_label, cond_name)); + graph_.addInstruction(new JumpTac(true_label)); + + auto *current_block = graph_.getCurrentBlock(); + current_block->setTrueBlock(true_block); + current_block->setFalseBlock(join_block); + + graph_.setCurrentBlock(true_block); + (void)eval(*stmt); + graph_.addInstruction(new JumpTac(join_label)); + graph_.getCurrentBlock()->setTrueBlock(join_block); + + graph_.setCurrentBlock(join_block); + + set_value(node, std::string{}); + return; + } + + if (const auto *if_else_node = dynamic_cast(&node)) { + const auto *cond = child_at(*if_else_node, 0); + const auto *stmt = child_at(*if_else_node, 1); + const auto *else_stmt = child_at(*if_else_node, 2); + if (cond == nullptr || stmt == nullptr || else_stmt == nullptr) { + set_value(node, std::string{}); + return; + } + + auto *true_block = graph_.newBlock(); + auto *false_block = graph_.newBlock(); + auto *join_block = graph_.newBlock(); + + const auto &false_label = false_block->getName(); + const auto &join_label = join_block->getName(); + + const auto cond_name = eval(*cond); + graph_.addInstruction(new CondJumpTac(false_label, cond_name)); + graph_.addInstruction(new JumpTac(true_block->getName())); + + auto *current_block = graph_.getCurrentBlock(); + current_block->setTrueBlock(true_block); + current_block->setFalseBlock(false_block); + + graph_.setCurrentBlock(true_block); + (void)eval(*stmt); + graph_.addInstruction(new JumpTac(join_label)); + graph_.getCurrentBlock()->setTrueBlock(join_block); + + graph_.setCurrentBlock(false_block); + (void)eval(*else_stmt); + graph_.addInstruction(new JumpTac(join_label)); + graph_.getCurrentBlock()->setTrueBlock(join_block); + + graph_.setCurrentBlock(join_block); + + set_value(node, std::string{}); + return; + } + + if (const auto *while_node = dynamic_cast(&node)) { + const auto *cond = child_at(*while_node, 0); + const auto *stmt = child_at(*while_node, 1); + if (cond == nullptr || stmt == nullptr) { + set_value(node, std::string{}); + return; + } + + auto *header_block = graph_.newBlock(); + const auto &header_label = header_block->getName(); + auto *body_block = graph_.newBlock(); + body_block->setTrueBlock(header_block); + auto *join_block = graph_.newBlock(); + + auto *current_block = graph_.getCurrentBlock(); + current_block->setTrueBlock(header_block); + graph_.addInstruction(new JumpTac(header_label)); + + graph_.setCurrentBlock(header_block); + const auto cond_name = eval(*cond); + auto *condition_block = graph_.getCurrentBlock(); + graph_.addInstruction( + new CondJumpTac(join_block->getName(), cond_name)); + graph_.addInstruction(new JumpTac(body_block->getName())); + + graph_.setCurrentBlock(body_block); + (void)eval(*stmt); + graph_.getCurrentBlock()->setTrueBlock(header_block); + graph_.addInstruction(new JumpTac(header_label)); + + condition_block->setTrueBlock(body_block); + condition_block->setFalseBlock(join_block); + + graph_.setCurrentBlock(join_block); + + set_value(node, std::string{}); + return; + } + + if (const auto *method_body_node = + dynamic_cast(&node)) { + const auto *body = child_at(*method_body_node, 0); + const auto *return_value = child_at(*method_body_node, 1); + if (body == nullptr || return_value == nullptr) { + set_value(node, std::string{}); + return; + } + + (void)eval(*body); + const auto name = eval(*return_value); + graph_.addInstruction(new ReturnTac(name)); + set_value(node, name); + return; + } + + if (const auto *return_only_method_body_node = + dynamic_cast(&node)) { + const auto *return_value = child_at(*return_only_method_body_node, 0); + if (return_value == nullptr) { + set_value(node, std::string{}); + return; + } + + const auto name = eval(*return_value); + graph_.addInstruction(new ReturnTac(name)); + set_value(node, name); + return; + } + + visit_generic(node); +} + +IRGenerationResult generate_ir(const Node &root, CFG &graph, SymbolTable &table, + lexing::DiagnosticSink *sink) { + while (table.getParentScope() != nullptr) { + table.exitScope(); + } + + IRGenerationVisitor visitor(graph, table, sink); + root.accept(visitor); + return visitor.result(); +} diff --git a/src/ir/IRGenerationVisitor.hpp b/src/ir/IRGenerationVisitor.hpp new file mode 100644 index 0000000..93493ba --- /dev/null +++ b/src/ir/IRGenerationVisitor.hpp @@ -0,0 +1,58 @@ +#ifndef IR_GENERATION_VISITOR_HPP +#define IR_GENERATION_VISITOR_HPP + +#include +#include + +#include "ast/AstVisitor.hpp" +#include "ir/Tac.hpp" +#include "lexing/Diagnostics.hpp" + +class CFG; +class Node; +class SymbolTable; + +class ClassNode; +class MainClassNode; +class MethodNode; +class MethodWithoutParametersNode; + +struct IRGenerationResult { + int error_count = 0; + + [[nodiscard]] bool ok() const { return error_count == 0; } +}; + +class IRGenerationVisitor : public AstVisitor { + public: + explicit IRGenerationVisitor(CFG &graph, SymbolTable &table, + lexing::DiagnosticSink *sink = nullptr) + : graph_(graph), table_(table), sink_(sink) {} + + [[nodiscard]] IRGenerationResult result() const { + return {.error_count = error_count_}; + } + + void visit(const Node &node) override; + void visit(const ClassNode &node) override; + void visit(const MainClassNode &node) override; + void visit(const MethodNode &node) override; + void visit(const MethodWithoutParametersNode &node) override; + + private: + CFG &graph_; + SymbolTable &table_; + lexing::DiagnosticSink *sink_ = nullptr; + int error_count_ = 0; + std::unordered_map values_; + + [[nodiscard]] Operand eval(const Node &node); + void set_value(const Node &node, Operand value); + void visit_generic(const Node &node); + void emit_error(int line, std::string message); +}; + +IRGenerationResult generate_ir(const Node &root, CFG &graph, SymbolTable &table, + lexing::DiagnosticSink *sink = nullptr); + +#endif diff --git a/src/main.cpp b/src/main.cpp index cb7ddc4..e768d30 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,6 +10,7 @@ namespace fs = std::filesystem; #include "ast/Node.h" #include "bytecode/BytecodeProgram.hpp" #include "ir/CFG.hpp" +#include "ir/IRGenerationVisitor.hpp" #include "lexing/LegacyDiagnostics.hpp" #include "lexing/Lexer.hpp" #include "lexing/SourceBuffer.hpp" @@ -309,7 +310,11 @@ int main(int argc, char **argv) { return 1; } - root->generateIR(graph, st); + const auto ir_result = generate_ir(*root, graph, st, &semantic_diag); + if (!ir_result.ok()) { + std::cout << "IR generation failed.\n"; + return errCodes::SEMANTIC_ERROR; + } graph.printGraphviz(controlFlowGraph); std::ofstream stGraph(outputDirectory / "st.dot");