From 8db23dbd3c372132b9b68b488cc0b937e7d29423 Mon Sep 17 00:00:00 2001 From: bog Date: Sun, 17 Sep 2023 21:36:58 +0200 Subject: [PATCH] ADD: program and vm for integers. --- meson.build | 6 +++- src/Compiler.cpp | 42 ++++++++++++++++++++++++++ src/Compiler.hpp | 26 ++++++++++++++++ src/Constant.cpp | 38 +++++++++++++++++++++++ src/Constant.hpp | 34 +++++++++++++++++++++ src/Module.cpp | 17 ++++++++++- src/Module.hpp | 6 +++- src/Program.cpp | 68 +++++++++++++++++++++++++++++++++++++++++ src/Program.hpp | 45 ++++++++++++++++++++++++++++ src/VM.cpp | 78 ++++++++++++++++++++++++++++++++++++++++++++++++ src/VM.hpp | 34 +++++++++++++++++++++ src/common.hpp | 1 + src/main.cpp | 60 +++++++++++++++++++++++++++++++++++-- 13 files changed, 450 insertions(+), 5 deletions(-) create mode 100644 src/Compiler.cpp create mode 100644 src/Compiler.hpp create mode 100644 src/Constant.cpp create mode 100644 src/Constant.hpp create mode 100644 src/Program.cpp create mode 100644 src/Program.hpp create mode 100644 src/VM.cpp create mode 100644 src/VM.hpp diff --git a/meson.build b/meson.build index 3dd5a81..3124f82 100644 --- a/meson.build +++ b/meson.build @@ -16,7 +16,11 @@ zarn_lib = shared_library('zarn', 'src/Node.cpp', 'src/Logger.cpp', 'src/Lexer.cpp', - 'src/Parser.cpp' + 'src/Parser.cpp', + 'src/Compiler.cpp', + 'src/Program.cpp', + 'src/VM.cpp', + 'src/Constant.cpp', ], install: true) diff --git a/src/Compiler.cpp b/src/Compiler.cpp new file mode 100644 index 0000000..535fadc --- /dev/null +++ b/src/Compiler.cpp @@ -0,0 +1,42 @@ +#include "Compiler.hpp" +#include "src/Node.hpp" +#include "src/Program.hpp" + +namespace zn +{ + /*explicit*/ Compiler::Compiler(Logger& logger) + : m_logger { logger } + { + } + + /*virtual*/ Compiler::~Compiler() + { + } + + void Compiler::compile(Node const& node, Program& program) + { + switch (node.type()) + { + case NODE_MODULE: { + for (size_t i=0; i + (TYPE_INT, std::stoi(node.repr()))); + program.append(OPCODE_LOAD_CONST, addr); + } break; + + default: { + std::cerr << "cannot compile node '" + << node.string() << "'" << std::endl; + abort(); + } break; + } + } +} diff --git a/src/Compiler.hpp b/src/Compiler.hpp new file mode 100644 index 0000000..b6fe70b --- /dev/null +++ b/src/Compiler.hpp @@ -0,0 +1,26 @@ +#ifndef zn_COMPILER_HPP +#define zn_COMPILER_HPP + +#include "common.hpp" +#include "Logger.hpp" +#include "Node.hpp" +#include "Program.hpp" + +namespace zn +{ + ZN_ERROR(compile_error); + + class Compiler + { + public: + explicit Compiler(Logger& logger); + virtual ~Compiler(); + + void compile(Node const& node, Program& program); + + private: + Logger& m_logger; + }; +} + +#endif diff --git a/src/Constant.cpp b/src/Constant.cpp new file mode 100644 index 0000000..2d610ef --- /dev/null +++ b/src/Constant.cpp @@ -0,0 +1,38 @@ +#include "Constant.hpp" + +namespace zn +{ + /*explicit*/ Constant::Constant(Type type, value_t value) + : m_type { type } + , m_value { value } + { + } + + /*virtual*/ Constant::~Constant() + { + } + + bool Constant::equals(Constant const& rhs) const + { + if (m_type != rhs.m_type) + { + return false; + } + + return m_value == rhs.m_value; + } + + std::string Constant::string() const + { + if (auto val = std::get_if(&(*m_value)); + val) + { + return std::to_string(*val); + } + + std::cerr << "cannot stringify " + << (TypeStr[m_type] + strlen("TYPE_")) + << std::endl; + abort(); + } +} diff --git a/src/Constant.hpp b/src/Constant.hpp new file mode 100644 index 0000000..07e6037 --- /dev/null +++ b/src/Constant.hpp @@ -0,0 +1,34 @@ +#ifndef zn_CONSTANT_HPP +#define zn_CONSTANT_HPP + +#include "common.hpp" + +#define TYPES(G) \ + G(TYPE_NIL), \ + G(TYPE_INT) + +namespace zn +{ + ZN_MK_ENUM(Type, TYPES); + + using value_t = std::optional>; + + class Constant + { + public: + explicit Constant(Type type, value_t value); + virtual ~Constant(); + + value_t value() const { return m_value; } + Type type() const { return m_type; } + + bool equals(Constant const& rhs) const; + std::string string() const; + + private: + Type m_type; + value_t m_value; + }; +} + +#endif diff --git a/src/Module.cpp b/src/Module.cpp index cfb80f5..a949b05 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -1,6 +1,9 @@ #include "Module.hpp" #include "Lexer.hpp" #include "Parser.hpp" +#include "Program.hpp" +#include "Compiler.hpp" +#include "VM.hpp" namespace zn { @@ -39,6 +42,18 @@ namespace zn Parser parser { m_logger }; auto ast = parser.parse(lexer.all()); - std::cout << ast->string() << std::endl; + + Compiler compiler { m_logger }; + compiler.compile(*ast, m_program); + + m_vm.execute(m_program); + } + + std::string Module::string() const + { + std::stringstream ss; + ss << m_program.string() << "\n"; + ss << m_vm.string() << "\n"; + return ss.str(); } } diff --git a/src/Module.hpp b/src/Module.hpp index fbc356a..e2d19a0 100644 --- a/src/Module.hpp +++ b/src/Module.hpp @@ -3,6 +3,8 @@ #include "common.hpp" #include "Logger.hpp" +#include "VM.hpp" +#include "Program.hpp" namespace zn { @@ -16,10 +18,12 @@ namespace zn void load_from_file(std::filesystem::path file_path); + std::string string() const; private: Logger& m_logger; std::string m_source; - + Program m_program; + VM m_vm; }; } diff --git a/src/Program.cpp b/src/Program.cpp new file mode 100644 index 0000000..db1ce11 --- /dev/null +++ b/src/Program.cpp @@ -0,0 +1,68 @@ +#include "Program.hpp" + +namespace zn +{ + /*explicit*/ Program::Program() + { + } + + /*virtual*/ Program::~Program() + { + } + + void Program::append(Opcode opcode, int param) + { + m_instrs.push_back(Instr {opcode, param}); + } + + Instr Program::instr(size_t index) const + { + assert(index < size()); + return m_instrs[index]; + } + + size_t Program::add_constant(std::shared_ptr constant) + { + for (size_t i=0; iequals(*constant)) + { + return i; + } + } + + m_constant_pool.push_back(constant); + return m_constant_pool.size() - 1; + } + + std::shared_ptr Program::constant(size_t index) const + { + assert(index < const_size()); + return m_constant_pool[index]; + } + + std::string Program::string() const + { + std::stringstream ss; + + ss << "======== Instructions ========\n"; + for (size_t i=0; istring() << "\n"; + } + + return ss.str(); + } +} diff --git a/src/Program.hpp b/src/Program.hpp new file mode 100644 index 0000000..4f86523 --- /dev/null +++ b/src/Program.hpp @@ -0,0 +1,45 @@ +#ifndef zn_PROGRAM_HPP +#define zn_PROGRAM_HPP + +#include "common.hpp" +#include "Constant.hpp" + +#define NO_PARAM (-1) + +#define OPCODES(G) \ + G(OPCODE_LOAD_CONST), \ + G(OPCODE_POP) + +namespace zn +{ + ZN_MK_ENUM(Opcode, OPCODES); + + struct Instr { + Opcode opcode; + int param; + }; + + class Program + { + public: + explicit Program(); + virtual ~Program(); + + size_t size() const { return m_instrs.size(); } + size_t const_size() const { return m_constant_pool.size(); } + + void append(Opcode opcode, int param=NO_PARAM); + Instr instr(size_t index) const; + + size_t add_constant(std::shared_ptr constant); + std::shared_ptr constant(size_t index) const; + + std::string string() const; + + private: + std::vector m_instrs; + std::vector> m_constant_pool; + }; +} + +#endif diff --git a/src/VM.cpp b/src/VM.cpp new file mode 100644 index 0000000..27aa3ec --- /dev/null +++ b/src/VM.cpp @@ -0,0 +1,78 @@ +#include "VM.hpp" +#include "src/Program.hpp" + +namespace zn +{ + /*explicit*/ VM::VM() + { + } + + /*virtual*/ VM::~VM() + { + } + + void VM::execute(Program& program) + { + m_pc = 0; + m_frames.push_back(Frame {program}); + + while (m_pc < program.size()) + { + auto instr = program.instr(m_pc); + execute(instr.opcode, instr.param); + } + } + + void VM::execute(Opcode opcode, int param) + { + switch (opcode) + { + case OPCODE_LOAD_CONST: { + push(param); + m_pc++; + } break; + + case OPCODE_POP: { + pop(); + m_pc++; + } break; + + default: { + std::cerr << "cannot execute opcode '" + << OpcodeStr[opcode] + << "'" << std::endl; + abort(); + } break; + } + } + + std::string VM::string() const + { + std::stringstream ss; + + ss << "======== VM Stack ========\n"; + + size_t addr = 0; + + for (int val: m_stack) + { + ss << addr << " " << val << "\n"; + addr++; + } + + return ss.str(); + } + + void VM::push(int value) + { + m_stack.push_back(value); + } + + int VM::pop() + { + assert(m_stack.size() > 0); + int value = m_stack.back(); + m_stack.pop_back(); + return value; + } +} diff --git a/src/VM.hpp b/src/VM.hpp new file mode 100644 index 0000000..63cd995 --- /dev/null +++ b/src/VM.hpp @@ -0,0 +1,34 @@ +#ifndef zn_VM_HPP +#define zn_VM_HPP + +#include "common.hpp" +#include "Program.hpp" + +namespace zn +{ + struct Frame { + Program& program; + }; + + class VM + { + public: + explicit VM(); + virtual ~VM(); + + void execute(Program& program); + void execute(Opcode opcode, int param); + + std::string string() const; + + private: + std::vector m_frames; + std::vector m_stack; + size_t m_pc = 0; + + void push(int value); + int pop(); + }; +} + +#endif diff --git a/src/common.hpp b/src/common.hpp index 664a6cc..3ff4e27 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include diff --git a/src/main.cpp b/src/main.cpp index a5e70df..718312a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,15 +1,71 @@ #include +#include #include "Module.hpp" int main(int argc, char** argv) { + bool debug_mode = false; - if (argc > 1) + while (true) + { + static struct option options[] = { + {"debug", no_argument, 0, 'd'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} + }; + + int opt_index; + int c = getopt_long(argc, argv, "hd", options, &opt_index); + + if (c == -1) { break; } + + switch (c) + { + case 'h': { + std::stringstream ss; + ss << "Usage: zarn [OPTIONS]... " << "\n"; + + ss << "\n\t" << "[OPTIONS]" << "\n"; + + ss << "\t" << "-d, --debug" + << "\t" << "show debug informations." << "\n"; + + ss << "\t" << "-h, --help" + << "\t" << "show this message." << "\n"; + std::cout << ss.str() << std::endl; + return 0; + } break; + + case 'd': { + debug_mode = true; + } break; + + default: break; + } + } + + if (optind < argc) { zn::Logger logger; zn::Module mod { logger }; - mod.load_from_file(argv[1]); + if (debug_mode) + { + mod.load_from_file(argv[optind]); + std::cout << mod.string() << std::endl; + } + else + { + try + { + mod.load_from_file(argv[optind]); + } + catch(std::exception const& err) + { + std::cerr << err.what() << std::endl; + return -1; + } + } } return 0;