Make some refactors for name mangling and encapsulation.

This commit is contained in:
Danila Fedorin 2020-09-15 18:51:28 -07:00
parent 18aac4c8fd
commit ed1f9a1460
18 changed files with 895 additions and 303 deletions

View File

@ -38,6 +38,8 @@ add_executable(compiler
graph.cpp graph.hpp graph.cpp graph.hpp
global_scope.cpp global_scope.hpp global_scope.cpp global_scope.hpp
parse_driver.cpp parse_driver.hpp parse_driver.cpp parse_driver.hpp
mangler.cpp mangler.hpp
compiler.cpp compiler.hpp
${BISON_parser_OUTPUTS} ${BISON_parser_OUTPUTS}
${FLEX_scanner_OUTPUTS} ${FLEX_scanner_OUTPUTS}
main.cpp main.cpp

View File

@ -57,9 +57,8 @@ void ast_lid::translate(global_scope& scope) {
void ast_lid::compile(const env_ptr& env, std::vector<instruction_ptr>& into) const { void ast_lid::compile(const env_ptr& env, std::vector<instruction_ptr>& into) const {
into.push_back(instruction_ptr( into.push_back(instruction_ptr(
(this->env->is_global(id)) ? (this->env->is_global(id)) ?
(instruction*) new instruction_pushglobal(id) : (instruction*) new instruction_pushglobal(this->env->get_mangled_name(id)) :
(instruction*) new instruction_push( (instruction*) new instruction_push(env->get_offset(id))));
env->get_offset(this->env->get_mangled_name(id)))));
} }
void ast_uid::print(int indent, std::ostream& to) const { void ast_uid::print(int indent, std::ostream& to) const {

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
#include <array>
#include <string> #include <string>
enum binop { enum binop {
@ -11,5 +12,10 @@ enum binop {
LESS_EQUALS, LESS_EQUALS,
}; };
constexpr binop all_binops[] = {
PLUS, MINUS, TIMES, DIVIDE, MODULO,
EQUALS, LESS_EQUALS
};
std::string op_name(binop op); std::string op_name(binop op);
std::string op_action(binop op); std::string op_action(binop op);

181
13/compiler.cpp Normal file
View File

@ -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<std::string> 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<instruction_ptr> 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<instruction_ptr> 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<llvm::TargetMachine> targetMachine(
target->createTargetMachine(targetTriple, cpu, features,
options, llvm::Optional<llvm::Reloc::Model>()));
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;
}

39
13/compiler.hpp Normal file
View File

@ -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, std::string> 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();
};

View File

@ -9,28 +9,28 @@ void compiler_error::print_about(std::ostream& to) {
to << description << std::endl; 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; if(!loc) return;
to << "occuring on line " << loc->begin.line << ":" << std::endl; 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_about(to);
print_location(to, drv); print_location(to, fm);
} }
const char* type_error::what() const noexcept { const char* type_error::what() const noexcept {
return "an error occured while checking the types of the program"; 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_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) { void unification_error::pretty_print(std::ostream& to, file_mgr& fm, type_mgr& mgr) {
type_error::pretty_print(to, drv); type_error::pretty_print(to, fm);
to << "the expected type was:" << std::endl; to << "the expected type was:" << std::endl;
to << " \033[34m"; to << " \033[34m";
left->print(mgr, to); left->print(mgr, to);

View File

@ -17,9 +17,9 @@ struct compiler_error : std::exception {
const char* what() const noexcept override; const char* what() const noexcept override;
void print_about(std::ostream& to); 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 { struct type_error : compiler_error {
@ -29,7 +29,7 @@ struct type_error : compiler_error {
: compiler_error(std::move(d), std::move(l)) {} : compiler_error(std::move(d), std::move(l)) {}
const char* what() const noexcept override; 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 { struct unification_error : public type_error {
@ -40,5 +40,5 @@ struct unification_error : public type_error {
: left(std::move(l)), right(std::move(r)), : left(std::move(l)), right(std::move(r)),
type_error("failed to unify types", std::move(loc)) {} 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);
}; };

View File

@ -36,14 +36,23 @@ void global_constructor::generate_llvm(llvm_context& ctx) {
ctx.builder.CreateRetVoid(); ctx.builder.CreateRetVoid();
} }
global_function& global_scope::add_function(std::string n, std::vector<std::string> ps, ast_ptr b) { global_function& global_scope::add_function(
global_function* new_function = new global_function(mangle_name(n), std::move(ps), std::move(b)); const std::string& n,
std::vector<std::string> 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)); functions.push_back(global_function_ptr(new_function));
return *new_function; return *new_function;
} }
global_constructor& global_scope::add_constructor(std::string n, int8_t t, size_t a) { global_constructor& global_scope::add_constructor(
global_constructor* new_constructor = new global_constructor(mangle_name(n), t, a); 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)); constructors.push_back(global_constructor_ptr(new_constructor));
return *new_constructor; return *new_constructor;
} }
@ -65,19 +74,3 @@ void global_scope::generate_llvm(llvm_context& ctx) {
function->generate_llvm(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;
}

View File

@ -4,6 +4,7 @@
#include <vector> #include <vector>
#include <llvm/IR/Function.h> #include <llvm/IR/Function.h>
#include "instruction.hpp" #include "instruction.hpp"
#include "mangler.hpp"
struct ast; struct ast;
using ast_ptr = std::unique_ptr<ast>; using ast_ptr = std::unique_ptr<ast>;
@ -40,16 +41,18 @@ struct global_constructor {
using global_constructor_ptr = std::unique_ptr<global_constructor>; using global_constructor_ptr = std::unique_ptr<global_constructor>;
struct global_scope { struct global_scope {
std::map<std::string, int> occurence_count;
std::vector<global_function_ptr> functions; std::vector<global_function_ptr> functions;
std::vector<global_constructor_ptr> constructors; std::vector<global_constructor_ptr> constructors;
mangler* mng;
global_function& add_function(std::string n, std::vector<std::string> ps, ast_ptr b); global_scope(mangler& m) : mng(&m) {}
global_constructor& add_constructor(std::string n, int8_t t, size_t a);
global_function& add_function(
const std::string& n,
std::vector<std::string> ps,
ast_ptr b);
global_constructor& add_constructor(const std::string& n, int8_t t, size_t a);
void compile(); void compile();
void generate_llvm(llvm_context& ctx); void generate_llvm(llvm_context& ctx);
private:
std::string mangle_name(const std::string& n);
}; };

View File

@ -1,214 +1,27 @@
#include "ast.hpp" #include "ast.hpp"
#include <iostream> #include <iostream>
#include "binop.hpp"
#include "definition.hpp"
#include "graph.hpp"
#include "instruction.hpp"
#include "llvm_context.hpp"
#include "parser.hpp" #include "parser.hpp"
#include "compiler.hpp"
#include "error.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) { void yy::parser::error(const yy::location& loc, const std::string& msg) {
std::cerr << "An error occured: " << msg << std::endl; 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<std::string> 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<llvm::TargetMachine> targetMachine(
target->createTargetMachine(targetTriple, cpu, features,
options, llvm::Optional<llvm::Reloc::Model>()));
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<instruction_ptr> 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<instruction_ptr> 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) { int main(int argc, char** argv) {
if(argc != 2) { if(argc != 2) {
std::cerr << "please enter a file to compile." << std::endl; std::cerr << "please enter a file to compile." << std::endl;
exit(1); exit(1);
} }
parse_driver driver(argv[1]); compiler cmp(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
try { try {
typecheck_program(driver.global_defs, mgr, env); cmp("program.o");
global_scope scope = translate_program(driver.global_defs);
scope.compile();
gen_llvm(scope);
} catch(unification_error& err) { } 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) { } catch(type_error& err) {
err.pretty_print(std::cerr, driver); err.pretty_print(std::cerr, cmp.get_file_manager());
} catch (compiler_error& err) { } catch (compiler_error& err) {
err.pretty_print(std::cerr, driver); err.pretty_print(std::cerr, cmp.get_file_manager());
} }
} }

17
13/mangler.cpp Normal file
View File

@ -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;
}

9
13/mangler.hpp Normal file
View File

@ -0,0 +1,9 @@
#pragma once
#include <string>
#include <map>
struct mangler {
std::map<std::string, int> occurence_count;
std::string new_mangled_name(const std::string& str);
};

View File

@ -2,44 +2,37 @@
#include "scanner.hpp" #include "scanner.hpp"
#include <sstream> #include <sstream>
bool parse_driver::run_parse() { file_mgr::file_mgr() : file_offset(0) {
FILE* stream = fopen(file_name.c_str(), "r");
if(!stream) return false;
line_offsets.push_back(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); string_stream.write(buf, len);
file_offset += len; file_offset += len;
} }
void parse_driver::mark_line() { void file_mgr::mark_line() {
line_offsets.push_back(file_offset); line_offsets.push_back(file_offset);
} }
size_t parse_driver::get_index(int line, int column) { void file_mgr::finalize() {
assert(line > 0 && line <= line_offsets.size()); file_contents = string_stream.str();
return line_offsets[line-1] + column - 1;
} }
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(); if(line == line_offsets.size()) return file_contents.size();
return get_index(line+1, 1); return get_index(line+1, 1);
} }
void parse_driver::print_location( void file_mgr::print_location(
std::ostream& stream, std::ostream& stream,
const yy::location& loc, const yy::location& loc,
bool highlight) { bool highlight) const {
size_t print_start = get_index(loc.begin.line, 1); 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_start = get_index(loc.begin.line, loc.begin.column);
size_t highlight_end = get_index(loc.end.line, loc.end.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"; if(highlight) stream << "\033[0m";
stream.write(content + highlight_end, print_end - highlight_end); 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;
}

View File

@ -11,29 +11,46 @@ struct parse_driver;
void scanner_init(parse_driver* d, yyscan_t* scanner); void scanner_init(parse_driver* d, yyscan_t* scanner);
void scanner_destroy(yyscan_t* scanner); void scanner_destroy(yyscan_t* scanner);
struct parse_driver { class file_mgr {
std::string file_name; private:
std::ostringstream string_stream; std::ostringstream string_stream;
std::string file_contents; std::string file_contents;
yy::location location;
size_t file_offset; size_t file_offset;
std::vector<size_t> line_offsets; std::vector<size_t> line_offsets;
public:
file_mgr();
definition_group global_defs; void write(const char* buffer, size_t len);
parse_driver(const std::string& file)
: file_name(file), file_offset(0) {}
bool run_parse();
void write(const char* buff, size_t len);
void mark_line(); void mark_line();
size_t get_index(int line, int column); void finalize();
size_t get_line_end(int line);
size_t get_index(int line, int column) const;
size_t get_line_end(int line) const;
void print_location( void print_location(
std::ostream& stream, std::ostream& stream,
const yy::location& loc, const yy::location& loc,
bool highlight = true); 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();
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) #define YY_DECL yy::parser::symbol_type yylex(yyscan_t yyscanner, parse_driver& drv)

View File

@ -68,7 +68,7 @@ using yyscan_t = void*;
%% %%
program 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 definitions

492
13/scanner.hpp Normal file
View File

@ -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 <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
/* end standard C headers. */
/* flex integer type definitions */
#ifndef FLEXINT_H
#define FLEXINT_H
/* C99 systems have <inttypes.h>. 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 <inttypes.h>
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 <unistd.h>
#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 */

View File

@ -9,38 +9,41 @@
#include "parse_driver.hpp" #include "parse_driver.hpp"
#include "parser.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_BACKSLASH(LOC); }
\+ { return yy::parser::make_PLUS(drv.location); } \+ { return yy::parser::make_PLUS(LOC); }
\* { return yy::parser::make_TIMES(drv.location); } \* { return yy::parser::make_TIMES(LOC); }
- { return yy::parser::make_MINUS(drv.location); } - { return yy::parser::make_MINUS(LOC); }
\/ { return yy::parser::make_DIVIDE(drv.location); } \/ { return yy::parser::make_DIVIDE(LOC); }
% { return yy::parser::make_MODULO(drv.location); } % { return yy::parser::make_MODULO(LOC); }
== { return yy::parser::make_EQUALS(drv.location); } == { return yy::parser::make_EQUALS(LOC); }
\<= { return yy::parser::make_LESS_EQUALS(drv.location); } \<= { return yy::parser::make_LESS_EQUALS(LOC); }
` { return yy::parser::make_BACKTICK(drv.location); } ` { return yy::parser::make_BACKTICK(LOC); }
[0-9]+ { return yy::parser::make_INT(atoi(yytext), drv.location); } [0-9]+ { return yy::parser::make_INT(atoi(yytext), LOC); }
defn { return yy::parser::make_DEFN(drv.location); } defn { return yy::parser::make_DEFN(LOC); }
data { return yy::parser::make_DATA(drv.location); } data { return yy::parser::make_DATA(LOC); }
case { return yy::parser::make_CASE(drv.location); } case { return yy::parser::make_CASE(LOC); }
of { return yy::parser::make_OF(drv.location); } of { return yy::parser::make_OF(LOC); }
let { return yy::parser::make_LET(drv.location); } let { return yy::parser::make_LET(LOC); }
in { return yy::parser::make_IN(drv.location); } in { return yy::parser::make_IN(LOC); }
\{ { return yy::parser::make_OCURLY(drv.location); } \{ { return yy::parser::make_OCURLY(LOC); }
\} { return yy::parser::make_CCURLY(drv.location); } \} { return yy::parser::make_CCURLY(LOC); }
\( { return yy::parser::make_OPAREN(drv.location); } \( { return yy::parser::make_OPAREN(LOC); }
\) { return yy::parser::make_CPAREN(drv.location); } \) { return yy::parser::make_CPAREN(LOC); }
, { return yy::parser::make_COMMA(drv.location); } , { return yy::parser::make_COMMA(LOC); }
-> { return yy::parser::make_ARROW(drv.location); } -> { return yy::parser::make_ARROW(LOC); }
= { return yy::parser::make_EQUAL(drv.location); } = { return yy::parser::make_EQUAL(LOC); }
[a-z][a-zA-Z]* { return yy::parser::make_LID(std::string(yytext), drv.location); } [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), drv.location); } [A-Z][a-zA-Z]* { return yy::parser::make_UID(std::string(yytext), LOC); }
<<EOF>> { return yy::parser::make_YYEOF(drv.location); } <<EOF>> { return yy::parser::make_YYEOF(LOC); }
%% %%

View File

@ -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 { const std::string& type_env::get_mangled_name(const std::string& name) const {
auto it = names.find(name); auto it = names.find(name);
if(it != names.end()) if(it != names.end()) return it->second.mangled_name;
return (it->second.mangled_name != "") ? it->second.mangled_name : name;
assert(parent != nullptr); assert(parent != nullptr);
return parent->get_mangled_name(name); return parent->get_mangled_name(name);
} }