From b36e41de4cb4c194b41c2c43fd27421f3e8573c7 Mon Sep 17 00:00:00 2001 From: wesuRage Date: Wed, 11 Dec 2024 19:59:11 -0300 Subject: [PATCH 1/6] feat(ternary): added ternary to the assignment --- .../parser/expressions/parse_assignment_expr.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/frontend/parser/expressions/parse_assignment_expr.c b/src/frontend/parser/expressions/parse_assignment_expr.c index 388d613..d618671 100644 --- a/src/frontend/parser/expressions/parse_assignment_expr.c +++ b/src/frontend/parser/expressions/parse_assignment_expr.c @@ -6,6 +6,7 @@ #include "frontend/ast/definitions.h" #include "frontend/parser/expressions/parse_assignment_expr.h" #include "frontend/parser/expressions/parse_expr.h" +#include "frontend/parser/expressions/parse_ternary_expr.h" #include "frontend/parser/expressions/parse_object_expr.h" AstNode *parse_assignment_expr(Parser *parser) { @@ -13,12 +14,17 @@ AstNode *parse_assignment_expr(Parser *parser) { int column_start = at(parser).column_start; int position_start = at(parser).position_start; - AstNode *left = parse_object_expr(parser); + AstNode *left = parse_ternary_expr(parser); if (at(parser).type == TOKEN_ASSIGN) { eat(parser); - AstNode *value = parse_expr(parser); + AstNode *value; + + switch (at(parser).type) { + case TOKEN_OBRACE: value = parse_object_expr(parser); + default: value = parse_ternary_expr(parser); + } int column_end = at(parser).column_end - 1; int position_end = at(parser).position_end - 1; From ba421a5b042ff16d8438a3b40578a91e00a05bec Mon Sep 17 00:00:00 2001 From: wesuRage Date: Wed, 11 Dec 2024 19:59:51 -0300 Subject: [PATCH 2/6] feat(switch): added a switch for better checking of tokens --- src/frontend/parser/expressions/parse_expr.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/frontend/parser/expressions/parse_expr.c b/src/frontend/parser/expressions/parse_expr.c index 6713724..65b9735 100644 --- a/src/frontend/parser/expressions/parse_expr.c +++ b/src/frontend/parser/expressions/parse_expr.c @@ -6,7 +6,7 @@ #include "frontend/parser/expressions/parse_expr.h" #include "frontend/parser/expressions/parse_unary_expr.h" #include "frontend/parser/expressions/parse_assignment_expr.h" -#include "frontend/parser/expressions/binary_operations/parse_additive_expr.h" +#include "frontend/parser/expressions/binary_operations/parse_bitwise_expr.h" AstNode *parse_expr(Parser *parser) { if ( @@ -15,7 +15,21 @@ AstNode *parse_expr(Parser *parser) { || at(parser).type == TOKEN_BITWISE_NOT || at(parser).type == TOKEN_INCREMENT || at(parser).type == TOKEN_DECREMENT + || next(parser).type == TOKEN_INCREMENT + || next(parser).type == TOKEN_DECREMENT ) return parse_unary_expr(parser); - return parse_assignment_expr(parser); + switch (next(parser).type){ + case TOKEN_BITWISE_AND: + case TOKEN_BITWISE_OR: + case TOKEN_BITWISE_XOR: + case TOKEN_SHIFT_LEFT: + case TOKEN_SHIFT_RIGHT: + case TOKEN_PLUS: + case TOKEN_MINUS: + case TOKEN_MUL: + case TOKEN_DIV: + case TOKEN_MODULUS: return parse_bitwise_expr(parser); + default: return parse_assignment_expr(parser); + } } From cd0fc7a165caec58969e60aac4ec65b57a023e04 Mon Sep 17 00:00:00 2001 From: wesuRage Date: Wed, 11 Dec 2024 20:00:14 -0300 Subject: [PATCH 3/6] feat(bool): added bool to the lexer --- src/frontend/lexer/lexer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/frontend/lexer/lexer.c b/src/frontend/lexer/lexer.c index d7df51d..3f0e549 100644 --- a/src/frontend/lexer/lexer.c +++ b/src/frontend/lexer/lexer.c @@ -142,6 +142,7 @@ TokenType match_keyword(const char *lexeme) { if (strcmp(lexeme, "true") == 0) return TOKEN_TRUE; if (strcmp(lexeme, "false") == 0) return TOKEN_FALSE; if (strcmp(lexeme, "const") == 0) return TOKEN_CONST; + if (strcmp(lexeme, "bool") == 0) return TOKEN_TYPE_BOOL; if (strcmp(lexeme, "int") == 0) return TOKEN_TYPE_INT; if (strcmp(lexeme, "float") == 0) return TOKEN_TYPE_FLOAT; if (strcmp(lexeme, "double") == 0) return TOKEN_TYPE_DOUBLE; From 90eacdfae64aad6707e3b011930346fb40edbe84 Mon Sep 17 00:00:00 2001 From: wesuRage Date: Wed, 11 Dec 2024 20:11:29 -0300 Subject: [PATCH 4/6] feat(spaces): increased the space of print_indent --- src/frontend/parser/printer/print_indent.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/frontend/parser/printer/print_indent.c b/src/frontend/parser/printer/print_indent.c index 3c3aa2f..b2de774 100644 --- a/src/frontend/parser/printer/print_indent.c +++ b/src/frontend/parser/printer/print_indent.c @@ -10,6 +10,6 @@ */ void print_indent(int depth) { for (int i = 0; i < depth; i++) { - printf(" "); + printf(" "); } } \ No newline at end of file From b4cbc5c2200d774eb0de330e3903e61b7e8a699e Mon Sep 17 00:00:00 2001 From: wesuRage Date: Wed, 11 Dec 2024 20:12:13 -0300 Subject: [PATCH 5/6] feat(ternary): fully working ternary expressions --- examples/a.glx | 8 +------ .../printer/nodes/expressions/print_ternary.h | 9 ++++++++ .../printer/nodes/expressions/print_ternary.c | 21 +++++++++++++++++++ src/frontend/parser/printer/print_ast.c | 5 +++++ 4 files changed, 36 insertions(+), 7 deletions(-) create mode 100644 include/frontend/parser/printer/nodes/expressions/print_ternary.h create mode 100644 src/frontend/parser/printer/nodes/expressions/print_ternary.c diff --git a/examples/a.glx b/examples/a.glx index ca66200..0ebca6f 100644 --- a/examples/a.glx +++ b/examples/a.glx @@ -1,7 +1 @@ -def my_return( int i) -> int: - return i; -end; - -def main( ) -> int: - return my_return( 10) ; -end; +bool isBigger := 3 > 2 ? 1 : 0; \ No newline at end of file diff --git a/include/frontend/parser/printer/nodes/expressions/print_ternary.h b/include/frontend/parser/printer/nodes/expressions/print_ternary.h new file mode 100644 index 0000000..29766cd --- /dev/null +++ b/include/frontend/parser/printer/nodes/expressions/print_ternary.h @@ -0,0 +1,9 @@ +#ifndef PRINT_TERNARY_H +#define PRINT_TERNARY_H + +#include "frontend/ast/definitions.h" +#include "frontend/parser/printer/visited.h" + +void print_ternary(const AstNode *node, int depth, VisitedNodes *visited); + +#endif // PRINT_TERNARY_H \ No newline at end of file diff --git a/src/frontend/parser/printer/nodes/expressions/print_ternary.c b/src/frontend/parser/printer/nodes/expressions/print_ternary.c new file mode 100644 index 0000000..37c7737 --- /dev/null +++ b/src/frontend/parser/printer/nodes/expressions/print_ternary.c @@ -0,0 +1,21 @@ +#include "frontend/parser/printer/nodes/expressions/print_ternary.h" +#include "frontend/ast/definitions.h" +#include "frontend/parser/printer/print_indent.h" +#include "frontend/parser/printer/print_ast.h" +#include "frontend/parser/printer/visited.h" + +void print_ternary(const AstNode *node, int depth, VisitedNodes *visited){ + TernaryNode *ternary_data = (TernaryNode *)node->data; + + print_indent(depth + 1); + printf("Condition:\n"); + print_ast_node(ternary_data->condition, depth + 2, visited); + + print_indent(depth + 1); + printf("Consequent:\n"); + print_ast_node(ternary_data->consequent, depth + 2, visited); + + print_indent(depth + 1); + printf("Alternate:\n"); + print_ast_node(ternary_data->alternate, depth + 2, visited); +} \ No newline at end of file diff --git a/src/frontend/parser/printer/print_ast.c b/src/frontend/parser/printer/print_ast.c index 0316db8..b36f578 100644 --- a/src/frontend/parser/printer/print_ast.c +++ b/src/frontend/parser/printer/print_ast.c @@ -21,6 +21,7 @@ #include "frontend/parser/printer/nodes/expressions/print_boolean.h" #include "frontend/parser/printer/nodes/expressions/print_call.h" #include "frontend/parser/printer/nodes/expressions/print_return.h" +#include "frontend/parser/printer/nodes/expressions/print_ternary.h" #include "frontend/parser/printer/nodes/statements/print_import.h" #include "frontend/parser/printer/nodes/statements/print_package.h" @@ -113,6 +114,10 @@ void print_ast_node(const AstNode *node, int depth, VisitedNodes *visited) { print_boolean(node, depth); } break; + case NODE_TERNARY: { + print_ternary(node, depth, visited); + } break; + case NODE_RETURN: { print_return(node, depth, visited); } break; From 0b7c9bf801307f8960d878a7d91ba79c5728df4c Mon Sep 17 00:00:00 2001 From: wesuRage Date: Wed, 11 Dec 2024 21:07:45 -0300 Subject: [PATCH 6/6] feat(generator): added generator to main file --- CMakeLists.txt | 36 ++++++++-- src/main.c | 67 ------------------- src/main.cpp | 174 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 206 insertions(+), 71 deletions(-) delete mode 100644 src/main.c create mode 100644 src/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 283f05d..c78abba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,13 +9,9 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_C_COMPILER clang) set(CMAKE_CXX_COMPILER clang++) -# Define the main executable from the main.c file -add_executable(galaxy src/main.c) -target_include_directories(galaxy PRIVATE include) include_directories(${PROJECT_SOURCE_DIR}/include) # Link libraries to galaxy -target_link_libraries(galaxy PRIVATE arg_parse lexer parser node_definitions generator) # Add subdirectories for lexer, parser, and node_definitions add_subdirectory(src/args) @@ -23,3 +19,35 @@ add_subdirectory(src/frontend/lexer) add_subdirectory(src/frontend/parser) add_subdirectory(src/frontend/node_definitions) add_subdirectory(src/backend/generator) + +# Locate LLVM using llvm-config +find_package(LLVM REQUIRED CONFIG) + +# Retrieve LLVM flags +execute_process(COMMAND llvm-config --cxxflags OUTPUT_VARIABLE CMAKE_CXX_FLAGS) +execute_process(COMMAND llvm-config --libs OUTPUT_VARIABLE LLVM_LIBS) +execute_process(COMMAND llvm-config --system-libs OUTPUT_VARIABLE LLVM_SYS_LIBS) +execute_process(COMMAND llvm-config --ldflags OUTPUT_VARIABLE LLVM_LDFLAGS) + +# Strip trailing spaces and newlines +string(STRIP "${LLVM_LIBS}" LLVM_LIBS) +string(STRIP "${LLVM_SYS_LIBS}" LLVM_SYS_LIBS) +string(STRIP "${LLVM_LDFLAGS}" LLVM_LDFLAGS) +string(STRIP "${CMAKE_CXX_FLAGS}" CMAKE_CXX_FLAGS) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexceptions") + +# Include LLVM directories +include_directories(${LLVM_INCLUDE_DIRS}) +link_directories(${LLVM_LIBRARY_DIRS}) +add_definitions(${LLVM_DEFINITIONS}) + +# Link LLVM libraries +link_libraries(${LLVM_LIBS} ${LLVM_SYS_LIBS} ${LLVM_LDFLAGS}) + +# Create a test executable if the test file exists +if(EXISTS "src/main.cpp") +add_executable(galaxy src/main.cpp) + target_include_directories(galaxy PRIVATE ${PROJECT_SOURCE_DIR}/include ${LLVM_INCLUDE_DIRS}) + target_compile_options(galaxy PRIVATE ${CMAKE_CXX_FLAGS}) + target_link_libraries(galaxy PRIVATE arg_parse lexer parser node_definitions generator ${LLVM_LIBS} ${LLVM_SYS_LIBS}) +endif() \ No newline at end of file diff --git a/src/main.c b/src/main.c deleted file mode 100644 index 0a72c8b..0000000 --- a/src/main.c +++ /dev/null @@ -1,67 +0,0 @@ -#include -#include -#include "../include/frontend/lexer/core.h" -#include "../include/frontend/parser/core.h" -#include "../include/utils.h" -#include "../include/args/definitions.h" - -/** - * @brief Frees the memory allocated for an array of tokens. - * - * This function iterates over the array of tokens and frees the memory allocated for each token's lexeme and message. - * After freeing the memory for each token, it frees the memory for the array of tokens itself. - * - * @param tokens The array of tokens to be freed. - * @param tokenCount The number of tokens in the array. - */ -void freeTokens(Token *tokens, int tokenCount) { - if (tokens != NULL) { - for (int i = 0; i < tokenCount; i++) { - free(tokens[i].lexeme); - free(tokens[i].message); - } - free(tokens); - } -} - -/** - * @brief Entry point for the program. - * - * Processes a source file by tokenizing its contents, generating an abstract syntax tree (AST), - * and cleaning up allocated resources. - * - * @param argc Number of command-line arguments. - * @param argv Command-line arguments: program name and source file path. - * @return 0 on success, or a non-zero error code on failure. - */ -int main(int argc, char **argv) { - ArgParseResult args = arg_parse(argc, argv); - - //TODO: implement arg_parse function for flags - - free_arg_parse(&args); - - if (argc < 2) { - printf("Usage: %s \n", argv[0]); - return 1; - } - - char * arg_source_file = argv[1]; - - FILE *sourceFile; - if (!fopen_safe(sourceFile, argv[1], "r")) { - fprintf(stderr, "Error opening file '%s'\n", arg_source_file); - return 1; - } - - int count = 0; - Token *tokens = tokenize(sourceFile, arg_source_file, &count); - - Parser parser = parser_new(); - AstNode *ast = produce_ast(&parser, tokens, count); - - free_ast_node(ast); - freeTokens(tokens, count); - fclose(sourceFile); - return 0; -} diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..d569698 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,174 @@ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "backend/generator/generate_ir.hpp" + +extern "C" { + #include "frontend/lexer/core.h" + #include "utils.h" + #include "frontend/lexer/freeTokens.h" + #include "frontend/ast/definitions.h" + #include "frontend/parser/core.h" + #include "frontend/parser/printer/print_ast.h" + #include "frontend/getTokenTypeName.h" + #include "frontend/freeTokens.h" + #include "args/definitions.h" +} + + +/** + * @brief Entry point for the program. + * + * Processes a source file by tokenizing its contents, generating an abstract syntax tree (AST), + * and cleaning up allocated resources. + * + * @param argc Number of command-line arguments. + * @param argv Command-line arguments: program name and source file path. + * @return 0 on success, or a non-zero error code on failure. + */ +int main(int argc, char **argv) { + ArgParseResult args = arg_parse(argc, argv); + + //TODO: implement arg_parse function for flags + + free_arg_parse(&args); + + if (argc < 2) { + printf("Usage: %s \n", argv[0]); + return 1; + } + + char * arg_source_file = argv[1]; + + FILE *sourceFile; + if (!fopen_safe(sourceFile, argv[1], "r")) { + fprintf(stderr, "Error opening file '%s'\n", arg_source_file); + return 1; + } + + int count = 0; + Token *tokens = tokenize(sourceFile, arg_source_file, &count); + + Parser parser = parser_new(); + AstNode *ast = produce_ast(&parser, tokens, count); + + // Initialize LLVM target-related components (needed to generate machine code) + llvm::InitializeAllTargetInfos(); + llvm::InitializeAllTargets(); + llvm::InitializeAllTargetMCs(); + llvm::InitializeAllAsmParsers(); + llvm::InitializeAllAsmPrinters(); + + // Create the LLVM context, module, and IR builder + llvm::LLVMContext TheContext; + llvm::Module TheModule("GalaxyJIT", TheContext); + llvm::IRBuilder<> Builder(TheContext); + + // Generate the LLVM IR from the AST + std::vector values = generate_ir(ast, TheContext, TheModule, Builder); + + // Print out the generated LLVM IR for debugging + for (size_t i = 0; i < values.size(); ++i) { + if (values[i]) { + values[i]->print(llvm::errs()); // Print IR to error stream + std::cout << "\n"; + } else { + std::cerr << "Valor IR nulo encontrado no índice " << i << "\n"; // Handle NULL IR value + } + } + + // Verify the generated module for correctness + std::string errorMsg; + llvm::raw_string_ostream errorStream(errorMsg); + if (llvm::verifyModule(TheModule, &errorStream)) { + llvm::errs() << "Erro ao verificar o módulo:\n" << errorStream.str(); + free_ast_node(ast); // Free the AST if there's an error + freeTokens(tokens, count); // Free the tokens + fclose(sourceFile); // Close the source file + return 1; + } + + // Set the target triple (the target machine details) for code generation + auto TargetTriple = llvm::sys::getDefaultTargetTriple(); + TheModule.setTargetTriple(TargetTriple); + + std::string Error; + auto Target = llvm::TargetRegistry::lookupTarget(TargetTriple, Error); + + if (!Target) { + llvm::errs() << Error; + return 1; + } + + // Specify the target CPU and features (e.g., generic) + auto CPU = "generic"; + auto Features = ""; + + // Set the target options and create the target machine + llvm::TargetOptions opt; + auto TheTargetMachine = Target->createTargetMachine( + TargetTriple, CPU, Features, opt, llvm::Reloc::PIC_); + + // Set the data layout for the module based on the target machine + TheModule.setDataLayout(TheTargetMachine->createDataLayout()); + + // Write the generated IR to a file + auto IRFilename = "output.ll"; + std::error_code EC; + llvm::raw_fd_ostream IRFile(IRFilename, EC, llvm::sys::fs::OF_None); + + if (EC) { + llvm::errs() << "Could not open file: " << EC.message(); + return 1; + } + + TheModule.print(IRFile, nullptr); + IRFile.flush(); + llvm::outs() << "Wrote IR to " << IRFilename << "\n"; + + // Generate an object file from the IR using the target machine + auto ObjFilename = "output.o"; + llvm::raw_fd_ostream ObjFile(ObjFilename, EC, llvm::sys::fs::OF_None); + + if (EC) { + llvm::errs() << "Could not open file: " << EC.message(); + return 1; + } + + llvm::legacy::PassManager pass; + auto FileType = llvm::CodeGenFileType::ObjectFile; + + // Add passes to generate the object file + if (TheTargetMachine->addPassesToEmitFile(pass, ObjFile, nullptr, FileType)) { + llvm::errs() << "TheTargetMachine can't emit a file of this type"; + return 1; + } + + // Execute the passes to generate the object file + pass.run(TheModule); + ObjFile.flush(); + + llvm::outs() << "Wrote object file to " << ObjFilename << "\n"; + + free_ast_node(ast); + freeTokens(tokens, count); + fclose(sourceFile); + return 0; +}