diff --git a/code/compiler/13/CMakeLists.txt b/code/compiler/13/CMakeLists.txt index 3ddf289..67a048d 100644 --- a/code/compiler/13/CMakeLists.txt +++ b/code/compiler/13/CMakeLists.txt @@ -38,6 +38,8 @@ add_executable(compiler graph.cpp graph.hpp global_scope.cpp global_scope.hpp parse_driver.cpp parse_driver.hpp + mangler.cpp mangler.hpp + compiler.cpp compiler.hpp ${BISON_parser_OUTPUTS} ${FLEX_scanner_OUTPUTS} main.cpp diff --git a/code/compiler/13/ast.cpp b/code/compiler/13/ast.cpp index 2305430..b6ce2e9 100644 --- a/code/compiler/13/ast.cpp +++ b/code/compiler/13/ast.cpp @@ -57,9 +57,8 @@ void ast_lid::translate(global_scope& scope) { void ast_lid::compile(const env_ptr& env, std::vector& into) const { into.push_back(instruction_ptr( (this->env->is_global(id)) ? - (instruction*) new instruction_pushglobal(id) : - (instruction*) new instruction_push( - env->get_offset(this->env->get_mangled_name(id))))); + (instruction*) new instruction_pushglobal(this->env->get_mangled_name(id)) : + (instruction*) new instruction_push(env->get_offset(id)))); } void ast_uid::print(int indent, std::ostream& to) const { diff --git a/code/compiler/13/binop.hpp b/code/compiler/13/binop.hpp index 90b4c89..1a74323 100644 --- a/code/compiler/13/binop.hpp +++ b/code/compiler/13/binop.hpp @@ -1,4 +1,5 @@ #pragma once +#include #include enum binop { @@ -11,5 +12,10 @@ enum binop { LESS_EQUALS, }; +constexpr binop all_binops[] = { + PLUS, MINUS, TIMES, DIVIDE, MODULO, + EQUALS, LESS_EQUALS +}; + std::string op_name(binop op); std::string op_action(binop op); diff --git a/code/compiler/13/compiler.cpp b/code/compiler/13/compiler.cpp new file mode 100644 index 0000000..c94b156 --- /dev/null +++ b/code/compiler/13/compiler.cpp @@ -0,0 +1,181 @@ +#include "compiler.hpp" +#include "binop.hpp" +#include "error.hpp" +#include "global_scope.hpp" +#include "parse_driver.hpp" +#include "type.hpp" +#include "type_env.hpp" + +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Verifier.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Target/TargetOptions.h" +#include "llvm/Target/TargetMachine.h" + +void compiler::add_default_types() { + global_env->bind_type("Int", type_ptr(new type_internal("Int"))); + global_env->bind_type("Bool", type_ptr(new type_internal("Bool"))); +} + +void compiler::add_binop_type(binop op, type_ptr type) { + auto name = mng.new_mangled_name(op_action(op)); + binop_names[op] = name; + global_env->bind(op_name(op), std::move(type), visibility::global); + global_env->set_mangled_name(op_name(op), name); +} + +void compiler::add_default_function_types() { + type_ptr int_type = global_env->lookup_type("Int"); + assert(int_type != nullptr); + type_ptr int_type_app = type_ptr(new type_app(int_type)); + + type_ptr bool_type = global_env->lookup_type("Bool"); + assert(bool_type != nullptr); + type_ptr bool_type_app = type_ptr(new type_app(bool_type)); + + type_ptr closed_int_op_type( + new type_arr(int_type_app, type_ptr(new type_arr(int_type_app, int_type_app)))); + type_ptr compare_int_op_type( + new type_arr(int_type_app, type_ptr(new type_arr(int_type_app, bool_type_app)))); + + constexpr binop closed_ops[] = { PLUS, MINUS, TIMES, DIVIDE, MODULO }; + constexpr binop compare_ops[] = { EQUALS, LESS_EQUALS }; + for(auto& op : closed_ops) add_binop_type(op, closed_int_op_type); + for(auto& op : compare_ops) add_binop_type(op, compare_int_op_type); + + for(auto name : { "True", "False" }) { + global_env->bind(name, bool_type_app, visibility::global); + global_env->set_mangled_name(name, mng.new_mangled_name(name)); + } +} + +void compiler::parse() { + if(!driver.run_parse()) + throw compiler_error("failed to open file"); +} + +void compiler::typecheck() { + std::set free_variables; + global_defs.find_free(free_variables); + global_defs.typecheck(type_m, global_env); +} + +void compiler::translate() { + for(auto& data : global_defs.defs_data) { + data.second->into_globals(global_scp); + } + for(auto& defn : global_defs.defs_defn) { + auto& function = defn.second->into_global(global_scp); + function.body->env->parent->set_mangled_name(defn.first, function.name); + } +} + +void compiler::compile() { + global_scp.compile(); +} + +void compiler::create_llvm_binop(binop op) { + auto new_function = ctx.create_custom_function(binop_names.at(op), 2); + std::vector instructions; + instructions.push_back(instruction_ptr(new instruction_push(1))); + instructions.push_back(instruction_ptr(new instruction_eval())); + instructions.push_back(instruction_ptr(new instruction_push(1))); + instructions.push_back(instruction_ptr(new instruction_eval())); + instructions.push_back(instruction_ptr(new instruction_binop(op))); + instructions.push_back(instruction_ptr(new instruction_update(2))); + instructions.push_back(instruction_ptr(new instruction_pop(2))); + ctx.builder.SetInsertPoint(&new_function->getEntryBlock()); + for(auto& instruction : instructions) { + instruction->gen_llvm(ctx, new_function); + } + ctx.builder.CreateRetVoid(); +} + +void compiler::create_llvm_bool(bool b) { + auto new_function = ctx.create_custom_function(b ? "True" : "False", 0); + std::vector instructions; + instructions.push_back(instruction_ptr(new instruction_pushint(b))); + instructions.push_back(instruction_ptr(new instruction_update(0))); + ctx.builder.SetInsertPoint(&new_function->getEntryBlock()); + for(auto& instruction : instructions) { + instruction->gen_llvm(ctx, new_function); + } + ctx.builder.CreateRetVoid(); +} + +void compiler::generate_llvm() { + for(auto op : all_binops) { + create_llvm_binop(op); + } + create_llvm_bool(true); + create_llvm_bool(false); + + global_scp.generate_llvm(ctx); +} + +void compiler::output_llvm(const std::string& into) { + std::string targetTriple = llvm::sys::getDefaultTargetTriple(); + + llvm::InitializeNativeTarget(); + llvm::InitializeNativeTargetAsmParser(); + llvm::InitializeNativeTargetAsmPrinter(); + + std::string error; + const llvm::Target* target = + llvm::TargetRegistry::lookupTarget(targetTriple, error); + if (!target) { + std::cerr << error << std::endl; + } else { + std::string cpu = "generic"; + std::string features = ""; + llvm::TargetOptions options; + std::unique_ptr targetMachine( + target->createTargetMachine(targetTriple, cpu, features, + options, llvm::Optional())); + + ctx.module.setDataLayout(targetMachine->createDataLayout()); + ctx.module.setTargetTriple(targetTriple); + + std::error_code ec; + llvm::raw_fd_ostream file(into, ec, llvm::sys::fs::F_None); + if (ec) { + throw compiler_error("failed to open object file for writing"); + } else { + llvm::CodeGenFileType type = llvm::CGFT_ObjectFile; + llvm::legacy::PassManager pm; + if (targetMachine->addPassesToEmitFile(pm, file, NULL, type)) { + throw compiler_error("failed to add passes to pass manager"); + } else { + pm.run(ctx.module); + file.close(); + } + } + } +} + +compiler::compiler(const std::string& filename) + : file_m(), global_defs(), driver(file_m, global_defs, filename), + mng(), global_scp(mng), global_env(new type_env), type_m(), ctx() { + add_default_types(); + add_default_function_types(); +} + +void compiler::operator()(const std::string& into) { + parse(); + typecheck(); + translate(); + compile(); + generate_llvm(); + output_llvm(into); +} + +file_mgr& compiler::get_file_manager() { + return file_m; +} + +type_mgr& compiler::get_type_manager() { + return type_m; +} diff --git a/code/compiler/13/compiler.hpp b/code/compiler/13/compiler.hpp new file mode 100644 index 0000000..a5873be --- /dev/null +++ b/code/compiler/13/compiler.hpp @@ -0,0 +1,39 @@ +#pragma once +#include "binop.hpp" +#include "parse_driver.hpp" +#include "definition.hpp" +#include "type_env.hpp" +#include "type.hpp" +#include "global_scope.hpp" +#include "mangler.hpp" +#include "llvm_context.hpp" + +class compiler { + private: + std::map binop_names; + file_mgr file_m; + definition_group global_defs; + parse_driver driver; + mangler mng; + global_scope global_scp; + type_env_ptr global_env; + type_mgr type_m; + llvm_context ctx; + + void add_default_types(); + void add_binop_type(binop op, type_ptr type); + void add_default_function_types(); + void parse(); + void typecheck(); + void translate(); + void compile(); + void create_llvm_binop(binop op); + void create_llvm_bool(bool b); + void generate_llvm(); + void output_llvm(const std::string& into); + public: + compiler(const std::string& filename); + void operator()(const std::string& into); + file_mgr& get_file_manager(); + type_mgr& get_type_manager(); +}; diff --git a/code/compiler/13/error.cpp b/code/compiler/13/error.cpp index 06c83c3..7ed68c1 100644 --- a/code/compiler/13/error.cpp +++ b/code/compiler/13/error.cpp @@ -9,28 +9,28 @@ void compiler_error::print_about(std::ostream& to) { to << description << std::endl; } -void compiler_error::print_location(std::ostream& to, parse_driver& drv, bool highlight) { +void compiler_error::print_location(std::ostream& to, file_mgr& fm, bool highlight) { if(!loc) return; to << "occuring on line " << loc->begin.line << ":" << std::endl; - drv.print_location(to, *loc, highlight); + fm.print_location(to, *loc, highlight); } -void compiler_error::pretty_print(std::ostream& to, parse_driver& drv) { +void compiler_error::pretty_print(std::ostream& to, file_mgr& fm) { print_about(to); - print_location(to, drv); + print_location(to, fm); } const char* type_error::what() const noexcept { return "an error occured while checking the types of the program"; } -void type_error::pretty_print(std::ostream& to, parse_driver& drv) { +void type_error::pretty_print(std::ostream& to, file_mgr& fm) { print_about(to); - print_location(to, drv, true); + print_location(to, fm, true); } -void unification_error::pretty_print(std::ostream& to, parse_driver& drv, type_mgr& mgr) { - type_error::pretty_print(to, drv); +void unification_error::pretty_print(std::ostream& to, file_mgr& fm, type_mgr& mgr) { + type_error::pretty_print(to, fm); to << "the expected type was:" << std::endl; to << " \033[34m"; left->print(mgr, to); diff --git a/code/compiler/13/error.hpp b/code/compiler/13/error.hpp index c76df13..42a6404 100644 --- a/code/compiler/13/error.hpp +++ b/code/compiler/13/error.hpp @@ -17,9 +17,9 @@ struct compiler_error : std::exception { const char* what() const noexcept override; void print_about(std::ostream& to); - void print_location(std::ostream& to, parse_driver& drv, bool highlight = false); + void print_location(std::ostream& to, file_mgr& fm, bool highlight = false); - void pretty_print(std::ostream& to, parse_driver& drv); + void pretty_print(std::ostream& to, file_mgr& fm); }; struct type_error : compiler_error { @@ -29,7 +29,7 @@ struct type_error : compiler_error { : compiler_error(std::move(d), std::move(l)) {} const char* what() const noexcept override; - void pretty_print(std::ostream& to, parse_driver& drv); + void pretty_print(std::ostream& to, file_mgr& fm); }; struct unification_error : public type_error { @@ -40,5 +40,5 @@ struct unification_error : public type_error { : left(std::move(l)), right(std::move(r)), type_error("failed to unify types", std::move(loc)) {} - void pretty_print(std::ostream& to, parse_driver& drv, type_mgr& mgr); + void pretty_print(std::ostream& to, file_mgr& fm, type_mgr& mgr); }; diff --git a/code/compiler/13/global_scope.cpp b/code/compiler/13/global_scope.cpp index 2107703..62b45cc 100644 --- a/code/compiler/13/global_scope.cpp +++ b/code/compiler/13/global_scope.cpp @@ -36,14 +36,23 @@ void global_constructor::generate_llvm(llvm_context& ctx) { ctx.builder.CreateRetVoid(); } -global_function& global_scope::add_function(std::string n, std::vector ps, ast_ptr b) { - global_function* new_function = new global_function(mangle_name(n), std::move(ps), std::move(b)); +global_function& global_scope::add_function( + const std::string& n, + std::vector ps, + ast_ptr b) { + auto name = mng->new_mangled_name(n); + global_function* new_function = + new global_function(std::move(name), std::move(ps), std::move(b)); functions.push_back(global_function_ptr(new_function)); return *new_function; } -global_constructor& global_scope::add_constructor(std::string n, int8_t t, size_t a) { - global_constructor* new_constructor = new global_constructor(mangle_name(n), t, a); +global_constructor& global_scope::add_constructor( + const std::string& n, + int8_t t, + size_t a) { + auto name = mng->new_mangled_name(n); + global_constructor* new_constructor = new global_constructor(name, t, a); constructors.push_back(global_constructor_ptr(new_constructor)); return *new_constructor; } @@ -65,19 +74,3 @@ void global_scope::generate_llvm(llvm_context& ctx) { function->generate_llvm(ctx); } } - -std::string global_scope::mangle_name(const std::string& n) { - auto occurence_it = occurence_count.find(n); - int occurence = 0; - if(occurence_it != occurence_count.end()) { - occurence = occurence_it->second + 1; - } - occurence_count[n] = occurence; - - std::string final_name = n; - if (occurence != 0) { - final_name += "_"; - final_name += std::to_string(occurence); - } - return final_name; -} diff --git a/code/compiler/13/global_scope.hpp b/code/compiler/13/global_scope.hpp index 9f75ce3..e157493 100644 --- a/code/compiler/13/global_scope.hpp +++ b/code/compiler/13/global_scope.hpp @@ -4,6 +4,7 @@ #include #include #include "instruction.hpp" +#include "mangler.hpp" struct ast; using ast_ptr = std::unique_ptr; @@ -40,16 +41,18 @@ struct global_constructor { using global_constructor_ptr = std::unique_ptr; struct global_scope { - std::map occurence_count; std::vector functions; std::vector constructors; + mangler* mng; - global_function& add_function(std::string n, std::vector ps, ast_ptr b); - global_constructor& add_constructor(std::string n, int8_t t, size_t a); + global_scope(mangler& m) : mng(&m) {} + + global_function& add_function( + const std::string& n, + std::vector ps, + ast_ptr b); + global_constructor& add_constructor(const std::string& n, int8_t t, size_t a); void compile(); void generate_llvm(llvm_context& ctx); - - private: - std::string mangle_name(const std::string& n); }; diff --git a/code/compiler/13/main.cpp b/code/compiler/13/main.cpp index 188f299..4607e5b 100644 --- a/code/compiler/13/main.cpp +++ b/code/compiler/13/main.cpp @@ -1,214 +1,27 @@ #include "ast.hpp" #include -#include "binop.hpp" -#include "definition.hpp" -#include "graph.hpp" -#include "instruction.hpp" -#include "llvm_context.hpp" #include "parser.hpp" +#include "compiler.hpp" #include "error.hpp" -#include "type.hpp" -#include "parse_driver.hpp" -#include "type_env.hpp" -#include "llvm/IR/LegacyPassManager.h" -#include "llvm/IR/Verifier.h" -#include "llvm/Support/TargetSelect.h" -#include "llvm/Support/TargetRegistry.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Target/TargetOptions.h" -#include "llvm/Target/TargetMachine.h" void yy::parser::error(const yy::location& loc, const std::string& msg) { std::cerr << "An error occured: " << msg << std::endl; } -void prelude_types(definition_group& defs, type_env_ptr env) { - type_ptr int_type = type_ptr(new type_internal("Int")); - env->bind_type("Int", int_type); - type_ptr int_type_app = type_ptr(new type_app(int_type)); - - type_ptr bool_type = type_ptr(new type_internal("Bool")); - env->bind_type("Bool", bool_type); - type_ptr bool_type_app = type_ptr(new type_app(bool_type)); - - type_ptr binop_type = type_ptr(new type_arr( - int_type_app, - type_ptr(new type_arr(int_type_app, int_type_app)))); - type_ptr cmp_type = type_ptr(new type_arr( - int_type_app, - type_ptr(new type_arr(int_type_app, bool_type_app)))); - - constexpr binop number_ops[] = { PLUS, MINUS, TIMES, DIVIDE, MODULO }; - constexpr binop cmp_ops[] = { EQUALS, LESS_EQUALS }; - for(auto& op : number_ops) { - env->bind(op_name(op), binop_type, visibility::global); - env->set_mangled_name(op_name(op), op_action(op)); - } - for(auto& op : cmp_ops) { - env->bind(op_name(op), cmp_type, visibility::global); - env->set_mangled_name(op_name(op), op_action(op)); - } - - env->bind("True", bool_type_app, visibility::global); - env->bind("False", bool_type_app, visibility::global); -} - -void typecheck_program( - definition_group& defs, - type_mgr& mgr, type_env_ptr& env) { - prelude_types(defs, env); - - std::set free; - defs.find_free(free); - defs.typecheck(mgr, env); - -#ifdef DEBUG_OUT - for(auto& pair : defs.env->names) { - std::cout << pair.first << ": "; - pair.second.type->print(mgr, std::cout); - std::cout << std::endl; - } -#endif -} - -global_scope translate_program(definition_group& group) { - global_scope scope; - for(auto& data : group.defs_data) { - data.second->into_globals(scope); - } - for(auto& defn : group.defs_defn) { - auto& function = defn.second->into_global(scope); - function.body->env->parent->set_mangled_name(defn.first, function.name); - } - return scope; -} - -void output_llvm(llvm_context& ctx, const std::string& filename) { - std::string targetTriple = llvm::sys::getDefaultTargetTriple(); - - llvm::InitializeNativeTarget(); - llvm::InitializeNativeTargetAsmParser(); - llvm::InitializeNativeTargetAsmPrinter(); - - std::string error; - const llvm::Target* target = - llvm::TargetRegistry::lookupTarget(targetTriple, error); - if (!target) { - std::cerr << error << std::endl; - } else { - std::string cpu = "generic"; - std::string features = ""; - llvm::TargetOptions options; - std::unique_ptr targetMachine( - target->createTargetMachine(targetTriple, cpu, features, - options, llvm::Optional())); - - ctx.module.setDataLayout(targetMachine->createDataLayout()); - ctx.module.setTargetTriple(targetTriple); - - std::error_code ec; - llvm::raw_fd_ostream file(filename, ec, llvm::sys::fs::F_None); - if (ec) { - throw compiler_error("failed to open object file for writing"); - } else { - llvm::CodeGenFileType type = llvm::CGFT_ObjectFile; - llvm::legacy::PassManager pm; - if (targetMachine->addPassesToEmitFile(pm, file, NULL, type)) { - throw compiler_error("failed to add passes to pass manager"); - } else { - pm.run(ctx.module); - file.close(); - } - } - } -} - -void gen_llvm_internal_op(llvm_context& ctx, binop op) { - auto new_function = ctx.create_custom_function(op_action(op), 2); - std::vector instructions; - instructions.push_back(instruction_ptr(new instruction_push(1))); - instructions.push_back(instruction_ptr(new instruction_eval())); - instructions.push_back(instruction_ptr(new instruction_push(1))); - instructions.push_back(instruction_ptr(new instruction_eval())); - instructions.push_back(instruction_ptr(new instruction_binop(op))); - instructions.push_back(instruction_ptr(new instruction_update(2))); - instructions.push_back(instruction_ptr(new instruction_pop(2))); - ctx.builder.SetInsertPoint(&new_function->getEntryBlock()); - for(auto& instruction : instructions) { - instruction->gen_llvm(ctx, new_function); - } - ctx.builder.CreateRetVoid(); -} - -void gen_llvm_boolean_constructor(llvm_context& ctx, const std::string& s, bool b) { - auto new_function = ctx.create_custom_function(s, 0); - std::vector instructions; - instructions.push_back(instruction_ptr(new instruction_pushint(b))); - instructions.push_back(instruction_ptr(new instruction_update(0))); - ctx.builder.SetInsertPoint(&new_function->getEntryBlock()); - for(auto& instruction : instructions) { - instruction->gen_llvm(ctx, new_function); - } - ctx.builder.CreateRetVoid(); -} - -void gen_llvm(global_scope& scope) { - llvm_context ctx; - gen_llvm_internal_op(ctx, PLUS); - gen_llvm_internal_op(ctx, MINUS); - gen_llvm_internal_op(ctx, TIMES); - gen_llvm_internal_op(ctx, DIVIDE); - gen_llvm_internal_op(ctx, MODULO); - gen_llvm_internal_op(ctx, EQUALS); - gen_llvm_internal_op(ctx, LESS_EQUALS); - gen_llvm_boolean_constructor(ctx, "True", true); - gen_llvm_boolean_constructor(ctx, "False", false); - - scope.generate_llvm(ctx); - -#ifdef DEBUG_OUT - ctx.module.print(llvm::outs(), nullptr); -#endif - - output_llvm(ctx, "program.o"); -} - int main(int argc, char** argv) { if(argc != 2) { std::cerr << "please enter a file to compile." << std::endl; exit(1); } - parse_driver driver(argv[1]); - if(!driver.run_parse()) { - std::cerr << "failed to parse file " << argv[1] << std::endl; - exit(1); - } - - type_mgr mgr; - type_env_ptr env(new type_env); - -#ifdef DEBUG_OUT - for(auto& def_defn : driver.global_defs.defs_defn) { - std::cout << def_defn.second->name; - for(auto& param : def_defn.second->params) std::cout << " " << param; - std::cout << ":" << std::endl; - def_defn.second->body->print(1, std::cout); - - std::cout << std::endl; - } -#endif + compiler cmp(argv[1]); try { - typecheck_program(driver.global_defs, mgr, env); - global_scope scope = translate_program(driver.global_defs); - scope.compile(); - gen_llvm(scope); + cmp("program.o"); } catch(unification_error& err) { - err.pretty_print(std::cerr, driver, mgr); + err.pretty_print(std::cerr, cmp.get_file_manager(), cmp.get_type_manager()); } catch(type_error& err) { - err.pretty_print(std::cerr, driver); + err.pretty_print(std::cerr, cmp.get_file_manager()); } catch (compiler_error& err) { - err.pretty_print(std::cerr, driver); + err.pretty_print(std::cerr, cmp.get_file_manager()); } } diff --git a/code/compiler/13/mangler.cpp b/code/compiler/13/mangler.cpp new file mode 100644 index 0000000..3beb052 --- /dev/null +++ b/code/compiler/13/mangler.cpp @@ -0,0 +1,17 @@ +#include "mangler.hpp" + +std::string mangler::new_mangled_name(const std::string& n) { + auto occurence_it = occurence_count.find(n); + int occurence = 0; + if(occurence_it != occurence_count.end()) { + occurence = occurence_it->second + 1; + } + occurence_count[n] = occurence; + + std::string final_name = n; + if (occurence != 0) { + final_name += "_"; + final_name += std::to_string(occurence); + } + return final_name; +} diff --git a/code/compiler/13/mangler.hpp b/code/compiler/13/mangler.hpp new file mode 100644 index 0000000..d1017c9 --- /dev/null +++ b/code/compiler/13/mangler.hpp @@ -0,0 +1,9 @@ +#pragma once +#include +#include + +struct mangler { + std::map occurence_count; + + std::string new_mangled_name(const std::string& str); +}; diff --git a/code/compiler/13/parse_driver.cpp b/code/compiler/13/parse_driver.cpp index 99193c7..86c2fc7 100644 --- a/code/compiler/13/parse_driver.cpp +++ b/code/compiler/13/parse_driver.cpp @@ -2,44 +2,37 @@ #include "scanner.hpp" #include -bool parse_driver::run_parse() { - FILE* stream = fopen(file_name.c_str(), "r"); - if(!stream) return false; +file_mgr::file_mgr() : file_offset(0) { line_offsets.push_back(0); - yyscan_t scanner; - yylex_init(&scanner); - yyset_in(stream, scanner); - yy::parser parser(scanner, *this); - parser(); - yylex_destroy(scanner); - fclose(stream); - file_contents = string_stream.str(); - return true; } -void parse_driver::write(const char* buf, size_t len) { +void file_mgr::write(const char* buf, size_t len) { string_stream.write(buf, len); file_offset += len; } -void parse_driver::mark_line() { +void file_mgr::mark_line() { line_offsets.push_back(file_offset); } -size_t parse_driver::get_index(int line, int column) { - assert(line > 0 && line <= line_offsets.size()); - return line_offsets[line-1] + column - 1; +void file_mgr::finalize() { + file_contents = string_stream.str(); } -size_t parse_driver::get_line_end(int line) { +size_t file_mgr::get_index(int line, int column) const { + assert(line > 0 && line <= line_offsets.size()); + return line_offsets.at(line-1) + column - 1; +} + +size_t file_mgr::get_line_end(int line) const { if(line == line_offsets.size()) return file_contents.size(); return get_index(line+1, 1); } -void parse_driver::print_location( +void file_mgr::print_location( std::ostream& stream, const yy::location& loc, - bool highlight) { + bool highlight) const { size_t print_start = get_index(loc.begin.line, 1); size_t highlight_start = get_index(loc.begin.line, loc.begin.column); size_t highlight_end = get_index(loc.end.line, loc.end.column); @@ -51,3 +44,29 @@ void parse_driver::print_location( if(highlight) stream << "\033[0m"; stream.write(content + highlight_end, print_end - highlight_end); } + +bool parse_driver::run_parse() { + FILE* stream = fopen(file_name.c_str(), "r"); + if(!stream) return false; + yyscan_t scanner; + yylex_init(&scanner); + yyset_in(stream, scanner); + yy::parser parser(scanner, *this); + parser(); + yylex_destroy(scanner); + fclose(stream); + file_m->finalize(); + return true; +} + +yy::location& parse_driver::get_current_location() { + return location; +} + +file_mgr& parse_driver::get_file_manager() const { + return *file_m; +} + +definition_group& parse_driver::get_global_defs() const { + return *global_defs; +} diff --git a/code/compiler/13/parse_driver.hpp b/code/compiler/13/parse_driver.hpp index 4f22850..2364c58 100644 --- a/code/compiler/13/parse_driver.hpp +++ b/code/compiler/13/parse_driver.hpp @@ -11,29 +11,46 @@ struct parse_driver; void scanner_init(parse_driver* d, yyscan_t* scanner); void scanner_destroy(yyscan_t* scanner); -struct parse_driver { - std::string file_name; - std::ostringstream string_stream; - std::string file_contents; +class file_mgr { + private: + std::ostringstream string_stream; + std::string file_contents; - yy::location location; - size_t file_offset; - std::vector line_offsets; + size_t file_offset; + std::vector line_offsets; + public: + file_mgr(); - definition_group global_defs; + void write(const char* buffer, size_t len); + void mark_line(); + void finalize(); - parse_driver(const std::string& file) - : file_name(file), file_offset(0) {} + size_t get_index(int line, int column) const; + size_t get_line_end(int line) const; + void print_location( + std::ostream& stream, + const yy::location& loc, + bool highlight = true) const; +}; + +class parse_driver { + private: + std::string file_name; + yy::location location; + definition_group* global_defs; + file_mgr* file_m; + + public: + parse_driver( + file_mgr& mgr, + definition_group& defs, + const std::string& file) + : file_name(file), file_m(&mgr), global_defs(&defs) {} bool run_parse(); - void write(const char* buff, size_t len); - void mark_line(); - size_t get_index(int line, int column); - size_t get_line_end(int line); - void print_location( - std::ostream& stream, - const yy::location& loc, - bool highlight = true); + yy::location& get_current_location(); + file_mgr& get_file_manager() const; + definition_group& get_global_defs() const; }; #define YY_DECL yy::parser::symbol_type yylex(yyscan_t yyscanner, parse_driver& drv) diff --git a/code/compiler/13/parser.y b/code/compiler/13/parser.y index 528f75f..0791f76 100644 --- a/code/compiler/13/parser.y +++ b/code/compiler/13/parser.y @@ -68,7 +68,7 @@ using yyscan_t = void*; %% program - : definitions { $1.vis = visibility::global; std::swap(drv.global_defs, $1); } + : definitions { $1.vis = visibility::global; std::swap(drv.get_global_defs(), $1); } ; definitions diff --git a/code/compiler/13/scanner.hpp b/code/compiler/13/scanner.hpp new file mode 100644 index 0000000..383b6d6 --- /dev/null +++ b/code/compiler/13/scanner.hpp @@ -0,0 +1,492 @@ +#ifndef yyHEADER_H +#define yyHEADER_H 1 +#define yyIN_HEADER 1 + +#line 5 "scanner.hpp" + +#line 7 "scanner.hpp" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 6 +#define YY_FLEX_SUBMINOR_VERSION 4 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include +#include +#include +#include + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have . Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef SIZE_MAX +#define SIZE_MAX (~(size_t)0) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +/* begin standard C++ headers. */ + +/* TODO: this is always defined, so inline it */ +#define yyconst const + +#if defined(__GNUC__) && __GNUC__ >= 3 +#define yynoreturn __attribute__((__noreturn__)) +#else +#define yynoreturn +#endif + +/* An opaque pointer. */ +#ifndef YY_TYPEDEF_YY_SCANNER_T +#define YY_TYPEDEF_YY_SCANNER_T +typedef void* yyscan_t; +#endif + +/* For convenience, these vars (plus the bison vars far below) + are macros in the reentrant scanner. */ +#define yyin yyg->yyin_r +#define yyout yyg->yyout_r +#define yyextra yyg->yyextra_r +#define yyleng yyg->yyleng_r +#define yytext yyg->yytext_r +#define yylineno (YY_CURRENT_BUFFER_LVALUE->yy_bs_lineno) +#define yycolumn (YY_CURRENT_BUFFER_LVALUE->yy_bs_column) +#define yy_flex_debug yyg->yy_flex_debug_r + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + int yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +void yyrestart ( FILE *input_file , yyscan_t yyscanner ); +void yy_switch_to_buffer ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_create_buffer ( FILE *file, int size , yyscan_t yyscanner ); +void yy_delete_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yy_flush_buffer ( YY_BUFFER_STATE b , yyscan_t yyscanner ); +void yypush_buffer_state ( YY_BUFFER_STATE new_buffer , yyscan_t yyscanner ); +void yypop_buffer_state ( yyscan_t yyscanner ); + +YY_BUFFER_STATE yy_scan_buffer ( char *base, yy_size_t size , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_string ( const char *yy_str , yyscan_t yyscanner ); +YY_BUFFER_STATE yy_scan_bytes ( const char *bytes, int len , yyscan_t yyscanner ); + +void *yyalloc ( yy_size_t , yyscan_t yyscanner ); +void *yyrealloc ( void *, yy_size_t , yyscan_t yyscanner ); +void yyfree ( void * , yyscan_t yyscanner ); + +/* Begin user sect3 */ + +#define yywrap(yyscanner) (/*CONSTCOND*/1) +#define YY_SKIP_YYWRAP + +#define yytext_ptr yytext_r + +#ifdef YY_HEADER_EXPORT_START_CONDITIONS +#define INITIAL 0 + +#endif + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +int yylex_init (yyscan_t* scanner); + +int yylex_init_extra ( YY_EXTRA_TYPE user_defined, yyscan_t* scanner); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int yylex_destroy ( yyscan_t yyscanner ); + +int yyget_debug ( yyscan_t yyscanner ); + +void yyset_debug ( int debug_flag , yyscan_t yyscanner ); + +YY_EXTRA_TYPE yyget_extra ( yyscan_t yyscanner ); + +void yyset_extra ( YY_EXTRA_TYPE user_defined , yyscan_t yyscanner ); + +FILE *yyget_in ( yyscan_t yyscanner ); + +void yyset_in ( FILE * _in_str , yyscan_t yyscanner ); + +FILE *yyget_out ( yyscan_t yyscanner ); + +void yyset_out ( FILE * _out_str , yyscan_t yyscanner ); + + int yyget_leng ( yyscan_t yyscanner ); + +char *yyget_text ( yyscan_t yyscanner ); + +int yyget_lineno ( yyscan_t yyscanner ); + +void yyset_lineno ( int _line_number , yyscan_t yyscanner ); + +int yyget_column ( yyscan_t yyscanner ); + +void yyset_column ( int _column_no , yyscan_t yyscanner ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap ( yyscan_t yyscanner ); +#else +extern int yywrap ( yyscan_t yyscanner ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy ( char *, const char *, int , yyscan_t yyscanner); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen ( const char * , yyscan_t yyscanner); +#endif + +#ifndef YY_NO_INPUT + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int yylex (yyscan_t yyscanner); + +#define YY_DECL int yylex (yyscan_t yyscanner) +#endif /* !YY_DECL */ + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +#undef YY_NEW_FILE +#undef YY_FLUSH_BUFFER +#undef yy_set_bol +#undef yy_new_buffer +#undef yy_set_interactive +#undef YY_DO_BEFORE_ACTION + +#ifdef YY_DECL_IS_OURS +#undef YY_DECL_IS_OURS +#undef YY_DECL +#endif + +#ifndef yy_create_buffer_ALREADY_DEFINED +#undef yy_create_buffer +#endif +#ifndef yy_delete_buffer_ALREADY_DEFINED +#undef yy_delete_buffer +#endif +#ifndef yy_scan_buffer_ALREADY_DEFINED +#undef yy_scan_buffer +#endif +#ifndef yy_scan_string_ALREADY_DEFINED +#undef yy_scan_string +#endif +#ifndef yy_scan_bytes_ALREADY_DEFINED +#undef yy_scan_bytes +#endif +#ifndef yy_init_buffer_ALREADY_DEFINED +#undef yy_init_buffer +#endif +#ifndef yy_flush_buffer_ALREADY_DEFINED +#undef yy_flush_buffer +#endif +#ifndef yy_load_buffer_state_ALREADY_DEFINED +#undef yy_load_buffer_state +#endif +#ifndef yy_switch_to_buffer_ALREADY_DEFINED +#undef yy_switch_to_buffer +#endif +#ifndef yypush_buffer_state_ALREADY_DEFINED +#undef yypush_buffer_state +#endif +#ifndef yypop_buffer_state_ALREADY_DEFINED +#undef yypop_buffer_state +#endif +#ifndef yyensure_buffer_stack_ALREADY_DEFINED +#undef yyensure_buffer_stack +#endif +#ifndef yylex_ALREADY_DEFINED +#undef yylex +#endif +#ifndef yyrestart_ALREADY_DEFINED +#undef yyrestart +#endif +#ifndef yylex_init_ALREADY_DEFINED +#undef yylex_init +#endif +#ifndef yylex_init_extra_ALREADY_DEFINED +#undef yylex_init_extra +#endif +#ifndef yylex_destroy_ALREADY_DEFINED +#undef yylex_destroy +#endif +#ifndef yyget_debug_ALREADY_DEFINED +#undef yyget_debug +#endif +#ifndef yyset_debug_ALREADY_DEFINED +#undef yyset_debug +#endif +#ifndef yyget_extra_ALREADY_DEFINED +#undef yyget_extra +#endif +#ifndef yyset_extra_ALREADY_DEFINED +#undef yyset_extra +#endif +#ifndef yyget_in_ALREADY_DEFINED +#undef yyget_in +#endif +#ifndef yyset_in_ALREADY_DEFINED +#undef yyset_in +#endif +#ifndef yyget_out_ALREADY_DEFINED +#undef yyget_out +#endif +#ifndef yyset_out_ALREADY_DEFINED +#undef yyset_out +#endif +#ifndef yyget_leng_ALREADY_DEFINED +#undef yyget_leng +#endif +#ifndef yyget_text_ALREADY_DEFINED +#undef yyget_text +#endif +#ifndef yyget_lineno_ALREADY_DEFINED +#undef yyget_lineno +#endif +#ifndef yyset_lineno_ALREADY_DEFINED +#undef yyset_lineno +#endif +#ifndef yyget_column_ALREADY_DEFINED +#undef yyget_column +#endif +#ifndef yyset_column_ALREADY_DEFINED +#undef yyset_column +#endif +#ifndef yywrap_ALREADY_DEFINED +#undef yywrap +#endif +#ifndef yyget_lval_ALREADY_DEFINED +#undef yyget_lval +#endif +#ifndef yyset_lval_ALREADY_DEFINED +#undef yyset_lval +#endif +#ifndef yyget_lloc_ALREADY_DEFINED +#undef yyget_lloc +#endif +#ifndef yyset_lloc_ALREADY_DEFINED +#undef yyset_lloc +#endif +#ifndef yyalloc_ALREADY_DEFINED +#undef yyalloc +#endif +#ifndef yyrealloc_ALREADY_DEFINED +#undef yyrealloc +#endif +#ifndef yyfree_ALREADY_DEFINED +#undef yyfree +#endif +#ifndef yytext_ALREADY_DEFINED +#undef yytext +#endif +#ifndef yyleng_ALREADY_DEFINED +#undef yyleng +#endif +#ifndef yyin_ALREADY_DEFINED +#undef yyin +#endif +#ifndef yyout_ALREADY_DEFINED +#undef yyout +#endif +#ifndef yy_flex_debug_ALREADY_DEFINED +#undef yy_flex_debug +#endif +#ifndef yylineno_ALREADY_DEFINED +#undef yylineno +#endif +#ifndef yytables_fload_ALREADY_DEFINED +#undef yytables_fload +#endif +#ifndef yytables_destroy_ALREADY_DEFINED +#undef yytables_destroy +#endif +#ifndef yyTABLES_NAME_ALREADY_DEFINED +#undef yyTABLES_NAME +#endif + +#line 49 "/home/vanilla/projects/blog-static/code/compiler/13/scanner.l" + + +#line 490 "scanner.hpp" +#undef yyIN_HEADER +#endif /* yyHEADER_H */ diff --git a/code/compiler/13/scanner.l b/code/compiler/13/scanner.l index e967d23..20f9b70 100644 --- a/code/compiler/13/scanner.l +++ b/code/compiler/13/scanner.l @@ -9,38 +9,41 @@ #include "parse_driver.hpp" #include "parser.hpp" -#define YY_USER_ACTION drv.write(yytext, yyleng); drv.location.step(); drv.location.columns(yyleng); +#define YY_USER_ACTION \ + drv.get_file_manager().write(yytext, yyleng); \ + LOC.step(); LOC.columns(yyleng); +#define LOC drv.get_current_location() %} %% -\n { drv.location.lines(); drv.mark_line(); } +\n { drv.get_current_location().lines(); drv.get_file_manager().mark_line(); } [ ]+ {} -\\ { return yy::parser::make_BACKSLASH(drv.location); } -\+ { return yy::parser::make_PLUS(drv.location); } -\* { return yy::parser::make_TIMES(drv.location); } -- { return yy::parser::make_MINUS(drv.location); } -\/ { return yy::parser::make_DIVIDE(drv.location); } -% { return yy::parser::make_MODULO(drv.location); } -== { return yy::parser::make_EQUALS(drv.location); } -\<= { return yy::parser::make_LESS_EQUALS(drv.location); } -` { return yy::parser::make_BACKTICK(drv.location); } -[0-9]+ { return yy::parser::make_INT(atoi(yytext), drv.location); } -defn { return yy::parser::make_DEFN(drv.location); } -data { return yy::parser::make_DATA(drv.location); } -case { return yy::parser::make_CASE(drv.location); } -of { return yy::parser::make_OF(drv.location); } -let { return yy::parser::make_LET(drv.location); } -in { return yy::parser::make_IN(drv.location); } -\{ { return yy::parser::make_OCURLY(drv.location); } -\} { return yy::parser::make_CCURLY(drv.location); } -\( { return yy::parser::make_OPAREN(drv.location); } -\) { return yy::parser::make_CPAREN(drv.location); } -, { return yy::parser::make_COMMA(drv.location); } --> { return yy::parser::make_ARROW(drv.location); } -= { return yy::parser::make_EQUAL(drv.location); } -[a-z][a-zA-Z]* { return yy::parser::make_LID(std::string(yytext), drv.location); } -[A-Z][a-zA-Z]* { return yy::parser::make_UID(std::string(yytext), drv.location); } -<> { return yy::parser::make_YYEOF(drv.location); } +\\ { return yy::parser::make_BACKSLASH(LOC); } +\+ { return yy::parser::make_PLUS(LOC); } +\* { return yy::parser::make_TIMES(LOC); } +- { return yy::parser::make_MINUS(LOC); } +\/ { return yy::parser::make_DIVIDE(LOC); } +% { return yy::parser::make_MODULO(LOC); } +== { return yy::parser::make_EQUALS(LOC); } +\<= { return yy::parser::make_LESS_EQUALS(LOC); } +` { return yy::parser::make_BACKTICK(LOC); } +[0-9]+ { return yy::parser::make_INT(atoi(yytext), LOC); } +defn { return yy::parser::make_DEFN(LOC); } +data { return yy::parser::make_DATA(LOC); } +case { return yy::parser::make_CASE(LOC); } +of { return yy::parser::make_OF(LOC); } +let { return yy::parser::make_LET(LOC); } +in { return yy::parser::make_IN(LOC); } +\{ { return yy::parser::make_OCURLY(LOC); } +\} { return yy::parser::make_CCURLY(LOC); } +\( { return yy::parser::make_OPAREN(LOC); } +\) { return yy::parser::make_CPAREN(LOC); } +, { return yy::parser::make_COMMA(LOC); } +-> { return yy::parser::make_ARROW(LOC); } += { return yy::parser::make_EQUAL(LOC); } +[a-z][a-zA-Z]* { return yy::parser::make_LID(std::string(yytext), LOC); } +[A-Z][a-zA-Z]* { return yy::parser::make_UID(std::string(yytext), LOC); } +<> { return yy::parser::make_YYEOF(LOC); } %% diff --git a/code/compiler/13/type_env.cpp b/code/compiler/13/type_env.cpp index 07f9a34..6f4fe6a 100644 --- a/code/compiler/13/type_env.cpp +++ b/code/compiler/13/type_env.cpp @@ -44,8 +44,7 @@ void type_env::set_mangled_name(const std::string& name, const std::string& mang const std::string& type_env::get_mangled_name(const std::string& name) const { auto it = names.find(name); - if(it != names.end()) - return (it->second.mangled_name != "") ? it->second.mangled_name : name; + if(it != names.end()) return it->second.mangled_name; assert(parent != nullptr); return parent->get_mangled_name(name); }