commit 5c1f937a7eb7a9cc9cd86cb69b3263f41f24408f
parent 2cfc45ff22cd9b6166de3cf963aceede21b358aa
Author: Cori Barker <coribarker2@gmail.com>
Date: Sun, 22 Feb 2026 22:24:27 +0000
Partially completed lots of changes, refactoring most of the files
Diffstat:
30 files changed, 913 insertions(+), 756 deletions(-)
diff --git a/include/ast_node.hpp b/include/ast_node.hpp
@@ -0,0 +1,36 @@
+#pragma once
+
+#include "node_type.hpp"
+#include "type.hpp"
+
+#include <string>
+#include <vector>
+#include <memory>
+
+class ASTNode {
+public:
+ int line;
+ int column;
+
+ virtual ~ASTNode() = default;
+};
+
+class ProgramNode : ASTNode {
+public:
+ std::vector<ASTNode> function_declarations;
+
+ explicit ProgramNode(std::vector<ASTNode> f) : function_declarations(f) { }
+};
+
+class FunctionDeclNode : ASTNode {
+ Type type;
+ std::vector<ParameterNode> parameters;
+ std::vector<ASTNode> body;
+
+ FunctionDeclNode(std::string t,std::vector<ASTNode> p, std::vector<ASTNode> b) : type(t), parameters(p), body(b) { }
+};
+
+class ParameterNode : ASTNode {
+ std::string name;
+ std::string type;
+};
diff --git a/include/lexer.hpp b/include/lexer.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "token.hpp"
+
+#include <vector>
+#include <string>
+
+class Lexer {
+public:
+ explicit Lexer (const std::string& src);
+
+ std::vector<Token> tokenise();
+
+private:
+ int line;
+ int column;
+ int position;
+ std::string src;
+ std::vector<Token> tokens;
+
+ char advance();
+ void skipWhitespace();
+ void skipComment();
+};
diff --git a/include/lexer/lexer.hpp b/include/lexer/lexer.hpp
@@ -1,27 +0,0 @@
-#ifndef LEXER_H
-#define LEXER_H
-
-#include "token.hpp"
-
-#include <vector>
-#include <string>
-
-class Lexer {
-public:
- explicit Lexer (const std::string& src);
-
- std::vector<Token> tokenise();
-
-private:
- int line;
- int column;
- int position;
- std::string src;
- std::vector<Token> tokens;
-
- char advance();
- void skipWhitespace();
- void skipComment();
-};
-
-#endif
diff --git a/include/lexer/token.hpp b/include/lexer/token.hpp
@@ -1,17 +0,0 @@
-#ifndef TOKEN_H
-#define TOKEN_H
-
-#include "token_type.hpp"
-
-#include <string>
-
-struct Token {
- TokenType type;
- std::string value;
- int line;
- int column;
-
- Token(TokenType t, const std::string& val, int line, int col) : type{t}, value{val}, line{line}, column{col} {};
-};
-
-#endif
diff --git a/include/lexer/token_type.hpp b/include/lexer/token_type.hpp
@@ -1,25 +0,0 @@
-#ifndef TOKEN_TYPE_H
-#define TOKEN_TYPE_H
-
-enum class TokenType {
- INT,
- STRING,
-
- NUMBER,
- IDENTIFIER,
-
- PLUS,
- MINUS,
- MULTIPLY,
- DIVIDE,
-
- ASSIGN,
-
- SEMICOLON,
-
- END_OF_FILE,
- INVALID
-
-};
-
-#endif
diff --git a/include/parser.hpp b/include/parser.hpp
@@ -0,0 +1,28 @@
+#pragma once
+
+#include "lexer/token.hpp"
+#include "parser/ast_node.hpp"
+
+#include <vector>
+
+class Parser {
+public:
+ explicit Parser(const std::vector<Token>& tokens);
+ std::unique_ptr<Program> parse();
+
+private:
+ std::vector<Token> tokens_;
+ int position_;
+
+ std::unique_ptr<ASTNode> parseStatement();
+ std::unique_ptr<ASTNode> parseExpression();
+ std::unique_ptr<ASTNode> parseAddSub();
+ std::unique_ptr<ASTNode> parseMulDiv();
+ std::unique_ptr<ASTNode> parsePrimary();
+ std::unique_ptr<ASTNode> parseDeclaration();
+ std::unique_ptr<ASTNode> parseAssignment();
+ Token advance();
+ Token peek();
+ bool isAtEnd();
+ void error(std::string s);
+};
diff --git a/include/parser/ast_node.hpp b/include/parser/ast_node.hpp
@@ -1,70 +0,0 @@
-#ifndef AST_NODE_H
-#define AST_NODE_H
-
-#include "node_type.hpp"
-
-#include <string>
-#include <vector>
-#include <memory>
-
-class ASTNode {
-public:
- int line;
- int column;
-
- virtual ~ASTNode() = default;
-};
-
-class Program : public ASTNode {
-public:
- std::vector<std::unique_ptr<ASTNode>> declarations;
-};
-
-class Declaration : public ASTNode {
-public:
- std::string type;
- std::string var_name;
- std::unique_ptr<ASTNode> value;
-
- Declaration(std::string type, std::string var_name, std::unique_ptr<ASTNode> value = nullptr) : type(type), var_name(var_name), value(std::move(value)) {}
-};
-
-class Assignment : public ASTNode {
-public:
- std::string variable_name;
- std::unique_ptr<ASTNode> value;
-
- Assignment(std::string var, std::unique_ptr<ASTNode> val) : variable_name(var), value(std::move(val)) {}
-};
-
-class NumberLiteral : public ASTNode {
-public:
- double value;
-
- NumberLiteral(double val) : value(val) {}
-};
-
-class StringLiteral : public ASTNode {
-public:
- std::string value;
-
- StringLiteral(std::string val) : value(val) {}
-};
-
-class Identifier : public ASTNode {
-public:
- std::string name;
-
- Identifier(std::string name) : name(name) {}
-};
-
-class BinaryOp : public ASTNode {
-public:
- std::unique_ptr<ASTNode> left;
- std::string value;
- std::unique_ptr<ASTNode> right;
-
- BinaryOp(std::unique_ptr<ASTNode> left, std::string value, std::unique_ptr<ASTNode> right) : left(std::move(left)), value(std::move(value)), right(std::move(right)) {}
-};
-
-#endif
diff --git a/include/parser/node_type.hpp b/include/parser/node_type.hpp
@@ -1,10 +0,0 @@
-#ifndef NODE_TYPE_H
-#define NODE_TYPE_H
-
-enum class NodeType {
- PROGRAM,
- VARIABLE_DECLARATION,
- ASSIGNMENT,
-};
-
-#endif
diff --git a/include/parser/parser.hpp b/include/parser/parser.hpp
@@ -1,31 +0,0 @@
-#ifndef PARSER_H
-#define PARSER_H
-
-#include "lexer/token.hpp"
-#include "parser/ast_node.hpp"
-
-#include <vector>
-
-class Parser {
-public:
- explicit Parser(const std::vector<Token>& tokens);
- std::unique_ptr<Program> parse();
-
-private:
- std::vector<Token> tokens_;
- int position_;
-
- std::unique_ptr<ASTNode> parseStatement();
- std::unique_ptr<ASTNode> parseExpression();
- std::unique_ptr<ASTNode> parseAddSub();
- std::unique_ptr<ASTNode> parseMulDiv();
- std::unique_ptr<ASTNode> parsePrimary();
- std::unique_ptr<ASTNode> parseDeclaration();
- std::unique_ptr<ASTNode> parseAssignment();
- Token advance();
- Token peek();
- bool isAtEnd();
- void error(std::string s);
-};
-
-#endif
diff --git a/include/semantic/scope.hpp b/include/scope.hpp
diff --git a/include/semantic/semantic_analyzer.hpp b/include/semantic_analyzer.hpp
diff --git a/include/semantic/symbol.hpp b/include/symbol.hpp
diff --git a/include/semantic/symbol_table.hpp b/include/symbol_table.hpp
diff --git a/include/semantic/symbol_type.hpp b/include/symbol_type.hpp
diff --git a/include/token.hpp b/include/token.hpp
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "token_type.hpp"
+
+#include <string>
+
+struct Token {
+ TokenType type;
+ std::string value;
+ int line;
+ int column;
+
+ Token(TokenType t, const std::string& val, int line, int col) : type{t}, value{val}, line{line}, column{col} {};
+};
diff --git a/include/token_type.hpp b/include/token_type.hpp
@@ -0,0 +1,22 @@
+#pragma once
+
+enum class TokenType {
+ INT,
+ STRING,
+
+ NUMBER,
+ IDENTIFIER,
+
+ PLUS,
+ MINUS,
+ MULTIPLY,
+ DIVIDE,
+
+ ASSIGN,
+
+ SEMICOLON,
+
+ END_OF_FILE,
+ INVALID
+
+};
diff --git a/include/type.hpp b/include/type.hpp
@@ -0,0 +1,11 @@
+#pragma once
+
+enum struct Type {
+ INT,
+ CHAR,
+ BOOL,
+ STRING,
+ FLOAT,
+ DOUBLE,
+ VOID,
+};
diff --git a/src/lexer.cpp b/src/lexer.cpp
@@ -0,0 +1,103 @@
+#include "lexer.hpp"
+
+Lexer::Lexer(const std::string& src) : src(src), position(0), line(1), column(1) {}
+
+std::vector<Token> Lexer::tokenise() {
+ while (position < src.size()) {
+ if (std::isdigit(src[position])) {
+ std::string digit;
+ int original_column = column;
+
+ while (std::isdigit(src[position])) {
+ digit.push_back(src[position]);
+ advance();
+ }
+
+ tokens.push_back(Token(TokenType::NUMBER, digit, line, original_column));
+
+ } else if (std::isalpha(src[position])) {
+ if (src.substr(position, 3) == "int") {
+ tokens.push_back(Token(TokenType::INT, "int", line, column));
+ advance();
+ advance();
+ advance();
+
+ } else {
+ std::string identifier;
+ int original_column = column;
+
+ while (std::isalnum(src[position])) {
+ identifier.push_back(src[position]);
+ advance();
+ }
+
+ tokens.push_back(Token(TokenType::IDENTIFIER, identifier, line, original_column));
+ }
+
+ } else if (src[position] == '+') {
+ tokens.push_back(Token(TokenType::PLUS, std::string(1, src[position]), line, column));
+ advance();
+
+ } else if (src[position] == '-') {
+ tokens.push_back(Token(TokenType::MINUS, std::string(1, src[position]), line, column));
+ advance();
+
+ } else if (src[position] == '*') {
+ tokens.push_back(Token(TokenType::MULTIPLY, std::string(1, src[position]), line, column));
+ advance();
+
+ } else if (src[position] == '/') {
+ tokens.push_back(Token(TokenType::DIVIDE, std::string(1, src[position]), line, column));
+ advance();
+
+ } else if (src[position] == '=') {
+ tokens.push_back(Token(TokenType::ASSIGN, std::string(1, src[position]), line, column));
+ advance();
+
+ } else if (src[position] == ';') {
+ tokens.push_back(Token(TokenType::SEMICOLON, std::string(1, src[position]), line, column));
+ advance();
+
+ } else {
+ tokens.push_back(Token(TokenType::INVALID, std::string(1, src[position]), line, column));
+ advance();
+
+ }
+ skipComment();
+ skipWhitespace();
+
+ }
+ tokens.push_back(Token(TokenType::END_OF_FILE, std::string(), line, column));
+ return tokens;
+}
+
+char Lexer::advance() {
+ column++;
+ return src[position++];
+}
+
+void Lexer::skipWhitespace() {
+ while (src[position] == ' ' || src[position] == '\n') {
+ if (src[position] == ' ') {
+ position++;
+ column++;
+
+ } else if (src[position] == '\n') {
+ position++;
+ column = 1;
+ line++;
+ }
+ }
+}
+
+void Lexer::skipComment() {
+ if (src[position] == '/' && src[++position] == '/') {
+ while (src[position] != '\n') {
+ position++;
+ column++;
+ }
+ position++;
+ line += 1;
+ column = 1;
+ }
+}
diff --git a/src/lexer/lexer.cpp b/src/lexer/lexer.cpp
@@ -1,103 +0,0 @@
-#include "lexer/lexer.hpp"
-
-Lexer::Lexer(const std::string& src) : src(src), position(0), line(1), column(1) {}
-
-std::vector<Token> Lexer::tokenise() {
- while (position < src.size()) {
- if (std::isdigit(src[position])) {
- std::string digit;
- int original_column = column;
-
- while (std::isdigit(src[position])) {
- digit.push_back(src[position]);
- advance();
- }
-
- tokens.push_back(Token(TokenType::NUMBER, digit, line, original_column));
-
- } else if (std::isalpha(src[position])) {
- if (src.substr(position, 3) == "int") {
- tokens.push_back(Token(TokenType::INT, "int", line, column));
- advance();
- advance();
- advance();
-
- } else {
- std::string identifier;
- int original_column = column;
-
- while (std::isalnum(src[position])) {
- identifier.push_back(src[position]);
- advance();
- }
-
- tokens.push_back(Token(TokenType::IDENTIFIER, identifier, line, original_column));
- }
-
- } else if (src[position] == '+') {
- tokens.push_back(Token(TokenType::PLUS, std::string(1, src[position]), line, column));
- advance();
-
- } else if (src[position] == '-') {
- tokens.push_back(Token(TokenType::MINUS, std::string(1, src[position]), line, column));
- advance();
-
- } else if (src[position] == '*') {
- tokens.push_back(Token(TokenType::MULTIPLY, std::string(1, src[position]), line, column));
- advance();
-
- } else if (src[position] == '/') {
- tokens.push_back(Token(TokenType::DIVIDE, std::string(1, src[position]), line, column));
- advance();
-
- } else if (src[position] == '=') {
- tokens.push_back(Token(TokenType::ASSIGN, std::string(1, src[position]), line, column));
- advance();
-
- } else if (src[position] == ';') {
- tokens.push_back(Token(TokenType::SEMICOLON, std::string(1, src[position]), line, column));
- advance();
-
- } else {
- tokens.push_back(Token(TokenType::INVALID, std::string(1, src[position]), line, column));
- advance();
-
- }
- skipComment();
- skipWhitespace();
-
- }
- tokens.push_back(Token(TokenType::END_OF_FILE, std::string(), line, column));
- return tokens;
-}
-
-char Lexer::advance() {
- column++;
- return src[position++];
-}
-
-void Lexer::skipWhitespace() {
- while (src[position] == ' ' || src[position] == '\n') {
- if (src[position] == ' ') {
- position++;
- column++;
-
- } else if (src[position] == '\n') {
- position++;
- column = 1;
- line++;
- }
- }
-}
-
-void Lexer::skipComment() {
- if (src[position] == '/' && src[++position] == '/') {
- while (src[position] != '\n') {
- position++;
- column++;
- }
- position++;
- line += 1;
- column = 1;
- }
-}
diff --git a/src/main.cpp b/src/main.cpp
@@ -2,8 +2,8 @@
#include <sstream>
#include <fstream>
-#include "lexer/lexer.hpp"
-#include "parser/parser.hpp"
+#include "lexer.hpp"
+#include "parser.hpp"
std::string tokenTypeToString(TokenType type) {
switch (type) {
diff --git a/src/parser.cpp b/src/parser.cpp
@@ -0,0 +1,171 @@
+#include <iostream>
+
+#include "parser.hpp"
+
+Parser::Parser(const std::vector<Token>& tokens) : tokens_(tokens), position_(0) {}
+
+std::unique_ptr<Program> Parser::parse() {
+ auto program = std::make_unique<Program>();
+
+ while (peek().type != TokenType::END_OF_FILE) {
+ try {
+ auto statement = parseStatement();
+ program->declarations.push_back(std::move(statement));
+
+ if (peek().type == TokenType::SEMICOLON) {
+ advance();
+ }
+ }
+
+ catch (const std::exception& e) {
+ std::cerr << " Parser error: " << e.what() << std::endl;
+ break;
+ }
+ }
+
+ return program;
+}
+
+std::unique_ptr<ASTNode> Parser::parseStatement() {
+ switch(peek().type) {
+ case TokenType::INT:
+ case TokenType::STRING:
+ {
+ return parseDeclaration();
+ break;
+ }
+
+ default:
+ {
+ error("Unexpected statement");
+ return nullptr;
+ }
+ }
+}
+
+std::unique_ptr<ASTNode> Parser::parseExpression() {
+ return parseAddSub();
+}
+
+std::unique_ptr<ASTNode> Parser::parseDeclaration() {
+ std::string type;
+
+ switch(peek().type) {
+ case TokenType::INT:
+ {
+ type = "int";
+ break;
+ }
+
+ case TokenType::STRING:
+ {
+ type = "string";
+ break;
+ }
+
+ default:
+ {
+ error("Unexpected declaration: Invalid type");
+ return nullptr;
+ }
+ }
+
+ advance();
+ std::string name = peek().value;
+ advance();
+ if (peek().type == TokenType::ASSIGN) {
+ advance();
+ auto value = parseExpression();
+ return std::make_unique<Declaration>(type, name, std::move(value));
+ }
+
+ else if (peek().type == TokenType::SEMICOLON) {
+ return std::make_unique<Declaration>(type, name);
+ }
+
+ else {
+ error("Invalid declaration");
+ return nullptr;
+ }
+}
+
+std::unique_ptr<ASTNode> Parser::parseAssignment() {
+ std::string name = peek().value;
+ advance();
+ advance(); // consume =
+ auto value = parseExpression();
+ return std::make_unique<Assignment>(name, std::move(value));
+}
+
+std::unique_ptr<ASTNode> Parser::parseAddSub() {
+ auto left = parseMulDiv();
+
+ while (peek().type == TokenType::PLUS || peek().type == TokenType::MINUS) {
+ std::string op = peek().value;
+ advance();
+ auto right = parseMulDiv();
+ left = std::make_unique<BinaryOp>(std::move(left), op, std::move(right));
+ }
+
+ return left;
+}
+
+std::unique_ptr<ASTNode> Parser::parseMulDiv() {
+ auto left = parsePrimary();
+
+ while (peek().type == TokenType::MULTIPLY || peek().type == TokenType::DIVIDE) {
+ std::string op = peek().value;
+ advance();
+ auto right = parsePrimary();
+ left = std::make_unique<BinaryOp>(std::move(left), op, std::move(right));
+ }
+
+ return left;
+}
+
+std::unique_ptr<ASTNode> Parser::parsePrimary() {
+ switch(peek().type) {
+ case TokenType::NUMBER:
+ {
+ double value = std::stod(peek().value);
+ advance();
+ return std::make_unique<NumberLiteral>(value);
+ }
+
+ case TokenType::IDENTIFIER:
+ {
+ std::string name = peek().value;
+ advance();
+ return std::make_unique<Identifier>(name);
+ }
+
+ case TokenType::STRING:
+ {
+ std::string value = peek().value;
+ advance();
+ return std::make_unique<StringLiteral>(value);
+ }
+
+ default:
+ {
+ error("Unknown keyword");
+ return nullptr;
+ }
+ }
+}
+
+Token Parser::advance() {
+ return tokens_[position_++];
+}
+
+Token Parser::peek() {
+ return tokens_[position_];
+}
+
+bool Parser::isAtEnd() {
+ return position_ >= tokens_.size();
+}
+
+void Parser::error(std::string s) {
+
+}
diff --git a/src/parser/parser.cpp b/src/parser/parser.cpp
@@ -1,171 +0,0 @@
-#include <iostream>
-
-#include "parser/parser.hpp"
-
-Parser::Parser(const std::vector<Token>& tokens) : tokens_(tokens), position_(0) {}
-
-std::unique_ptr<Program> Parser::parse() {
- auto program = std::make_unique<Program>();
-
- while (peek().type != TokenType::END_OF_FILE) {
- try {
- auto statement = parseStatement();
- program->declarations.push_back(std::move(statement));
-
- if (peek().type == TokenType::SEMICOLON) {
- advance();
- }
- }
-
- catch (const std::exception& e) {
- std::cerr << " Parser error: " << e.what() << std::endl;
- break;
- }
- }
-
- return program;
-}
-
-std::unique_ptr<ASTNode> Parser::parseStatement() {
- switch(peek().type) {
- case TokenType::INT:
- case TokenType::STRING:
- {
- return parseDeclaration();
- break;
- }
-
- default:
- {
- error("Unexpected statement");
- return nullptr;
- }
- }
-}
-
-std::unique_ptr<ASTNode> Parser::parseExpression() {
- return parseAddSub();
-}
-
-std::unique_ptr<ASTNode> Parser::parseDeclaration() {
- std::string type;
-
- switch(peek().type) {
- case TokenType::INT:
- {
- type = "int";
- break;
- }
-
- case TokenType::STRING:
- {
- type = "string";
- break;
- }
-
- default:
- {
- error("Unexpected declaration: Invalid type");
- return nullptr;
- }
- }
-
- advance();
- std::string name = peek().value;
- advance();
- if (peek().type == TokenType::ASSIGN) {
- advance();
- auto value = parseExpression();
- return std::make_unique<Declaration>(type, name, std::move(value));
- }
-
- else if (peek().type == TokenType::SEMICOLON) {
- return std::make_unique<Declaration>(type, name);
- }
-
- else {
- error("Invalid declaration");
- return nullptr;
- }
-}
-
-std::unique_ptr<ASTNode> Parser::parseAssignment() {
- std::string name = peek().value;
- advance();
- advance(); // consume =
- auto value = parseExpression();
- return std::make_unique<Assignment>(name, std::move(value));
-}
-
-std::unique_ptr<ASTNode> Parser::parseAddSub() {
- auto left = parseMulDiv();
-
- while (peek().type == TokenType::PLUS || peek().type == TokenType::MINUS) {
- std::string op = peek().value;
- advance();
- auto right = parseMulDiv();
- left = std::make_unique<BinaryOp>(std::move(left), op, std::move(right));
- }
-
- return left;
-}
-
-std::unique_ptr<ASTNode> Parser::parseMulDiv() {
- auto left = parsePrimary();
-
- while (peek().type == TokenType::MULTIPLY || peek().type == TokenType::DIVIDE) {
- std::string op = peek().value;
- advance();
- auto right = parsePrimary();
- left = std::make_unique<BinaryOp>(std::move(left), op, std::move(right));
- }
-
- return left;
-}
-
-std::unique_ptr<ASTNode> Parser::parsePrimary() {
- switch(peek().type) {
- case TokenType::NUMBER:
- {
- double value = std::stod(peek().value);
- advance();
- return std::make_unique<NumberLiteral>(value);
- }
-
- case TokenType::IDENTIFIER:
- {
- std::string name = peek().value;
- advance();
- return std::make_unique<Identifier>(name);
- }
-
- case TokenType::STRING:
- {
- std::string value = peek().value;
- advance();
- return std::make_unique<StringLiteral>(value);
- }
-
- default:
- {
- error("Unknown keyword");
- return nullptr;
- }
- }
-}
-
-Token Parser::advance() {
- return tokens_[position_++];
-}
-
-Token Parser::peek() {
- return tokens_[position_];
-}
-
-bool Parser::isAtEnd() {
- return position_ >= tokens_.size();
-}
-
-void Parser::error(std::string s) {
-
-}
diff --git a/src/scope.cpp b/src/scope.cpp
@@ -0,0 +1,52 @@
+#include "scope.hpp"
+
+Scope::Scope(std::string name, int level, std::unique_ptr<Scope> parent) : scope_name(name), scope_level(level), parent_scope(parent) {}
+
+std::string Scope::getScopeName() {
+ return scope_name;
+}
+
+int Scope::getScopeLevel() {
+ return scope_level;
+}
+
+std::unique_ptr<Scope> Scope::getParentScope() {
+ return parent_scope;
+}
+
+void Scope::define(Symbol symbol) {
+ if (isDeclared(symbol->getName())) {
+ // error
+ }
+
+ else {
+ symobls.add(symbol->getName(), symbol);
+ }
+}
+
+std::unique_ptr<Symbol> Scope::lookup(std::string name) {
+ auto it = symbols.find(name);
+ if (it != symbols.end()) {
+ return &(it->second);
+ }
+
+ return nullptr;
+}
+
+bool Scope::isDeclared(std::string name) {
+ return lookup(name) != nullptr;
+}
+
+std::unordered_map<std::string, Symbol> Scope::getAllSymbols() {
+ return symbols;
+}
+
+std::string Scope::toString() {
+ std::string result = "Scope: " + scope_name + "(level " + std::to_string(scope_level) + ") \n";
+
+ for (auto& pair : symbols) {
+ result += " " + pair.first + " : " + pair.second.getDataType() + "\n";
+ }
+
+ return result;
+}
diff --git a/src/semantic/scope.cpp b/src/semantic/scope.cpp
@@ -1,52 +0,0 @@
-#include "semantic/scope.hpp"
-
-Scope::Scope(std::string name, int level, std::unique_ptr<Scope> parent) : scope_name(name), scope_level(level), parent_scope(parent) {}
-
-std::string Scope::getScopeName() {
- return scope_name;
-}
-
-int Scope::getScopeLevel() {
- return scope_level;
-}
-
-std::unique_ptr<Scope> Scope::getParentScope() {
- return parent_scope;
-}
-
-void Scope::define(Symbol symbol) {
- if (isDeclared(symbol->getName())) {
- // error
- }
-
- else {
- symobls.add(symbol->getName(), symbol);
- }
-}
-
-std::unique_ptr<Symbol> Scope::lookup(std::string name) {
- auto it = symbols.find(name);
- if (it != symbols.end()) {
- return &(it->second);
- }
-
- return nullptr;
-}
-
-bool Scope::isDeclared(std::string name) {
- return lookup(name) != nullptr;
-}
-
-std::unordered_map<std::string, Symbol> Scope::getAllSymbols() {
- return symbols;
-}
-
-std::string Scope::toString() {
- std::string result = "Scope: " + scope_name + "(level " + std::to_string(scope_level) + ") \n";
-
- for (auto& pair : symbols) {
- result += " " + pair.first + " : " + pair.second.getDataType() + "\n";
- }
-
- return result;
-}
diff --git a/src/semantic/semantic_analyzer.cpp b/src/semantic/semantic_analyzer.cpp
@@ -1,33 +0,0 @@
-#include "semantic/semantic_analyzer.hpp"
-
-SemanticAnalyzer::SemanticAnalyzer() : symobl_table(new SemanticTable), errors(std::vector<Error>), warnings(std::vector<Error>), current_function(nullptr), current_function_return_type(""), has_main_function(false) {}
-
-bool SemanticAnalyzer::analyze(ASTNode* ast) {
- this->symbol_table.enterScope("global")
- this->visit(ast);
- this->validateMainFunction();
-
- if (has_main_function == false) {
- //error
- return false;
- }
-
- this->symbol_table.exitScope();
- return true;
-}
-
-std::vector<Error> SemanticAnalyzer::getErrors() {
- return this->errors;
-}
-
-std::vector<Error> SemanticAnalyzer::getWarnings() {
- return this->warnings;
-}
-
-bool SemanticAnalyzer::hasErrors() {
- return !this->errors.empty();
-}
-
-std::string SemanticAnalyzer::visit(ASTNode* ast) {
-
-}
diff --git a/src/semantic/symbol.cpp b/src/semantic/symbol.cpp
@@ -1,126 +0,0 @@
-#include "semantic/symbol.hpp"
-
-Symbol::Symbol(std::string name, SymbolType type, std::string data_type, int scope) : symbol_name(name), symbol_type(type), data_type(data_type), scope_level(scope_level) {}
-
-std::string Symbool::getName() {
- return name;
-}
-
-SymbolType Symbol::getSymbolType() {
- return symbol_type;
-}
-
-std::string Symbol::getDataType() {
- return symbol_data_type;
-}
-
-int Symbol::getSymbolLevel() {
- return scope_level;
-}
-
-bool Symbol::isInitialized() {
- return is_initialized;
-}
-
-void Symbol::setInitialized(bool init) {
- is_initialized = init;
-}
-
-bool Symbol::isParameter() {
- return is_parameter();
-}
-
-void Symbol::setParameter(bool is_param) {
- is_parameter = is_param;
-}
-
-std::vector<std::string> Symbol::getParameterTypes() {
- return paremeter_types;
-}
-
-void Symbol::setParameterTypes(std::vector<std::string> types) {
- parameter_types = types;
-}
-
-std::string Symbol::getReturnType() {
- return return_type;
-}
-
-void Symbol::setReturnType(std::string type) {
- return_type = type;
-}
-
-int Symbol::getLineDeclared() {
- return line_declared;
-}
-
-void Symbol::setLineDeclared(int line) {
- line_declared = line;
-}
-
-std::string Symbol::toString() const {
- std::string result = "";
-
- // Symbol name and basic info
- result += "Symbol: " + name + "\n";
-
- // Symbol type (VARIABLE, FUNCTION, PARAMETER)
- result += " Type: ";
- switch (symbol_type) {
- case SymbolType::VARIABLE:
- result += "VARIABLE\n";
- break;
- case SymbolType::FUNCTION:
- result += "FUNCTION\n";
- break;
- case SymbolType::PARAMETER:
- result += "PARAMETER\n";
- break;
- default:
- result += "UNKNOWN\n";
- break;
- }
-
- // Data type
- result += " Data Type: " + data_type + "\n";
-
- // Scope level
- result += " Scope Level: " + std::to_string(scope_level) + "\n";
-
- // Initialization status (only relevant for variables)
- if (symbol_type == SymbolType::VARIABLE || symbol_type == SymbolType::PARAMETER) {
- result += " Initialized: " + std::string(is_initialized ? "true" : "false") + "\n";
- }
-
- // Parameter flag
- if (is_parameter) {
- result += " Is Parameter: true\n";
- }
-
- // Function-specific information
- if (symbol_type == SymbolType::FUNCTION) {
- result += " Return Type: " + return_type + "\n";
-
- result += " Parameters: [";
- for (size_t i = 0; i < parameter_types.size(); i++) {
- result += parameter_types[i];
- if (i < parameter_types.size() - 1) {
- result += ", ";
- }
- }
- result += "]\n";
-
- result += " Parameter Count: " + std::to_string(parameter_types.size()) + "\n";
- }
-
- // Declaration location
- if (line_declared > 0) {
- result += " Declared at: line " + std::to_string(line_declared);
- if (column_declared > 0) {
- result += ", column " + std::to_string(column_declared);
- }
- result += "\n";
- }
-
- return result;
-}
diff --git a/src/semantic/symbol_table.cpp b/src/semantic/symbol_table.cpp
@@ -1,89 +0,0 @@
-#include "semantic/symbol_table.hpp"
-
-#include <iostream>
-
-SymbolTable::SymbolTable() : scopes(std::vector<Scope>), current_scope(nullptr), scope_level(0), global_scope(nullptr) {}
-
-SymbolTable::~SymbolTable() {}
-
-void SymbolTable::enterScope(std::string scope_name) {
- Scope scope = Scope(scope_name, scope_level, current_scope);
- scopes.push_back(scope*);
-
- this->current_scope = scope*;
- this->scope_level ++;
-}
-
-void SymbolTable::exitScope() {
- parent_scope = getParentScope();
- this->current_scope = parent_scope
-
- this->scope_level --;
-}
-
-Scope* SymbolTable::getCurrentScope() {
- return this->current_scope;
-}
-
-Scope* SymbolTable::getGlobalScope() {
- return this->global_scope;
-}
-
-int SymbolTable::getScopeLevel() {
- return this->scope_level;
-}
-
-void SymbolTable::insert(Symbol symbol) {
- if (this->current_scope == nullptr) {
- // error
- }
-
- this->current_scope->define(symbol);
-}
-
-Symbol* SymbolTable::lookup(std::string name) {
- current_scope = getCurrentScope();
- symbol = current_scope->lookup(name);
-
- while (symbol == nullptr) {
- current_scope = current_scope->getParentScope();
- if (current_scope == nullptr) {
- return nullptr;
- }
-
- symbol = current_scope->lookup(name);
- }
-
- return symbol;
-}
-
-Symbol* SymbolTable::lookupCurrentScope(std::string name) {
- current_scope = getCurrentScope();
- return current_scope->lookup(name);
-}
-
-bool SymbolTable::isDeclared(std::string name) {
- symbol == this->lookup(name);
- return (symbol != nullptr);
-}
-
-bool SymbolTable::isDeclaredInCurrentScope(std::string name) {
- symbol == this->lookupCurrentSceop(name);
- return (symbol != nullptr);
-}
-
-void display() {
- std::cout << this->toString();
-}
-
-std::string toString() {
- std::string indent;
- std::string result;
-
- for (const Scope& i : this->scopes) {
- indent += (" " * i->getScopeLevel());
- result += (indent + '\n' + i->toString());
- }
-
- return result;
-}
diff --git a/src/semantic_analyzer.cpp b/src/semantic_analyzer.cpp
@@ -0,0 +1,235 @@
+#include "semantic_analyzer.hpp"
+
+SemanticAnalyzer::SemanticAnalyzer() : symobl_table(new SemanticTable), errors(std::vector<Error>), warnings(std::vector<Error>), current_function(nullptr), current_function_return_type(""), has_main_function(false) {}
+
+bool SemanticAnalyzer::analyze(ASTNode* ast) {
+ symbol_table.enterScope("global")
+ visit(ast);
+ validateMainFunction();
+
+ if (has_main_function == false) {
+ //error
+ return false;
+ }
+
+ symbol_table.exitScope();
+ return true;
+}
+
+std::vector<Error> SemanticAnalyzer::getErrors() {
+ return errors;
+}
+
+std::vector<Error> SemanticAnalyzer::getWarnings() {
+ return warnings;
+}
+
+bool SemanticAnalyzer::hasErrors() {
+ return !errors.empty();
+}
+
+std::string SemanticAnalyzer::visit(ASTNode* node) {
+ if (ProgramNode* prog = dynamic_cast<ProgramNode*>(node)) {
+ return visitProgram(prog);
+ }
+
+ else if (FunctionDeclNode* func = dynamic_cast<FunctionDeclNode*>(node)) {
+ return visitFunctionDecl(func);
+ }
+
+ else if (ParameterNode* param = dynamic_cast<ParameterNode*>(node)) {
+ return visitParameter(param);
+ }
+
+ else if (VarDeclNode* var = dynamic_cast<VarDeclNode*>(node)) {
+ return visitVarDeclaration(var);
+ }
+
+ else if (AssignmentNode as = dynamic_cast<AssignmentNode>(node)) {
+ return visitAssignment(as);
+ }
+
+ else if (IfStatementNode is = dynamic_cast<IfStatementNode>(node)) {
+ return visitIfStatement(is);
+ }
+
+ else if (WhileStatementNode ws = dynamic_cast<WhileStatementNode>(node)) {
+ return visitWhileStatement(ws);
+ }
+
+ else if (ForStatementNode fs = dynamic_cast<ForStatementNode>(node)) {
+ return visitForStatement(fs);
+ }
+
+ else if (ReturnStatementNode rs = dynamic_cast<ReturnStatementNode>(node)) {
+ return visitReturnStatement(rs);
+ }
+
+ else if (ExpressionStatementNode es = dynamic_cast<ExpressionStatementNode>(node)) {
+ return visitExpressionStatement(es);
+ }
+
+ else if (BinaryExprNode bin = dynamic_cast<BinaryExprNode>(node)) {
+ return visitBinaryExpression(bin);
+ }
+
+ else if (UnaryExprNode un = dynamic_cast<UnaryExprNode>(node)) {
+ return visitUnaryExpression(un);
+ }
+
+ else if (FunctionCallNode func_call = dynamic_cast<FunctionCallNode>(node)) {
+ return visitFunctionCall(func_call);
+ }
+
+ else if (IdentifierNode ident = dynamic_cast<IdentifierNode>(node)) {
+ return visitIdentifier(ident);
+ }
+
+ else if (LiteralNode lit = dynamic_cast<LiteralNode>(node)) {
+ return visitLiteral(lit);
+ }
+}
+
+std::string visitProgram(ProgramNode* node){
+ // get list of functions
+ // visit each function
+ // return
+
+}
+
+std::string visitFunctionDecl(FunctionDeclNode* node){
+ // check for dupe name
+ // create function symbol and insert into global scope
+ // check if main function
+ // enter function scope
+ // process parameters
+ // process function body
+ // verify non-void functions have return statements
+ // exit function scope and clear context
+ // return
+
+}
+
+std::string visitParameter(ParameterNode*){
+ // get parameter info from node
+ // check for dupes
+ // create parameter symbol
+ // insert into current scope
+ // return parameter type
+
+}
+
+std::string visitVarDeclaration(VarDeclNode* node){
+ // get variable information
+ // check for dupes
+ // if initializer exists, check type
+ // create variable symbol
+ // insert into current scope
+ // return
+
+}
+
+std::string visitAssignment(AssignmentNode* node){
+ // get left side info
+ // look up target variable
+ // verify variable
+ // analyze right side info
+ // check type compatability
+ // make var as initialized
+ // return
+
+}
+
+std::string visitIfStatement(IfStatementNode* node){
+ // analyze condition
+ // verify condition is bool
+ // analyze then branch
+ // analyze else branch
+ // return
+
+}
+
+std::string visitWhileStatement(WhileStatementNode* node){
+ // analyze condition
+ // verify condition is bool
+ // analyze loop body
+ // return
+
+}
+
+std::string visitForStatement(ForStatementNode* node){
+ // enter new scope for loop
+ // analyze initialization
+ // analyze condition
+ // analyze update statement
+ // analyze loop body
+ // exit for loop scope
+ // return
+
+}
+
+std::string visitReturnStatement(ReturnStatementNode* node){
+ // check if inside function
+ // get return expression
+ // analyze return expression
+ // validate return type matches function
+ // return
+
+}
+
+std::String visitExpressionStatement(ExpressionStatementNode* node){
+ // get the expression
+ // analyze expression
+ // return
+
+}
+
+std::string visitBinaryExpression(BinaryExprNode* node){
+ // get operator and operands
+ // analyze operands
+ // infer result type based on operator
+ // return result type
+
+}
+
+std::string visitUnaryExpression(UnaryExprNode* node){
+ // get operator and operand
+ // analyze operand
+ // infer result type
+ // return result type
+
+}
+
+std::string visitFunctionCall(FunctionCallNode* node){
+ // get function name and args
+ // look up function
+ // verify its a function
+ // get expected parameter information
+ // check argument count
+ // check each argument type
+ // return functions return type
+
+}
+
+std::string visitIdentifier(IdentifierNode* node){
+ // get identifier name
+ // look up in symbol table
+ // check if initialized
+ // return symbol type
+
+}
+
+std::string visitLiteral(LiteralNode* node){
+ // determine literal type
+ // return appropriate type
+
+}
+
+bool checkTypeCompatibility(std::string target, std::string source){
+ // determines if a value of source type can be used where target type is expected
+
+}
+
+std::string inferBinaryOpType(std::string op, std::string left, std::string right){
+
+}
diff --git a/src/symbol.cpp b/src/symbol.cpp
@@ -0,0 +1,126 @@
+#include "symbol.hpp"
+
+Symbol::Symbol(std::string name, SymbolType type, std::string data_type, int scope) : symbol_name(name), symbol_type(type), data_type(data_type), scope_level(scope_level) {}
+
+std::string Symbool::getName() {
+ return name;
+}
+
+SymbolType Symbol::getSymbolType() {
+ return symbol_type;
+}
+
+std::string Symbol::getDataType() {
+ return symbol_data_type;
+}
+
+int Symbol::getSymbolLevel() {
+ return scope_level;
+}
+
+bool Symbol::isInitialized() {
+ return is_initialized;
+}
+
+void Symbol::setInitialized(bool init) {
+ is_initialized = init;
+}
+
+bool Symbol::isParameter() {
+ return is_parameter();
+}
+
+void Symbol::setParameter(bool is_param) {
+ is_parameter = is_param;
+}
+
+std::vector<std::string> Symbol::getParameterTypes() {
+ return paremeter_types;
+}
+
+void Symbol::setParameterTypes(std::vector<std::string> types) {
+ parameter_types = types;
+}
+
+std::string Symbol::getReturnType() {
+ return return_type;
+}
+
+void Symbol::setReturnType(std::string type) {
+ return_type = type;
+}
+
+int Symbol::getLineDeclared() {
+ return line_declared;
+}
+
+void Symbol::setLineDeclared(int line) {
+ line_declared = line;
+}
+
+std::string Symbol::toString() const {
+ std::string result = "";
+
+ // Symbol name and basic info
+ result += "Symbol: " + name + "\n";
+
+ // Symbol type (VARIABLE, FUNCTION, PARAMETER)
+ result += " Type: ";
+ switch (symbol_type) {
+ case SymbolType::VARIABLE:
+ result += "VARIABLE\n";
+ break;
+ case SymbolType::FUNCTION:
+ result += "FUNCTION\n";
+ break;
+ case SymbolType::PARAMETER:
+ result += "PARAMETER\n";
+ break;
+ default:
+ result += "UNKNOWN\n";
+ break;
+ }
+
+ // Data type
+ result += " Data Type: " + data_type + "\n";
+
+ // Scope level
+ result += " Scope Level: " + std::to_string(scope_level) + "\n";
+
+ // Initialization status (only relevant for variables)
+ if (symbol_type == SymbolType::VARIABLE || symbol_type == SymbolType::PARAMETER) {
+ result += " Initialized: " + std::string(is_initialized ? "true" : "false") + "\n";
+ }
+
+ // Parameter flag
+ if (is_parameter) {
+ result += " Is Parameter: true\n";
+ }
+
+ // Function-specific information
+ if (symbol_type == SymbolType::FUNCTION) {
+ result += " Return Type: " + return_type + "\n";
+
+ result += " Parameters: [";
+ for (size_t i = 0; i < parameter_types.size(); i++) {
+ result += parameter_types[i];
+ if (i < parameter_types.size() - 1) {
+ result += ", ";
+ }
+ }
+ result += "]\n";
+
+ result += " Parameter Count: " + std::to_string(parameter_types.size()) + "\n";
+ }
+
+ // Declaration location
+ if (line_declared > 0) {
+ result += " Declared at: line " + std::to_string(line_declared);
+ if (column_declared > 0) {
+ result += ", column " + std::to_string(column_declared);
+ }
+ result += "\n";
+ }
+
+ return result;
+}
diff --git a/src/symbol_table.cpp b/src/symbol_table.cpp
@@ -0,0 +1,89 @@
+#include "symbol_table.hpp"
+
+#include <iostream>
+
+SymbolTable::SymbolTable() : scopes(std::vector<Scope>), current_scope(nullptr), scope_level(0), global_scope(nullptr) {}
+
+SymbolTable::~SymbolTable() {}
+
+void SymbolTable::enterScope(std::string scope_name) {
+ Scope scope = Scope(scope_name, scope_level, current_scope);
+ scopes.push_back(scope*);
+
+ this->current_scope = scope*;
+ this->scope_level ++;
+}
+
+void SymbolTable::exitScope() {
+ parent_scope = getParentScope();
+ this->current_scope = parent_scope
+
+ this->scope_level --;
+}
+
+Scope* SymbolTable::getCurrentScope() {
+ return this->current_scope;
+}
+
+Scope* SymbolTable::getGlobalScope() {
+ return this->global_scope;
+}
+
+int SymbolTable::getScopeLevel() {
+ return this->scope_level;
+}
+
+void SymbolTable::insert(Symbol symbol) {
+ if (this->current_scope == nullptr) {
+ // error
+ }
+
+ this->current_scope->define(symbol);
+}
+
+Symbol* SymbolTable::lookup(std::string name) {
+ current_scope = getCurrentScope();
+ symbol = current_scope->lookup(name);
+
+ while (symbol == nullptr) {
+ current_scope = current_scope->getParentScope();
+ if (current_scope == nullptr) {
+ return nullptr;
+ }
+
+ symbol = current_scope->lookup(name);
+ }
+
+ return symbol;
+}
+
+Symbol* SymbolTable::lookupCurrentScope(std::string name) {
+ current_scope = getCurrentScope();
+ return current_scope->lookup(name);
+}
+
+bool SymbolTable::isDeclared(std::string name) {
+ symbol == this->lookup(name);
+ return (symbol != nullptr);
+}
+
+bool SymbolTable::isDeclaredInCurrentScope(std::string name) {
+ symbol == this->lookupCurrentSceop(name);
+ return (symbol != nullptr);
+}
+
+void display() {
+ std::cout << this->toString();
+}
+
+std::string toString() {
+ std::string indent;
+ std::string result;
+
+ for (const Scope& i : this->scopes) {
+ indent += (" " * i->getScopeLevel());
+ result += (indent + '\n' + i->toString());
+ }
+
+ return result;
+}