Compare commits
No commits in common. "bd819bfc542ab14b9581186045e53141bcfa69a3" and "85a7af18b9448afa8549b2521a1c1116fe0c35e0" have entirely different histories.
bd819bfc54
...
85a7af18b9
|
@ -1,29 +1,4 @@
|
|||
PROG ::= INSTR*
|
||||
INSTR ::=
|
||||
| DIR
|
||||
| EXPR semicolon
|
||||
| FUNDECL
|
||||
| return EXPR semicolon
|
||||
| EXTERN semicolon
|
||||
EXTERN ::= extern fun ident opar PARAMS cpar RET
|
||||
FUNDECL ::= fun ident opar PARAMS cpar RET BLOCK
|
||||
PARAMS ::= (ident type? (comma ident type?)*)
|
||||
RET ::= type?
|
||||
BLOCK ::= obrace INSTR* cbrace
|
||||
|
||||
INSTR ::= DIR
|
||||
DIR ::= hash ident EXPR
|
||||
|
||||
EXPR ::=
|
||||
| ADDSUB
|
||||
|
||||
|
||||
ADDSUB ::= MULDIVMOD ((add|sub) MULDIVMOD)*
|
||||
MULDIVMOD ::= LITERAL ((mul|div|mod) LITERAL)*
|
||||
|
||||
LITERAL ::=
|
||||
| ident
|
||||
| int
|
||||
| CALL
|
||||
|
||||
CALL ::= ident opar ARGS cpar
|
||||
ARGS ::= (EXPR (comma EXPR)*)?
|
||||
EXPR ::= ident
|
||||
|
|
264
lib/Compiler.cpp
264
lib/Compiler.cpp
|
@ -1,277 +1,17 @@
|
|||
#include "Compiler.hpp"
|
||||
#include <llvm/IR/BasicBlock.h>
|
||||
#include <llvm/IR/Verifier.h>
|
||||
#include <llvm/IR/Type.h>
|
||||
#include <llvm/TargetParser/Host.h>
|
||||
#include <llvm/Target/TargetOptions.h>
|
||||
#include <llvm/Target/TargetMachine.h>
|
||||
#include <llvm/Support/TargetSelect.h>
|
||||
#include <llvm/Support/FileSystem.h>
|
||||
#include <llvm/MC/TargetRegistry.h>
|
||||
#include <llvm/IR/LegacyPassManager.h>
|
||||
|
||||
namespace wg
|
||||
{
|
||||
/*explicit*/ Compiler::Compiler()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*virtual*/ Compiler::~Compiler()
|
||||
{
|
||||
}
|
||||
|
||||
void Compiler::gen()
|
||||
void Compiler::compile(std::shared_ptr<Node> node)
|
||||
{
|
||||
auto target_triple = llvm::sys::getDefaultTargetTriple();
|
||||
llvm::InitializeAllTargetInfos();
|
||||
llvm::InitializeAllTargets();
|
||||
llvm::InitializeAllTargetMCs();
|
||||
llvm::InitializeAllAsmParsers();
|
||||
llvm::InitializeAllAsmPrinters();
|
||||
|
||||
std::string err;
|
||||
auto target = llvm::TargetRegistry::lookupTarget(target_triple, err);
|
||||
|
||||
if (!target)
|
||||
{
|
||||
llvm::errs() << err;
|
||||
abort();
|
||||
}
|
||||
|
||||
auto cpu = "generic";
|
||||
auto features = "";
|
||||
|
||||
llvm::TargetOptions opt;
|
||||
auto rm = std::optional<llvm::Reloc::Model>();
|
||||
auto target_machine = target->createTargetMachine(target_triple,
|
||||
cpu,
|
||||
features,
|
||||
opt,
|
||||
rm);
|
||||
|
||||
m_module->setDataLayout(target_machine->createDataLayout());
|
||||
m_module->setTargetTriple(target_triple);
|
||||
|
||||
auto filename = "output.o";
|
||||
std::error_code ec;
|
||||
|
||||
llvm::raw_fd_ostream dest(filename, ec, llvm::sys::fs::OF_None);
|
||||
WG_ASSERT(!ec, "cannot write output file.");
|
||||
|
||||
llvm::legacy::PassManager pass;
|
||||
auto file_type = llvm::CodeGenFileType::CGFT_ObjectFile;
|
||||
|
||||
if (target_machine->addPassesToEmitFile(pass, dest, nullptr, file_type))
|
||||
{
|
||||
llvm::errs() << "Target machine cannot emit a file of this type";
|
||||
}
|
||||
|
||||
llvm::verifyModule(*m_module);
|
||||
pass.run(*m_module);
|
||||
|
||||
dest.flush();
|
||||
m_module->print(llvm::errs(), nullptr);
|
||||
|
||||
|
||||
}
|
||||
|
||||
llvm::Value* Compiler::compile(std::shared_ptr<Node> node)
|
||||
{
|
||||
switch (node->type())
|
||||
{
|
||||
case NODE_PROG: {
|
||||
for (size_t i=0; i<node->size(); i++)
|
||||
{
|
||||
compile(node->child(i));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
} break;
|
||||
|
||||
case NODE_BLOCK: {
|
||||
for (size_t i=0; i<node->size(); i++)
|
||||
{
|
||||
compile(node->child(i));
|
||||
}
|
||||
return nullptr;
|
||||
} break;
|
||||
|
||||
case NODE_RETURN: {
|
||||
return m_builder->CreateRet(compile(node->child(0)));
|
||||
} break;
|
||||
|
||||
case NODE_EXTERN: {
|
||||
auto ident = node->child(0)->repr();
|
||||
auto params = node->child(1);
|
||||
auto ret = node->child(2);
|
||||
|
||||
std::vector<std::string> names;
|
||||
std::vector<llvm::Type*> types;
|
||||
|
||||
for (size_t i=0; i<params->size(); i++)
|
||||
{
|
||||
auto param = params->child(i);
|
||||
|
||||
if (param->type() == NODE_IDENT)
|
||||
{
|
||||
names.push_back(param->repr());
|
||||
}
|
||||
else if (param->type() == NODE_TYPE)
|
||||
{
|
||||
auto ty = llvm::Type::getInt32Ty(*m_context);
|
||||
|
||||
for (auto name: names)
|
||||
{
|
||||
m_sym->declare(name, ty, node->loc());
|
||||
types.push_back(ty);
|
||||
}
|
||||
|
||||
names.clear();
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Type* ret_type = llvm::Type::getVoidTy(*m_context);
|
||||
|
||||
if (ret->size() > 0)
|
||||
{
|
||||
ret_type = llvm::Type::getInt32Ty(*m_context);
|
||||
}
|
||||
|
||||
auto fun_type = llvm::FunctionType::get(ret_type, types, false);
|
||||
auto fun = llvm::Function::Create(fun_type,
|
||||
llvm::Function::ExternalLinkage,
|
||||
ident,
|
||||
*m_module);
|
||||
|
||||
m_sym->declare_prototype(ident, fun_type, node->loc());
|
||||
return fun;
|
||||
} break;
|
||||
|
||||
case NODE_FUNDECL: {
|
||||
auto ident = node->child(0)->repr();
|
||||
auto params = node->child(1);
|
||||
auto ret = node->child(2);
|
||||
|
||||
std::vector<std::string> names;
|
||||
std::vector<llvm::Type*> types;
|
||||
|
||||
for (size_t i=0; i<params->size(); i++)
|
||||
{
|
||||
auto param = params->child(i);
|
||||
|
||||
if (param->type() == NODE_IDENT)
|
||||
{
|
||||
names.push_back(param->repr());
|
||||
}
|
||||
else if (param->type() == NODE_TYPE)
|
||||
{
|
||||
auto ty = llvm::Type::getInt32Ty(*m_context);
|
||||
|
||||
for (auto name: names)
|
||||
{
|
||||
m_sym->declare(name, ty, node->loc());
|
||||
types.push_back(ty);
|
||||
}
|
||||
|
||||
names.clear();
|
||||
}
|
||||
}
|
||||
|
||||
llvm::Type* ret_type = llvm::Type::getVoidTy(*m_context);
|
||||
auto body = node->child(3);
|
||||
|
||||
if (ret->size() > 0)
|
||||
{
|
||||
ret_type = llvm::Type::getInt32Ty(*m_context);
|
||||
}
|
||||
|
||||
auto fun_type = llvm::FunctionType::get(ret_type, types, false);
|
||||
auto fun = llvm::Function::Create(fun_type,
|
||||
llvm::Function::ExternalLinkage,
|
||||
ident,
|
||||
*m_module);
|
||||
|
||||
m_sym->declare(ident, fun_type, node->loc());
|
||||
|
||||
llvm::BasicBlock* old_bb = m_builder->GetInsertBlock();
|
||||
|
||||
auto* bb = llvm::BasicBlock::Create(*m_context,
|
||||
"entry",
|
||||
fun);
|
||||
m_builder->SetInsertPoint(bb);
|
||||
|
||||
compile(body);
|
||||
|
||||
m_builder->SetInsertPoint(old_bb);
|
||||
|
||||
llvm::verifyFunction(*fun);
|
||||
|
||||
return fun;
|
||||
} break;
|
||||
|
||||
case NODE_CALL: {
|
||||
std::string ident = node->child(0)->repr();
|
||||
|
||||
auto fun = m_module->getFunction(ident);
|
||||
WG_ASSERT(fun, "cannot call unknown function '" + ident + "'");
|
||||
|
||||
std::vector<llvm::Value*> values;
|
||||
|
||||
for (size_t i=0; i<node->child(1)->size(); i++)
|
||||
{
|
||||
auto arg = node->child(1)->child(i);
|
||||
auto val = compile(arg);
|
||||
values.push_back(val);
|
||||
}
|
||||
|
||||
return m_builder->CreateCall(fun, values);
|
||||
} break;
|
||||
|
||||
case NODE_ADD: {
|
||||
auto* lhs = compile(node->child(0));
|
||||
auto* rhs = compile(node->child(1));
|
||||
return m_builder->CreateAdd(lhs, rhs);
|
||||
} break;
|
||||
|
||||
case NODE_SUB: {
|
||||
auto* lhs = compile(node->child(0));
|
||||
auto* rhs = compile(node->child(1));
|
||||
return m_builder->CreateSub(lhs, rhs);
|
||||
} break;
|
||||
|
||||
case NODE_MUL: {
|
||||
auto* lhs = compile(node->child(0));
|
||||
auto* rhs = compile(node->child(1));
|
||||
return m_builder->CreateMul(lhs, rhs);
|
||||
} break;
|
||||
|
||||
case NODE_DIV: {
|
||||
auto* lhs = compile(node->child(0));
|
||||
auto* rhs = compile(node->child(1));
|
||||
return m_builder->CreateSDiv(lhs, rhs);
|
||||
} break;
|
||||
|
||||
case NODE_MOD: {
|
||||
auto* lhs = compile(node->child(0));
|
||||
auto* rhs = compile(node->child(1));
|
||||
return m_builder->CreateSRem(lhs, rhs);
|
||||
} break;
|
||||
|
||||
case NODE_INT: {
|
||||
|
||||
return llvm::ConstantInt::get(*m_context,
|
||||
llvm::APInt(32,
|
||||
std::stoi(node->repr()),
|
||||
true));
|
||||
} break;
|
||||
|
||||
default:
|
||||
WG_ASSERT(false,
|
||||
std::string()
|
||||
+ "cannot compile unknown node '"
|
||||
+ NodeTypeStr[node->type()]
|
||||
+ "'");
|
||||
}
|
||||
std::cout << node->string() << std::endl;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
#include "commons.hpp"
|
||||
#include "Node.hpp"
|
||||
#include "SymTable.hpp"
|
||||
|
||||
namespace wg
|
||||
{
|
||||
|
@ -17,9 +16,7 @@ namespace wg
|
|||
explicit Compiler();
|
||||
virtual ~Compiler();
|
||||
|
||||
void gen();
|
||||
|
||||
llvm::Value* compile(std::shared_ptr<Node> node);
|
||||
void compile(std::shared_ptr<Node> node);
|
||||
private:
|
||||
std::unique_ptr<llvm::LLVMContext> m_context =
|
||||
std::make_unique<llvm::LLVMContext>();
|
||||
|
@ -29,8 +26,6 @@ namespace wg
|
|||
|
||||
std::unique_ptr<llvm::Module> m_module =
|
||||
std::make_unique<llvm::Module>("my module", *m_context);
|
||||
|
||||
std::unique_ptr<SymTable> m_sym = std::make_unique<SymTable>();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
104
lib/Lexer.cpp
104
lib/Lexer.cpp
|
@ -1,29 +1,11 @@
|
|||
#include "Lexer.hpp"
|
||||
#include "lib/Node.hpp"
|
||||
|
||||
namespace wg
|
||||
{
|
||||
/*explicit*/ Lexer::Lexer()
|
||||
{
|
||||
add_keyword("int", NODE_TYPE, true);
|
||||
add_keyword("fun", NODE_FUN);
|
||||
add_keyword("return", NODE_RETURN);
|
||||
add_keyword("extern", NODE_EXTERN);
|
||||
|
||||
add_text("{", NODE_OBRACE);
|
||||
add_text("}", NODE_CBRACE);
|
||||
add_text(",", NODE_COMMA);
|
||||
add_text("#", NODE_HASH);
|
||||
add_text("+", NODE_ADD);
|
||||
add_text("-", NODE_SUB);
|
||||
add_text("*", NODE_MUL);
|
||||
add_text("/", NODE_DIV);
|
||||
add_text("%", NODE_MOD);
|
||||
add_text("(", NODE_OPAR);
|
||||
add_text(")", NODE_CPAR);
|
||||
add_text(";", NODE_SEMICOLON);
|
||||
|
||||
m_scanners.push_back(std::bind(&Lexer::scan_int, this));
|
||||
m_scanners.push_back(std::bind(&Lexer::scan_ident, this));
|
||||
}
|
||||
|
||||
|
@ -43,18 +25,6 @@ namespace wg
|
|||
|
||||
skip_spaces();
|
||||
|
||||
while (m_cursor + 1 < m_source.size()
|
||||
&& m_source[m_cursor] == ':'
|
||||
&& m_source[m_cursor + 1] == ':')
|
||||
{
|
||||
while (m_source[m_cursor] != '\n')
|
||||
{
|
||||
m_cursor++;
|
||||
}
|
||||
|
||||
skip_spaces();
|
||||
}
|
||||
|
||||
for (auto scanner: m_scanners)
|
||||
{
|
||||
auto info = scanner();
|
||||
|
@ -107,20 +77,6 @@ namespace wg
|
|||
node, has_value));
|
||||
}
|
||||
|
||||
void Lexer::add_keyword(std::string const& text,
|
||||
NodeType node,
|
||||
bool has_value)
|
||||
{
|
||||
if (text.size() == 1)
|
||||
{
|
||||
m_seps.push_back(text[0]);
|
||||
}
|
||||
|
||||
m_scanners.push_back(std::bind(&Lexer::scan_keyword,
|
||||
this, text,
|
||||
node, has_value));
|
||||
}
|
||||
|
||||
bool Lexer::is_sep(size_t index) const
|
||||
{
|
||||
WG_ASSERT(index < m_source.size(), "cannot find separator");
|
||||
|
@ -175,35 +131,6 @@ namespace wg
|
|||
};
|
||||
}
|
||||
|
||||
std::optional<ScanInfo> Lexer::scan_keyword(std::string const& text,
|
||||
NodeType type,
|
||||
bool has_value) const
|
||||
{
|
||||
if (m_cursor + text.size() > m_source.size())
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
for (size_t i=0; i<text.size(); i++)
|
||||
{
|
||||
if (m_source[m_cursor + i] != text[i])
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_sep(m_cursor + text.size()))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return ScanInfo {
|
||||
m_cursor + text.size(),
|
||||
type,
|
||||
has_value ? text : ""
|
||||
};
|
||||
}
|
||||
|
||||
std::optional<ScanInfo> Lexer::scan_ident() const
|
||||
{
|
||||
size_t cursor = m_cursor;
|
||||
|
@ -227,35 +154,4 @@ namespace wg
|
|||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<ScanInfo> Lexer::scan_int() const
|
||||
{
|
||||
size_t cursor = m_cursor;
|
||||
std::string repr;
|
||||
|
||||
if (cursor < m_source.size()
|
||||
&& m_source[cursor] == '-')
|
||||
{
|
||||
repr += '-';
|
||||
cursor++;
|
||||
}
|
||||
|
||||
while (cursor < m_source.size()
|
||||
&& std::isdigit(m_source[cursor]))
|
||||
{
|
||||
repr += m_source[cursor];
|
||||
cursor++;
|
||||
}
|
||||
|
||||
if (repr.empty() || repr.back() == '-')
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return ScanInfo {
|
||||
cursor,
|
||||
NODE_INT,
|
||||
repr
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,10 +36,6 @@ namespace wg
|
|||
NodeType node,
|
||||
bool has_value=false);
|
||||
|
||||
void add_keyword(std::string const& text,
|
||||
NodeType node,
|
||||
bool has_value=false);
|
||||
|
||||
bool is_sep(size_t index) const;
|
||||
|
||||
void skip_spaces();
|
||||
|
@ -48,12 +44,8 @@ namespace wg
|
|||
NodeType type,
|
||||
bool has_value) const;
|
||||
|
||||
std::optional<ScanInfo> scan_keyword(std::string const& text,
|
||||
NodeType type,
|
||||
bool has_value) const;
|
||||
|
||||
std::optional<ScanInfo> scan_ident() const;
|
||||
std::optional<ScanInfo> scan_int() const;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -16,10 +16,10 @@ namespace wg
|
|||
int line() const { return m_line; }
|
||||
|
||||
template <typename T>
|
||||
void error(std::string const& what) const;
|
||||
void error(std::string const& what);
|
||||
|
||||
template <typename T>
|
||||
void error(std::stringstream const& what) const;
|
||||
void error(std::stringstream const& what);
|
||||
|
||||
private:
|
||||
std::filesystem::path m_origin;
|
||||
|
@ -27,7 +27,7 @@ namespace wg
|
|||
};
|
||||
|
||||
template <typename T>
|
||||
void Loc::error(std::string const& what) const
|
||||
void Loc::error(std::string const& what)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << m_origin.string() << ": ERROR " << what;
|
||||
|
@ -36,7 +36,7 @@ namespace wg
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
void Loc::error(std::stringstream const& what) const
|
||||
void Loc::error(std::stringstream const& what)
|
||||
{
|
||||
error<T>(what.str());
|
||||
}
|
||||
|
|
|
@ -20,9 +20,7 @@ namespace wg
|
|||
|
||||
std::shared_ptr<Node> Node::child(size_t index) const
|
||||
{
|
||||
WG_ASSERT(index < size(), "Cannot get child node of '"
|
||||
+ string()
|
||||
+ "'");
|
||||
WG_ASSERT(index < size(), "aze");
|
||||
return m_children.at(index);
|
||||
}
|
||||
|
||||
|
|
11
lib/Node.hpp
11
lib/Node.hpp
|
@ -8,16 +8,7 @@
|
|||
G(NODE_PROG), \
|
||||
G(NODE_IDENT), \
|
||||
G(NODE_HASH), \
|
||||
G(NODE_DIR), \
|
||||
G(NODE_INT), \
|
||||
G(NODE_ADD), G(NODE_SUB), \
|
||||
G(NODE_MUL),G(NODE_DIV), \
|
||||
G(NODE_MOD), G(NODE_OPAR), G(NODE_CPAR), \
|
||||
G(NODE_SEMICOLON), G(NODE_COMMA), G(NODE_CALL), \
|
||||
G(NODE_ARGS), G(NODE_TYPE), G(NODE_RETURN), \
|
||||
G(NODE_FUN), G(NODE_PARAMS), G(NODE_BLOCK), \
|
||||
G(NODE_OBRACE), G(NODE_CBRACE), G(NODE_FUNDECL), \
|
||||
G(NODE_EXTERN), G(NODE_RET)
|
||||
G(NODE_DIR),
|
||||
|
||||
namespace wg
|
||||
{
|
||||
|
|
233
lib/Parser.cpp
233
lib/Parser.cpp
|
@ -1,5 +1,4 @@
|
|||
#include "Parser.hpp"
|
||||
#include "lib/Node.hpp"
|
||||
|
||||
namespace wg
|
||||
{
|
||||
|
@ -22,26 +21,11 @@ namespace wg
|
|||
|
||||
Loc Parser::loc() const
|
||||
{
|
||||
if (m_cursor >= m_tokens.size())
|
||||
{
|
||||
return m_tokens.back()->loc();
|
||||
}
|
||||
|
||||
return m_tokens[m_cursor]->loc();
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::consume(NodeType type)
|
||||
{
|
||||
if (m_cursor >= m_tokens.size())
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "type mismatch, expected '"
|
||||
<< (NodeTypeStr[type] + strlen("NODE_"))
|
||||
<< "', got nothing.";
|
||||
|
||||
loc().error<syntax_error>(ss);
|
||||
}
|
||||
|
||||
auto current = m_tokens[m_cursor];
|
||||
|
||||
if (current->type() != type)
|
||||
|
@ -105,126 +89,10 @@ namespace wg
|
|||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_instr()
|
||||
{
|
||||
if (type_is(NODE_HASH))
|
||||
{
|
||||
return parse_dir();
|
||||
}
|
||||
|
||||
if (type_is(NODE_FUN))
|
||||
{
|
||||
return parse_fundecl();
|
||||
}
|
||||
|
||||
if (type_is(NODE_RETURN))
|
||||
{
|
||||
auto node = consume();
|
||||
node->add_child(parse_expr());
|
||||
consume(NODE_SEMICOLON);
|
||||
return node;
|
||||
}
|
||||
|
||||
if (type_is(NODE_EXTERN))
|
||||
{
|
||||
auto node = parse_extern();
|
||||
consume(NODE_SEMICOLON);
|
||||
return node;
|
||||
}
|
||||
|
||||
auto expr = parse_expr();
|
||||
consume(NODE_SEMICOLON);
|
||||
return expr;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_extern()
|
||||
{
|
||||
auto node = consume(NODE_EXTERN);
|
||||
consume(NODE_FUN);
|
||||
node->add_child(consume(NODE_IDENT));
|
||||
|
||||
consume(NODE_OPAR);
|
||||
node->add_child(parse_params());
|
||||
consume(NODE_CPAR);
|
||||
|
||||
node->add_child(parse_ret());
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_fundecl()
|
||||
{
|
||||
auto node = make_node(NODE_FUNDECL);
|
||||
consume(NODE_FUN);
|
||||
node->add_child(consume(NODE_IDENT));
|
||||
consume(NODE_OPAR);
|
||||
node->add_child(parse_params());
|
||||
consume(NODE_CPAR);
|
||||
|
||||
node->add_child(parse_ret());
|
||||
|
||||
node->add_child(parse_block());
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_params()
|
||||
{
|
||||
auto node = make_node(NODE_PARAMS);
|
||||
|
||||
if (type_is(NODE_CPAR))
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
node->add_child(consume(NODE_IDENT));
|
||||
|
||||
if (type_is(NODE_TYPE))
|
||||
{
|
||||
node->add_child(consume());
|
||||
}
|
||||
|
||||
while (type_is(NODE_COMMA))
|
||||
{
|
||||
consume();
|
||||
|
||||
node->add_child(consume(NODE_IDENT));
|
||||
|
||||
if (type_is(NODE_TYPE))
|
||||
{
|
||||
node->add_child(consume());
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_ret()
|
||||
{
|
||||
auto node = make_node(NODE_RET);
|
||||
|
||||
if (type_is(NODE_TYPE))
|
||||
{
|
||||
node->add_child(consume());
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_block()
|
||||
{
|
||||
auto node = make_node(NODE_BLOCK);
|
||||
consume(NODE_OBRACE);
|
||||
|
||||
while (type_isnt(NODE_CBRACE))
|
||||
{
|
||||
node->add_child(parse_instr());
|
||||
}
|
||||
|
||||
consume(NODE_CBRACE);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_dir()
|
||||
{
|
||||
auto node = make_node(NODE_DIR);
|
||||
|
@ -236,105 +104,6 @@ namespace wg
|
|||
|
||||
std::shared_ptr<Node> Parser::parse_expr()
|
||||
{
|
||||
return parse_addsub();
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_addsub()
|
||||
{
|
||||
auto lhs = parse_muldivmod();
|
||||
|
||||
while (type_is(NODE_ADD)
|
||||
|| type_is(NODE_SUB))
|
||||
{
|
||||
auto node = consume();
|
||||
node->add_child(lhs);
|
||||
node->add_child(parse_muldivmod());
|
||||
lhs = node;
|
||||
}
|
||||
|
||||
return lhs;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_muldivmod()
|
||||
{
|
||||
auto lhs = parse_literal();
|
||||
|
||||
while (type_is(NODE_MUL)
|
||||
|| type_is(NODE_DIV)
|
||||
|| type_is(NODE_MOD))
|
||||
{
|
||||
auto node = consume();
|
||||
node->add_child(lhs);
|
||||
node->add_child(parse_literal());
|
||||
lhs = node;
|
||||
}
|
||||
|
||||
return lhs;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_literal()
|
||||
{
|
||||
if (type_is(NODE_IDENT)
|
||||
&& type_is(NODE_OPAR, 1))
|
||||
{
|
||||
return parse_call();
|
||||
}
|
||||
|
||||
if (type_is(NODE_INT)
|
||||
|| type_is(NODE_IDENT))
|
||||
{
|
||||
return consume();
|
||||
}
|
||||
|
||||
// Groups
|
||||
if (type_is(NODE_OPAR))
|
||||
{
|
||||
consume(NODE_OPAR);
|
||||
|
||||
auto expr = parse_expr();
|
||||
|
||||
consume(NODE_CPAR);
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
loc().error<syntax_error>(std::string()
|
||||
+ "unknown literal '"
|
||||
+ (NodeTypeStr[m_tokens[m_cursor]->type()]
|
||||
+ strlen("NODE_"))
|
||||
+ "'");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_call()
|
||||
{
|
||||
auto node = make_node(NODE_CALL);
|
||||
node->add_child(consume(NODE_IDENT));
|
||||
|
||||
consume(NODE_OPAR);
|
||||
node->add_child(parse_args());
|
||||
consume(NODE_CPAR);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
std::shared_ptr<Node> Parser::parse_args()
|
||||
{
|
||||
auto node = make_node(NODE_ARGS);
|
||||
|
||||
if (type_is(NODE_CPAR))
|
||||
{
|
||||
return node;
|
||||
}
|
||||
|
||||
node->add_child(parse_expr());
|
||||
|
||||
while (type_is(NODE_COMMA))
|
||||
{
|
||||
consume();
|
||||
node->add_child(parse_expr());
|
||||
}
|
||||
|
||||
return node;
|
||||
return consume(NODE_IDENT);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,21 +30,9 @@ namespace wg
|
|||
|
||||
std::shared_ptr<Node> parse_prog();
|
||||
std::shared_ptr<Node> parse_instr();
|
||||
std::shared_ptr<Node> parse_extern();
|
||||
std::shared_ptr<Node> parse_fundecl();
|
||||
std::shared_ptr<Node> parse_params();
|
||||
std::shared_ptr<Node> parse_ret();
|
||||
std::shared_ptr<Node> parse_block();
|
||||
std::shared_ptr<Node> parse_dir();
|
||||
|
||||
std::shared_ptr<Node> parse_expr();
|
||||
|
||||
std::shared_ptr<Node> parse_addsub();
|
||||
std::shared_ptr<Node> parse_muldivmod();
|
||||
std::shared_ptr<Node> parse_literal();
|
||||
std::shared_ptr<Node> parse_call();
|
||||
std::shared_ptr<Node> parse_args();
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
#include "SymTable.hpp"
|
||||
#include "commons.hpp"
|
||||
|
||||
namespace wg
|
||||
{
|
||||
/*explicit*/ SymTable::SymTable()
|
||||
{
|
||||
}
|
||||
|
||||
/*virtual*/ SymTable::~SymTable()
|
||||
{
|
||||
}
|
||||
|
||||
bool SymTable::exists(std::string const& name) const
|
||||
{
|
||||
return m_entries.find(name) != std::end(m_entries);
|
||||
}
|
||||
|
||||
void SymTable::declare_prototype(std::string const& name,
|
||||
llvm::Type* type,
|
||||
Loc const& loc)
|
||||
{
|
||||
if (auto itr=m_entries.find(name);
|
||||
itr != std::end(m_entries))
|
||||
{
|
||||
loc.error<symbol_error>("cannot declare existing symbol '"
|
||||
+ name
|
||||
+ "'");
|
||||
}
|
||||
|
||||
SymEntry entry;
|
||||
entry.name = name;
|
||||
entry.type = type;
|
||||
entry.prototype = true;
|
||||
m_entries[name] = entry;
|
||||
}
|
||||
|
||||
void SymTable::declare(std::string const& name,
|
||||
llvm::Type* type,
|
||||
Loc const& loc)
|
||||
{
|
||||
if (auto itr=m_entries.find(name);
|
||||
itr != std::end(m_entries)
|
||||
&& itr->second.prototype == false)
|
||||
{
|
||||
loc.error<symbol_error>("cannot declare existing symbol '"
|
||||
+ name
|
||||
+ "'");
|
||||
}
|
||||
|
||||
SymEntry entry;
|
||||
entry.name = name;
|
||||
entry.type = type;
|
||||
entry.prototype = false;
|
||||
m_entries[name] = entry;
|
||||
}
|
||||
|
||||
void SymTable::set(std::string const& name,
|
||||
llvm::Type* type,
|
||||
Loc const& loc)
|
||||
{
|
||||
if (auto itr=m_entries.find(name);
|
||||
itr == std::end(m_entries))
|
||||
{
|
||||
loc.error<symbol_error>("cannot set inexisting symbol '"
|
||||
+ name
|
||||
+ "'");
|
||||
}
|
||||
|
||||
SymEntry entry;
|
||||
entry.name = name;
|
||||
entry.type = type;
|
||||
m_entries[name] = entry;
|
||||
}
|
||||
|
||||
SymEntry& SymTable::get(std::string const& name, Loc const& loc)
|
||||
{
|
||||
if (auto itr=m_entries.find(name);
|
||||
itr != std::end(m_entries))
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
loc.error<symbol_error>("cannot find symbol '" + name + "'");
|
||||
}
|
||||
|
||||
abort();
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
#ifndef wg_SYMTABLE_HPP
|
||||
#define wg_SYMTABLE_HPP
|
||||
|
||||
#include <llvm/IR/Type.h>
|
||||
#include "commons.hpp"
|
||||
#include "Loc.hpp"
|
||||
|
||||
namespace wg
|
||||
{
|
||||
WG_ERROR(symbol_error);
|
||||
|
||||
struct SymEntry {
|
||||
std::string name;
|
||||
llvm::Type* type;
|
||||
bool prototype = false;
|
||||
};
|
||||
|
||||
class SymTable
|
||||
{
|
||||
public:
|
||||
explicit SymTable();
|
||||
virtual ~SymTable();
|
||||
|
||||
bool exists(std::string const& name) const;
|
||||
|
||||
void declare_prototype(std::string const& name,
|
||||
llvm::Type* type,
|
||||
Loc const& loc);
|
||||
|
||||
void declare(std::string const& name, llvm::Type* type, Loc const& loc);
|
||||
void set(std::string const& name, llvm::Type* type, Loc const& loc);
|
||||
SymEntry& get(std::string const& name, Loc const& loc);
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, SymEntry> m_entries;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -15,7 +15,6 @@ wongola_lib = static_library(
|
|||
'lib/Parser.cpp',
|
||||
'lib/Compiler.cpp',
|
||||
'lib/Loc.cpp',
|
||||
'lib/SymTable.cpp',
|
||||
],
|
||||
dependencies: [
|
||||
dependency('LLVM')
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include <Lexer.hpp>
|
||||
#include <Parser.hpp>
|
||||
#include <Compiler.hpp>
|
||||
|
@ -35,7 +34,6 @@ int main(int argc, char** argv)
|
|||
|
||||
wg::Compiler compiler;
|
||||
compiler.compile(ast);
|
||||
compiler.gen();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -34,37 +34,3 @@ TEST_CASE_METHOD(LexerTest, "Lexer_")
|
|||
test_next(lex, "IDENT[canard]");
|
||||
test_end(lex);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(LexerTest, "Lexer_int_literal")
|
||||
{
|
||||
wg::Lexer lex;
|
||||
lex.scan(" 3 -2 78 ");
|
||||
test_next(lex, "INT[3]");
|
||||
test_next(lex, "INT[-2]");
|
||||
test_next(lex, "INT[78]");
|
||||
test_end(lex);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(LexerTest, "Lexer_int_arith")
|
||||
{
|
||||
wg::Lexer lex;
|
||||
lex.scan(" +-*/% ()");
|
||||
test_next(lex, "ADD");
|
||||
test_next(lex, "SUB");
|
||||
test_next(lex, "MUL");
|
||||
test_next(lex, "DIV");
|
||||
test_next(lex, "MOD");
|
||||
test_next(lex, "OPAR");
|
||||
test_next(lex, "CPAR");
|
||||
test_end(lex);
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(LexerTest, "Lexer_fun_call")
|
||||
{
|
||||
wg::Lexer lex;
|
||||
lex.scan(" , int extern ");
|
||||
test_next(lex, "COMMA");
|
||||
test_next(lex, "TYPE[int]");
|
||||
test_next(lex, "EXTERN");
|
||||
test_end(lex);
|
||||
}
|
||||
|
|
|
@ -25,68 +25,8 @@ public:
|
|||
protected:
|
||||
};
|
||||
|
||||
TEST_CASE_METHOD(ParserTest, "Parser_dir")
|
||||
TEST_CASE_METHOD(ParserTest, "Parser_")
|
||||
{
|
||||
test_parse("PROG(DIR(IDENT[hello],IDENT[world]))",
|
||||
"#hello world");
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE_METHOD(ParserTest, "Parser_int")
|
||||
{
|
||||
test_parse("PROG(INT[45])",
|
||||
" 45; ");
|
||||
|
||||
test_parse("PROG(ADD(INT[1],MUL(INT[2],INT[3])))",
|
||||
" 1 + 2 * 3; ");
|
||||
|
||||
test_parse("PROG(MUL(ADD(INT[1],INT[2]),INT[3]))",
|
||||
" (1 + 2) * 3; ");
|
||||
|
||||
test_parse("PROG(SUB(INT[1],DIV(INT[2],INT[3])))",
|
||||
" 1 - 2 / 3; ");
|
||||
|
||||
test_parse("PROG(DIV(SUB(INT[1],INT[2]),INT[3]))",
|
||||
" (1 - 2) / 3; ");
|
||||
|
||||
test_parse("PROG(ADD(INT[1],MOD(INT[2],INT[3])))",
|
||||
" 1 + 2 % 3; ");
|
||||
|
||||
test_parse("PROG(MOD(ADD(INT[1],INT[2]),INT[3]))",
|
||||
" (1 + 2) % 3; ");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ParserTest, "Parser_call")
|
||||
{
|
||||
test_parse("PROG(CALL(IDENT[hello],ARGS))",
|
||||
" hello(); ");
|
||||
|
||||
test_parse("PROG(CALL(IDENT[hello_world],ARGS(IDENT[x])))",
|
||||
" hello_world(x); ");
|
||||
|
||||
test_parse("PROG(CALL(IDENT[hello_world],ARGS(IDENT[x],INT[78])))",
|
||||
" hello_world(x, 78); ");
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(ParserTest, "Parser_fundecl")
|
||||
{
|
||||
test_parse("PROG(EXTERN(IDENT[hello],"
|
||||
"PARAMS(IDENT[x],IDENT[y],TYPE[int]),RET(TYPE[int])))",
|
||||
" extern fun hello(x, y int) int; ");
|
||||
|
||||
test_parse("PROG(FUNDECL(IDENT[couc],PARAMS,RET,BLOCK))",
|
||||
" fun couc() {} ");
|
||||
|
||||
test_parse("PROG(FUNDECL(IDENT[couc],PARAMS("
|
||||
"IDENT[x],IDENT[y],TYPE[int]"
|
||||
"),RET,BLOCK(RETURN(INT[4]))))",
|
||||
" fun couc(x, y int) { return 4; } ");
|
||||
|
||||
test_parse("PROG(FUNDECL(IDENT[couc],PARAMS("
|
||||
"IDENT[x],IDENT[y],TYPE[int]"
|
||||
"),RET(TYPE[int]),BLOCK(RETURN(INT[4]))))",
|
||||
" fun couc(x, y int) int { return 4; } ");
|
||||
|
||||
test_parse("PROG(RETURN(ADD(CALL(IDENT[a],ARGS),INT[1])))",
|
||||
" return a() + 1; ");
|
||||
}
|
||||
|
|
Reference in New Issue