ADD: program and vm for integers.
parent
04f57c631e
commit
8db23dbd3c
|
@ -16,7 +16,11 @@ zarn_lib = shared_library('zarn',
|
||||||
'src/Node.cpp',
|
'src/Node.cpp',
|
||||||
'src/Logger.cpp',
|
'src/Logger.cpp',
|
||||||
'src/Lexer.cpp',
|
'src/Lexer.cpp',
|
||||||
'src/Parser.cpp'
|
'src/Parser.cpp',
|
||||||
|
'src/Compiler.cpp',
|
||||||
|
'src/Program.cpp',
|
||||||
|
'src/VM.cpp',
|
||||||
|
'src/Constant.cpp',
|
||||||
],
|
],
|
||||||
install: true)
|
install: true)
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -1,6 +1,9 @@
|
||||||
#include "Module.hpp"
|
#include "Module.hpp"
|
||||||
#include "Lexer.hpp"
|
#include "Lexer.hpp"
|
||||||
#include "Parser.hpp"
|
#include "Parser.hpp"
|
||||||
|
#include "Program.hpp"
|
||||||
|
#include "Compiler.hpp"
|
||||||
|
#include "VM.hpp"
|
||||||
|
|
||||||
namespace zn
|
namespace zn
|
||||||
{
|
{
|
||||||
|
@ -39,6 +42,18 @@ namespace zn
|
||||||
Parser parser { m_logger };
|
Parser parser { m_logger };
|
||||||
|
|
||||||
auto ast = parser.parse(lexer.all());
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "Logger.hpp"
|
#include "Logger.hpp"
|
||||||
|
#include "VM.hpp"
|
||||||
|
#include "Program.hpp"
|
||||||
|
|
||||||
namespace zn
|
namespace zn
|
||||||
{
|
{
|
||||||
|
@ -16,10 +18,12 @@ namespace zn
|
||||||
|
|
||||||
void load_from_file(std::filesystem::path file_path);
|
void load_from_file(std::filesystem::path file_path);
|
||||||
|
|
||||||
|
std::string string() const;
|
||||||
private:
|
private:
|
||||||
Logger& m_logger;
|
Logger& m_logger;
|
||||||
std::string m_source;
|
std::string m_source;
|
||||||
|
Program m_program;
|
||||||
|
VM m_vm;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <variant>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
60
src/main.cpp
60
src/main.cpp
|
@ -1,15 +1,71 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <getopt.h>
|
||||||
#include "Module.hpp"
|
#include "Module.hpp"
|
||||||
|
|
||||||
int main(int argc, char** argv)
|
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::Logger logger;
|
||||||
zn::Module mod { 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;
|
return 0;
|
||||||
|
|
Reference in New Issue