ADD: program and vm for integers.

main
bog 2023-09-17 21:36:58 +02:00
parent 04f57c631e
commit 8db23dbd3c
13 changed files with 450 additions and 5 deletions

View File

@ -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)

42
src/Compiler.cpp Normal file
View File

@ -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<node.size(); i++)
{
compile(*node.child_at(i), program);
program.append(OPCODE_POP);
}
} break;
case NODE_INT: {
size_t addr = program
.add_constant(std::make_shared<Constant>
(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;
}
}
}

26
src/Compiler.hpp Normal file
View File

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

38
src/Constant.cpp Normal file
View File

@ -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<int>(&(*m_value));
val)
{
return std::to_string(*val);
}
std::cerr << "cannot stringify "
<< (TypeStr[m_type] + strlen("TYPE_"))
<< std::endl;
abort();
}
}

34
src/Constant.hpp Normal file
View File

@ -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<std::variant<int>>;
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

View File

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

View File

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

68
src/Program.cpp Normal file
View File

@ -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> constant)
{
for (size_t i=0; i<const_size(); i++)
{
if (m_constant_pool[i]->equals(*constant))
{
return i;
}
}
m_constant_pool.push_back(constant);
return m_constant_pool.size() - 1;
}
std::shared_ptr<Constant> 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; i<size(); i++)
{
ss << i
<< "\t"
<< (OpcodeStr[m_instrs[i].opcode] + strlen("OPCODE_"))
<< "\t" << (m_instrs[i].param == NO_PARAM ? ""
: std::to_string(m_instrs[i].param))
<< "\n";
}
ss << "======== Constant Pool ========\n";
for (size_t i=0; i<const_size(); i++)
{
ss << i << "\t" << m_constant_pool[i]->string() << "\n";
}
return ss.str();
}
}

45
src/Program.hpp Normal file
View File

@ -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> constant);
std::shared_ptr<Constant> constant(size_t index) const;
std::string string() const;
private:
std::vector<Instr> m_instrs;
std::vector<std::shared_ptr<Constant>> m_constant_pool;
};
}
#endif

78
src/VM.cpp Normal file
View File

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

34
src/VM.hpp Normal file
View File

@ -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<Frame> m_frames;
std::vector<int> m_stack;
size_t m_pc = 0;
void push(int value);
int pop();
};
}
#endif

View File

@ -17,6 +17,7 @@
#include <cassert>
#include <fstream>
#include <variant>
#include <iostream>
#include <functional>
#include <unordered_map>

View File

@ -1,15 +1,71 @@
#include <iostream>
#include <getopt.h>
#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]... <source_file>" << "\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;