diff --git a/code/compiler/06/CMakeLists.txt b/code/compiler/06/CMakeLists.txt index 9109901..2ad7e91 100644 --- a/code/compiler/06/CMakeLists.txt +++ b/code/compiler/06/CMakeLists.txt @@ -18,6 +18,7 @@ add_executable(compiler env.cpp env.hpp type.cpp type.hpp error.cpp error.hpp + binop.cpp binop.hpp ${BISON_parser_OUTPUTS} ${FLEX_scanner_OUTPUTS} main.cpp diff --git a/code/compiler/06/ast.cpp b/code/compiler/06/ast.cpp index f8a88df..7da9306 100644 --- a/code/compiler/06/ast.cpp +++ b/code/compiler/06/ast.cpp @@ -2,16 +2,6 @@ #include #include "error.hpp" -std::string op_name(binop op) { - switch(op) { - case PLUS: return "+"; - case MINUS: return "-"; - case TIMES: return "*"; - case DIVIDE: return "/"; - } - return "??"; -} - void print_indent(int n, std::ostream& to) { while(n--) to << " "; } @@ -25,6 +15,10 @@ type_ptr ast_int::typecheck(type_mgr& mgr, const type_env& env) const { return type_ptr(new type_base("Int")); } +void ast_int::compile(const env_ptr& env, std::vector& into) const { + into.push_back(instruction_ptr(new instruction_pushint(value))); +} + void ast_lid::print(int indent, std::ostream& to) const { print_indent(indent, to); to << "LID: " << id << std::endl; @@ -34,6 +28,10 @@ type_ptr ast_lid::typecheck(type_mgr& mgr, const type_env& env) const { return env.lookup(id); } +void ast_lid::compile(const env_ptr& env, std::vector& into) const { + into.push_back(instruction_ptr(new instruction_pushglobal(id))); +} + void ast_uid::print(int indent, std::ostream& to) const { print_indent(indent, to); to << "UID: " << id << std::endl; @@ -43,6 +41,13 @@ type_ptr ast_uid::typecheck(type_mgr& mgr, const type_env& env) const { return env.lookup(id); } +void ast_uid::compile(const env_ptr& env, std::vector& into) const { + into.push_back(instruction_ptr( + env->has_variable(id) ? + (instruction*) new instruction_push(env->get_offset(id)) : + (instruction*) new instruction_pushglobal(id))); +} + void ast_binop::print(int indent, std::ostream& to) const { print_indent(indent, to); to << "BINOP: " << op_name(op) << std::endl; @@ -64,6 +69,14 @@ type_ptr ast_binop::typecheck(type_mgr& mgr, const type_env& env) const { return return_type; } +void ast_binop::compile(const env_ptr& env, std::vector& into) const { + left->compile(env, into); + right->compile(env, into); + into.push_back(instruction_ptr(new instruction_pushglobal(op_name(op)))); + into.push_back(instruction_ptr(new instruction_mkapp())); + into.push_back(instruction_ptr(new instruction_mkapp())); +} + void ast_app::print(int indent, std::ostream& to) const { print_indent(indent, to); to << "APP:" << std::endl; @@ -81,6 +94,12 @@ type_ptr ast_app::typecheck(type_mgr& mgr, const type_env& env) const { return return_type; } +void ast_app::compile(const env_ptr& env, std::vector& into) const { + left->compile(env, into); + right->compile(env, into); + into.push_back(instruction_ptr(new instruction_mkapp())); +} + void ast_case::print(int indent, std::ostream& to) const { print_indent(indent, to); to << "CASE: " << std::endl; @@ -111,6 +130,10 @@ type_ptr ast_case::typecheck(type_mgr& mgr, const type_env& env) const { return branch_type; } +void ast_case::compile(const env_ptr& env, std::vector& into) const { + +} + void pattern_var::print(std::ostream& to) const { to << var; } diff --git a/code/compiler/06/ast.hpp b/code/compiler/06/ast.hpp index 232b39d..558fee1 100644 --- a/code/compiler/06/ast.hpp +++ b/code/compiler/06/ast.hpp @@ -12,8 +12,8 @@ struct ast { virtual void print(int indent, std::ostream& to) const = 0; virtual type_ptr typecheck(type_mgr& mgr, const type_env& env) const = 0; - virtual void compile(const env_ptr env, - std::vector& into) const; + virtual void compile(const env_ptr& env, + std::vector& into) const = 0; }; using ast_ptr = std::unique_ptr; @@ -64,6 +64,7 @@ struct ast_int : public ast { void print(int indent, std::ostream& to) const; type_ptr typecheck(type_mgr& mgr, const type_env& env) const; + void compile(const env_ptr& env, std::vector& into) const; }; struct ast_lid : public ast { @@ -74,6 +75,7 @@ struct ast_lid : public ast { void print(int indent, std::ostream& to) const; type_ptr typecheck(type_mgr& mgr, const type_env& env) const; + void compile(const env_ptr& env, std::vector& into) const; }; struct ast_uid : public ast { @@ -84,6 +86,7 @@ struct ast_uid : public ast { void print(int indent, std::ostream& to) const; type_ptr typecheck(type_mgr& mgr, const type_env& env) const; + void compile(const env_ptr& env, std::vector& into) const; }; struct ast_binop : public ast { @@ -96,6 +99,7 @@ struct ast_binop : public ast { void print(int indent, std::ostream& to) const; type_ptr typecheck(type_mgr& mgr, const type_env& env) const; + void compile(const env_ptr& env, std::vector& into) const; }; struct ast_app : public ast { @@ -107,6 +111,7 @@ struct ast_app : public ast { void print(int indent, std::ostream& to) const; type_ptr typecheck(type_mgr& mgr, const type_env& env) const; + void compile(const env_ptr& env, std::vector& into) const; }; struct ast_case : public ast { @@ -118,6 +123,7 @@ struct ast_case : public ast { void print(int indent, std::ostream& to) const; type_ptr typecheck(type_mgr& mgr, const type_env& env) const; + void compile(const env_ptr& env, std::vector& into) const; }; struct pattern_var : public pattern { diff --git a/code/compiler/06/binop.cpp b/code/compiler/06/binop.cpp new file mode 100644 index 0000000..3a5f0ca --- /dev/null +++ b/code/compiler/06/binop.cpp @@ -0,0 +1,21 @@ +#include "binop.hpp" + +std::string op_name(binop op) { + switch(op) { + case PLUS: return "+"; + case MINUS: return "-"; + case TIMES: return "*"; + case DIVIDE: return "/"; + } + return "??"; +} + +std::string op_action(binop op) { + switch(op) { + case PLUS: return "plus"; + case MINUS: return "minus"; + case TIMES: return "times"; + case DIVIDE: return "divide"; + } + return "??"; +} diff --git a/code/compiler/06/binop.hpp b/code/compiler/06/binop.hpp index 7c1382a..8d07858 100644 --- a/code/compiler/06/binop.hpp +++ b/code/compiler/06/binop.hpp @@ -1,4 +1,5 @@ #pragma once +#include enum binop { PLUS, @@ -7,3 +8,5 @@ enum binop { DIVIDE }; +std::string op_name(binop op); +std::string op_action(binop op); diff --git a/code/compiler/06/env.cpp b/code/compiler/06/env.cpp new file mode 100644 index 0000000..818cf5d --- /dev/null +++ b/code/compiler/06/env.cpp @@ -0,0 +1,23 @@ +#include "env.hpp" + +int env_var::get_offset(const std::string& name) const { + if(name == this->name) return 0; + if(parent) return parent->get_offset(name) + 1; + throw 0; +} + +bool env_var::has_variable(const std::string& name) const { + if(name == this->name) return true; + if(parent) return parent->has_variable(name); + return false; +} + +int env_offset::get_offset(const std::string& name) const { + if(parent) return parent->get_offset(name) + offset; + throw 0; +} + +bool env_offset::has_variable(const std::string& name) const { + if(parent) return parent->has_variable(name); + return false; +} diff --git a/code/compiler/06/env.hpp b/code/compiler/06/env.hpp index 718ddb9..02d9663 100644 --- a/code/compiler/06/env.hpp +++ b/code/compiler/06/env.hpp @@ -6,6 +6,7 @@ struct env { virtual ~env() = default; virtual int get_offset(const std::string& name) const = 0; + virtual bool has_variable(const std::string& name) const = 0; }; using env_ptr = std::shared_ptr; @@ -17,7 +18,8 @@ struct env_var { env_var(std::string& n, env_ptr p) : name(std::move(n)), parent(std::move(p)) {} - virtual int get_offset(const std::string& name) const; + int get_offset(const std::string& name) const; + bool has_variable(const std::string& name) const; }; struct env_offset { @@ -27,5 +29,6 @@ struct env_offset { env_offset(int o, env_ptr p) : offset(o), parent(std::move(p)) {} - virtual int get_offset(const std::string& name) const; + int get_offset(const std::string& name) const; + bool has_variable(const std::string& name) const; }; diff --git a/content/blog/06_compiler_semantics.md b/content/blog/06_compiler_semantics.md index ee90da4..cc21103 100644 --- a/content/blog/06_compiler_semantics.md +++ b/content/blog/06_compiler_semantics.md @@ -185,11 +185,26 @@ we see a variable that __isn't__ in the current environment, it must be a functi Having finished contemplating out method, it's time to define a signature: ```C++ -virtual void compile(const env_ptr env, std::vector& into) const; +virtual void compile(const env_ptr& env, std::vector& into) const; ``` -Ah, but now we have to define "environment". Let's do that: +Ah, but now we have to define "environment". Let's do that. Here's our header: {{< codeblock "C++" "compiler/06/env.hpp" >}} +And here's the source file: + +{{< codeblock "C++" "compiler/06/env.cpp" >}} + +{{< todo >}}Explain the code drops. {{< /todo >}} + +It will also help to move some of the functions on the `binop` enum +into a separate file. The new neader is pretty small: + +{{< codeblock "C++" "compiler/06/binop.hpp" >}} + +The new source file is not much longer: + +{{< codeblock "C++" "compiler/06/binop.cpp" >}} + And now, we begin our implementation.