From c5f981321c27e753af00e1ba519c94e729b781db Mon Sep 17 00:00:00 2001 From: Bobby Lucero Date: Sun, 21 May 2023 20:40:43 -0400 Subject: [PATCH] AST Struct Generator --- .DS_Store | Bin 0 -> 6148 bytes .gitignore | 1 + Makefile | 14 +- headers/Expression.h | 49 +++++++ headers/Lexer.h | 20 ++- headers/bob.h | 31 +++++ headers/helperFunctions/HelperFunctions.h | 40 ++++++ source.bob | 14 +- source/.DS_Store | Bin 0 -> 6148 bytes source/Expression.cpp | 5 + {src => source}/Lexer.cpp | 148 ++++++++++++---------- source/bob.cpp | 60 +++++++++ source/main.cpp | 37 ++++++ {src => source}/test.cpp | 0 src/bob.cpp | 96 -------------- testthing | 35 +++++ tools/GenerateAST | Bin 0 -> 84424 bytes tools/GenerateAST.cpp | 72 +++++++++++ 18 files changed, 448 insertions(+), 174 deletions(-) create mode 100644 .DS_Store create mode 100644 headers/Expression.h create mode 100644 headers/bob.h create mode 100644 headers/helperFunctions/HelperFunctions.h create mode 100644 source/.DS_Store create mode 100644 source/Expression.cpp rename {src => source}/Lexer.cpp (57%) create mode 100644 source/bob.cpp create mode 100644 source/main.cpp rename {src => source}/test.cpp (100%) delete mode 100644 src/bob.cpp create mode 100644 testthing create mode 100755 tools/GenerateAST create mode 100644 tools/GenerateAST.cpp diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..b8af6b35dd43078f3955c11e4fbadf56a40f2759 GIT binary patch literal 6148 zcmeHKI|>3Z5S>vG!N$@uSMUZw^aOhWLB&QC6s@=NTprCgpGH?ZZR8D1UNV`NkXP*N zh=|TFo0-T&L`HB!x!KS)+c)o6FCz+si0p zwti-h{ zq5pp-aYY5Fz+Wk#gGIBL<4IXtJCCzkTi`3W<=o+Bm^%f7mt&xpV=Sy3PdzE}ip{ZK V6Wc(iBkpt{e+En!8Ws4p0uQpU6`%kB literal 0 HcmV?d00001 diff --git a/.gitignore b/.gitignore index e524d79..096eb1d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .vscode/ build/ +.idea diff --git a/Makefile b/Makefile index 51b581f..fe63122 100644 --- a/Makefile +++ b/Makefile @@ -7,22 +7,26 @@ CC = g++ CFLAGS = -Wall -Wextra -std=c++11 # Source directory -SRC_DIR = ./src +SRC_DIR = ./source # Output directory BUILD_DIR = ./build -# Get all CPP files in the source directory -CPP_FILES := $(wildcard $(SRC_DIR)/*.cpp) +# Find all C++ files recursively in the source directory +CPP_FILES := $(shell find $(SRC_DIR) -type f -name '*.cpp') # Generate object file names by replacing the source directory with the build directory OBJ_FILES := $(patsubst $(SRC_DIR)/%.cpp,$(BUILD_DIR)/%.o,$(CPP_FILES)) +# Create directories for object files +$(shell mkdir -p $(dir $(OBJ_FILES))) + # Default target all: $(BUILD_DIR)/bob -# Rule to create the build directory if it doesn't exist -$(shell mkdir -p $(BUILD_DIR)) +# Rule to create necessary directories +$(DIRS): + mkdir -p $(patsubst $(SRC_DIR)/%, $(OUTPUT_DIR)/%, $@) # Rule to compile object files $(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp diff --git a/headers/Expression.h b/headers/Expression.h new file mode 100644 index 0000000..ef21c20 --- /dev/null +++ b/headers/Expression.h @@ -0,0 +1,49 @@ +// +// Created by Bobby Lucero on 5/21/23. +// + +#pragma once +#include "Lexer.h" +#include +struct Expr{ + virtual ~Expr() + { + + } +}; + +struct BinaryExpr : Expr +{ + const Expr left; + const Token oper; + const Expr right; + + BinaryExpr(Expr left, Token oper, Expr right) : left(left), oper(oper), right(right) + { + } +}; +struct GroupingExpr : Expr +{ + const Expr expression; + + GroupingExpr(Expr expression) : expression(expression) + { + } +}; +struct LiteralExpr : Expr +{ + const std::string value; + + LiteralExpr(std::string value) : value(value) + { + } +}; +struct UnaryExpr : Expr +{ + const Token oper; + const Expr right; + + UnaryExpr(Token oper, Expr right) : oper(oper), right(right) + { + } +}; diff --git a/headers/Lexer.h b/headers/Lexer.h index 770baa4..290c6e0 100644 --- a/headers/Lexer.h +++ b/headers/Lexer.h @@ -24,7 +24,21 @@ enum TokenType{ }; const std::map KEYWORDS { - + {"and", AND}, + {"or", OR}, + {"true", TRUE}, + {"false", FALSE}, + {"if", IF}, + {"else", ELSE}, + {"func", FUNCTION}, + {"for", FOR}, + {"while", WHILE}, + {"var", VAR}, + {"class", CLASS}, + {"super", SUPER}, + {"this", THIS}, + {"none", NONE}, + {"return", RETURN} }; struct Token @@ -41,6 +55,8 @@ public: std::vector Tokenize(std::string source); private: int line; + std::vector src; private: - bool matchOn(char expected, std::vector& src); + bool matchOn(char expected); + void advance(); }; diff --git a/headers/bob.h b/headers/bob.h new file mode 100644 index 0000000..2d9cb3d --- /dev/null +++ b/headers/bob.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include +#include "../headers/Lexer.h" + +#define VERSION "0.0.1" + +class Bob +{ +public: + Lexer lexer; + +public: + void runFile(std::string path); + + void runPrompt(); + + void error(int line, std::string message); + + +private: + bool hadError = false; + +private: + void run(std::string source); + + void report(int line, std::string where, std::string message); +}; + diff --git a/headers/helperFunctions/HelperFunctions.h b/headers/helperFunctions/HelperFunctions.h new file mode 100644 index 0000000..e0aae20 --- /dev/null +++ b/headers/helperFunctions/HelperFunctions.h @@ -0,0 +1,40 @@ +#pragma once + +#include +#include + +std::vector splitString(const std::string& input, std::string delimiter) { + std::vector tokens; + std::string token; + size_t start = 0; + size_t end = input.find(delimiter); + + while (end != std::string::npos) { + token = input.substr(start, end - start); + tokens.push_back(token); + start = end + 1; + end = input.find(delimiter, start); + } + + // Add the last token (after the last delimiter) + token = input.substr(start, end); + tokens.push_back(token); + + return tokens; +} + +std::string trim(const std::string& str) { + // Find the first non-whitespace character + size_t start = str.find_first_not_of(" \t\n\r"); + + // If the string is all whitespace, return an empty string + if (start == std::string::npos) { + return ""; + } + + // Find the last non-whitespace character + size_t end = str.find_last_not_of(" \t\n\r"); + + // Extract the trimmed substring + return str.substr(start, end - start + 1); +} \ No newline at end of file diff --git a/source.bob b/source.bob index 76a517e..1e968a8 100644 --- a/source.bob +++ b/source.bob @@ -2,7 +2,15 @@ bob.test 10 11.1 -test = (11 + 2 "xs") +test = (11 + 2 "xs +hello +end") -//" -//11. \ No newline at end of file +// +//11. + +12//11 +11. +11.69 + 66.735293857293875 + 235982735987235.0 + 1 + +123a \ No newline at end of file diff --git a/source/.DS_Store b/source/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..cf37e4eb6286a7bf0b90d470de769dba2a336404 GIT binary patch literal 6148 zcmeHK!AiqG5PefCrU=rb7h%7k;2*@&9t3axfTns7swuTXkGcCXexE0OvojRiG*=Nj zQ)b_0cHVCDHe|8@Wc>DU2@C-gbj99)%^uTn^_KNKa!iyw#|#TBuIKfvnzyne@D~-( zy*ojLnm)ph{i`dE=woq3AAMzG4>-dVYwq(Bk9g(piQJbC?#B*yfE%*b^yPkrTwZ85RnJ0-?acDZrYoR-76}8w!L1p}~+G>kSB2nDtkII_#3*8geu`G1=fSD`>C@UIk*{^WKt<}G<`ZQY#K+C;yjt7%?i lxS_C #include - using namespace std; std::vector Lexer::Tokenize(std::string source){ std::vector tokens; - std::vector src{source.begin(), source.end()}; + src = std::vector{source.begin(), source.end()}; + line = 0; - while(src.size() > 0) + while(!src.empty()) { char t = src[0]; if(t == '(') { - tokens.push_back(Token{OPEN_PAREN, std::string(1, t)}); //brace initialization in case you forget - src.erase(src.begin()); + tokens.push_back(Token{OPEN_PAREN, std::string(1, t), line}); //brace initialization in case you forget + advance(); } else if(t == ')') { - tokens.push_back(Token{CLOSE_PAREN, std::string(1, t)}); - src.erase(src.begin()); + tokens.push_back(Token{CLOSE_PAREN, std::string(1, t), line}); + advance(); } else if(t == '{') { - tokens.push_back(Token{OPEN_BRACE, std::string(1, t)}); - src.erase(src.begin()); + tokens.push_back(Token{OPEN_BRACE, std::string(1, t), line}); + advance(); } else if(t == '}') { - tokens.push_back(Token{CLOSE_BRACE, std::string(1, t)}); - src.erase(src.begin()); + tokens.push_back(Token{CLOSE_BRACE, std::string(1, t), line}); + advance(); } else if(t == ',') { - tokens.push_back(Token{COMMA, std::string(1, t)}); - src.erase(src.begin()); + tokens.push_back(Token{COMMA, std::string(1, t), line}); + advance(); } else if(t == '.') { - tokens.push_back(Token{DOT, std::string(1, t)}); - src.erase(src.begin()); + tokens.push_back(Token{DOT, std::string(1, t), line}); + advance(); } else if(t == ';') { - tokens.push_back(Token{SEMICOLON, std::string(1, t)}); - src.erase(src.begin()); + tokens.push_back(Token{SEMICOLON, std::string(1, t), line}); + advance(); } else if(t == '+') { - tokens.push_back(Token{PLUS, std::string(1, t)}); - src.erase(src.begin()); + tokens.push_back(Token{PLUS, std::string(1, t), line}); + advance(); } else if(t == '-') { - tokens.push_back(Token{MINUS, std::string(1, t)}); - src.erase(src.begin()); + tokens.push_back(Token{MINUS, std::string(1, t), line}); + advance(); } - else if(t == '*') + else if(t == '*') { - tokens.push_back(Token{STAR, std::string(1, t)}); - src.erase(src.begin()); + tokens.push_back(Token{STAR, std::string(1, t), line}); + advance(); } else if(t == '=') { std::string token = std::string(1, t); - src.erase(src.begin()); - bool match = matchOn('=', src); + advance(); + bool match = matchOn('='); token += match ? "=" : ""; - tokens.push_back(Token{match ? DOUBLE_EQUAL : EQUAL, token}); + tokens.push_back(Token{match ? DOUBLE_EQUAL : EQUAL, token, line}); } else if(t == '!') { std::string token = std::string(1, t); - src.erase(src.begin()); - bool match = matchOn('=', src); + advance(); + bool match = matchOn('='); token += match ? "=" : ""; - tokens.push_back(Token{match ? BANG_EQUAL : BANG, token}); + tokens.push_back(Token{match ? BANG_EQUAL : BANG, token, line}); } else if(t == '<') { std::string token = std::string(1, t); - src.erase(src.begin()); - bool match = matchOn('=', src); + advance(); + bool match = matchOn('='); token += match ? "=" : ""; - tokens.push_back(Token{match ? LESS_EQUAL : LESS, token}); + tokens.push_back(Token{match ? LESS_EQUAL : LESS, token, line}); } else if(t == '>') { std::string token = std::string(1, t); - src.erase(src.begin()); - bool match = matchOn('=', src); + advance(); + bool match = matchOn('='); token += match ? "=" : ""; - tokens.push_back(Token{match ? GREATER_EQUAL : GREATER, token}); + tokens.push_back(Token{match ? GREATER_EQUAL : GREATER, token, line}); + } + else if(t == '&') + { + std::string token = std::string(1, t); + advance(); + bool match = matchOn('&'); + token += match ? "&" : ""; + if(match) tokens.push_back(Token{AND, token, line}); } else if(t == '/') { std::string token = std::string(1, t); - src.erase(src.begin()); - bool match = matchOn('/', src); + advance(); + bool match = matchOn('/'); if(match) { - while(src.size() > 0 && src[0] != '\n') + while(!src.empty() && src[0] != '\n') { - src.erase(src.begin()); + advance(); } } else { - tokens.push_back(Token{SLASH, std::string(1, t)}); + tokens.push_back(Token{SLASH, std::string(1, t), line}); } } else if(t == '"') { std::string str = std::string(1, src[0]); - src.erase(src.begin()); - while(src.size() > 0 && src[0] != '"') + advance(); + while(!src.empty() && src[0] != '"') { if(src[0] == '\n') line++; str += src[0]; - src.erase(src.begin()); + advance(); } - if(src.size() == 0) + if(src.empty()) { throw std::runtime_error("Unterminated string at line: " + std::to_string(this->line)); } else if(src[0] == '"') { str += '"'; - src.erase(src.begin()); - tokens.push_back(Token{STRING, str}); + advance(); + tokens.push_back(Token{STRING, str, line}); } @@ -137,30 +144,30 @@ std::vector Lexer::Tokenize(std::string source){ else if(t == '\n') { line++; - src.erase(src.begin()); + advance(); } else { //Multi char tokens if(std::isdigit(t)) { - std::string num = ""; - while(src.size() > 0 && std::isdigit(src[0])) + std::string num; + while(!src.empty() && std::isdigit(src[0])) { num += src[0]; - src.erase(src.begin()); + advance(); } - if(src.size() > 0 && src[0] == '.') + if(!src.empty() && src[0] == '.') { - src.erase(src.begin()); - if(src.size() > 0 && std::isdigit(src[0])) + advance(); + if(!src.empty() && std::isdigit(src[0])) { num += '.'; - while(src.size() > 0 && std::isdigit(src[0])) + while(!src.empty() && std::isdigit(src[0])) { num += src[0]; - src.erase(src.begin()); + advance(); } } else @@ -170,30 +177,30 @@ std::vector Lexer::Tokenize(std::string source){ } - tokens.push_back(Token{NUMBER, num}); + tokens.push_back(Token{NUMBER, num, line}); } else if(std::isalpha(t)) { - std::string ident = ""; - while(src.size() > 0 && std::isalpha(src[0])) + std::string ident; + while(!src.empty() && std::isalpha(src[0])) { ident += src[0]; - src.erase(src.begin()); + advance(); } if(KEYWORDS.find(ident) != KEYWORDS.end()) //identifier is a keyword { - tokens.push_back(Token{KEYWORDS.at(ident), ident}); + tokens.push_back(Token{KEYWORDS.at(ident), ident, line}); } else { - tokens.push_back(Token{IDENTIFIER, ident}); + tokens.push_back(Token{IDENTIFIER, ident, line}); } } - else if(t == ' ' || t == '\t' || t == '\n') + else if(t == ' ' || t == '\t') { - src.erase(src.begin()); //ignore t + advance(); } else { @@ -209,10 +216,15 @@ std::vector Lexer::Tokenize(std::string source){ return tokens; } -bool Lexer::matchOn(char expected, std::vector &src) +bool Lexer::matchOn(char expected) { - if(src.size() == 0) return false; + if(src.empty()) return false; if(src[0] != expected) return false; - src.erase(src.begin()); + advance(); return true; } + +void Lexer::advance() +{ + src.erase(src.begin()); +} diff --git a/source/bob.cpp b/source/bob.cpp new file mode 100644 index 0000000..52f7c1c --- /dev/null +++ b/source/bob.cpp @@ -0,0 +1,60 @@ +#include "../headers/bob.h" +using namespace std; + +void Bob::runFile(string path) +{ + ifstream file = ifstream(path); + + string source = ""; + + if(file.is_open()){ + source = string(istreambuf_iterator(file), istreambuf_iterator()); + } + else + { + cout << "File not found" << endl; + return; + } + + this->run(source); +} + +void Bob::runPrompt() +{ + cout << "Bob v" << VERSION << ", 2023" << endl; + for(;;) + { + string line; + cout << "-> "; + std::getline(std::cin, line); + + if(std::cin.eof()) + { + break; + } + + this->run(line); + hadError = false; + } +} + +void Bob::error(int line, string message) +{ + +} + +void Bob::run(string source) +{ + vector tokens = lexer.Tokenize(source); + + for(Token t : tokens){ + cout << "{type: " << t.type << ", value: " << t.lexeme << "}" << endl; + } +} + +void Bob::report(int line, string where, string message) +{ + hadError = true; +} + + diff --git a/source/main.cpp b/source/main.cpp new file mode 100644 index 0000000..d49ca38 --- /dev/null +++ b/source/main.cpp @@ -0,0 +1,37 @@ +// +// Created by Bobby Lucero on 5/21/23. +// +#include "../headers/bob.h" +#include "../headers/Expression.h" +#include "../headers/Lexer.h" +int main(){ + + Bob bobLang; + + //bobLang.runFile("source.bob"); + + + Expr a; + Expr b; + Token t = {PLUS, "+", 1}; + Token t2 = {MINUS, "-", 1}; + BinaryExpr e = BinaryExpr(a, t, b); + + std::shared_ptr any = std::make_shared(a, t, b); + if(std::shared_ptr binexpr = std::dynamic_pointer_cast(any)) + { + std::cout << binexpr->oper.lexeme; + } + + any = std::make_shared(a, t2, b); + if(std::shared_ptr binexpr = std::dynamic_pointer_cast(any)) + { + std::cout << binexpr->oper.lexeme; + } + + std::cout << std::endl; + + bobLang.runPrompt(); + + return 0; +} diff --git a/src/test.cpp b/source/test.cpp similarity index 100% rename from src/test.cpp rename to source/test.cpp diff --git a/src/bob.cpp b/src/bob.cpp deleted file mode 100644 index 5d9dbeb..0000000 --- a/src/bob.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include -#include -#include -#include "../headers/Lexer.h" - -#define VERSION "0.0.1" - -using namespace std; - -class Bob -{ -public: - Lexer lexer; - -public: - void runFile(string path) - { - ifstream file = ifstream(path); - - string source = ""; - - if(file.is_open()){ - source = string(istreambuf_iterator(file), istreambuf_iterator()); - } - else - { - cout << "File not found" << endl; - return; - } - - this->run(source); - } - - void runPrompt() - { - cout << "Bob v" << VERSION << ", 2023" << endl; - for(;;) - { - string line; - cout << "-> "; - std::getline(std::cin, line); - - if(std::cin.eof()) - { - break; - } - - this->run(line); - hadError = false; - } - } - - void error(int line, string message) - { - - } - - -private: - bool hadError = false; - -private: - void run(string source) - { - vector tokens = lexer.Tokenize(source); - - for(Token t : tokens){ - cout << "{type: " << t.type << ", value: " << t.lexeme << "}" << endl; - } - } - - void report(int line, string where, string message) - { - hadError = true; - } -}; -int main(){ - - // string TokenTypeMappings[] = { - // "Identifier", - // "Number", - // "Equals", - // "OpenParen", - // "CloseParen", - // "BinaryOperator", - // "TestKeyword" - // }; - - Bob bobLang; - - bobLang.runFile("source.bob"); - //bobLang.runPrompt(); - - - return 0; -} diff --git a/testthing b/testthing new file mode 100644 index 0000000..c250188 --- /dev/null +++ b/testthing @@ -0,0 +1,35 @@ +struct BinaryExpr : Expr +{ + const Expr left; + const Token oper; + const Expr right; + + BinaryExpr(Expr left, Token oper, Expr right) : left(left), oper(oper), right(right) + { + } +}; +struct GroupingExpr : Expr +{ + const Expr expression; + + GroupingExpr(Expr expression) : expression(expression) + { + } +}; +struct LiteralExpr : Expr +{ + const std::string value; + + LiteralExpr(std::string value) : value(value) + { + } +}; +struct UnaryExpr : Expr +{ + const Token oper; + const Expr right; + + UnaryExpr(Token oper, Expr right) : oper(oper), right(right) + { + } +}; diff --git a/tools/GenerateAST b/tools/GenerateAST new file mode 100755 index 0000000000000000000000000000000000000000..20ee1aedd57083fc1b5d6668de7508df2586d63d GIT binary patch literal 84424 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 literal 0 HcmV?d00001 diff --git a/tools/GenerateAST.cpp b/tools/GenerateAST.cpp new file mode 100644 index 0000000..ae78bb9 --- /dev/null +++ b/tools/GenerateAST.cpp @@ -0,0 +1,72 @@ +// +// Created by Bobby Lucero on 5/21/23. +// +#include +#include +#include +#include "../headers/helperFunctions/HelperFunctions.h" + +void defineType(std::ofstream &out, std::string baseName, std::string className, std::string fieldList) +{ + out << "struct " << className << "Expr : " << baseName << "\n{\n"; + std::vector fields = splitString(fieldList, ", "); + for(std::string field : fields) + { + out << " const " << trim(field) << ";\n"; + } + + out << "\n " << className << "Expr(" << fieldList << ") : "; + + std::string explicitDeclaration; + for(std::string field : fields) + { + std::string name = splitString(trim(field), " ")[1]; + + explicitDeclaration += trim(name) + "(" + trim(name) + "), "; + } + explicitDeclaration = trim(explicitDeclaration); + explicitDeclaration.pop_back(); + + out << explicitDeclaration; + + out << "\n {\n"; + out << " }\n"; + out << "};" << std::endl; +} + +void defineAst(std::string outputDir, std::string baseName, const std::vector& types) +{ + std::ofstream outFile(outputDir); + + if(outFile.is_open()) + { + for(std::string type : types) + { + std::vector type_split = splitString(type, "$"); + std::string className = trim(type_split[0]); + std::string fields = trim(type_split[1]); + defineType(outFile, baseName, className, fields); + } + } +} + + + +int main(int argc, char* argv[]){ + if(argc != 2) + { + std::cerr << "Usage " << argv[0] << " " << std::endl; + std::exit(64); + } + std::string outputDir = argv[1]; + + defineAst(outputDir, "Expr", { + "Binary $ Expr left, Token oper, Expr right", + "Grouping $ Expr expression", + "Literal $ std::string value", + "Unary $ Token oper, Expr right" + }); +} + + +