Skip to content

Commit

Permalink
feat(generator): added generator to main file
Browse files Browse the repository at this point in the history
  • Loading branch information
wesuRage committed Dec 12, 2024
1 parent 5b055d6 commit 0b7c9bf
Show file tree
Hide file tree
Showing 3 changed files with 206 additions and 71 deletions.
36 changes: 32 additions & 4 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,45 @@ 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)
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()
67 changes: 0 additions & 67 deletions src/main.c

This file was deleted.

174 changes: 174 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
#include <iostream>
#include <exception>
#include <vector>

#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/Verifier.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/MC/TargetRegistry.h>
#include <llvm/Target/TargetOptions.h>
#include <llvm/CodeGen/CommandFlags.h>
#include <llvm/IR/LegacyPassManager.h>
#include <llvm/Support/FileSystem.h>
#include <llvm/Support/raw_ostream.h>
#include <llvm/Support/Error.h>
#include <llvm/Target/TargetMachine.h>
#include <llvm/TargetParser/Host.h>
#include <llvm/Support/CodeGen.h>

#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 <source_file>\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<llvm::Value*> 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;
}

0 comments on commit 0b7c9bf

Please sign in to comment.