feat: introduced blocks and better project structure
This commit is contained in:
@@ -3,7 +3,6 @@ project(pl VERSION 0.0.1 LANGUAGES C CXX)
|
|||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 23)
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
src/ir.cpp
|
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ private:
|
|||||||
auto param_slot = m_allocator->Allocate(fn->params().data[0]);
|
auto param_slot = m_allocator->Allocate(fn->params().data[0]);
|
||||||
appendf("mov %s, rdi\n", GetSlotAddr(param_slot).c_str());
|
appendf("mov %s, rdi\n", GetSlotAddr(param_slot).c_str());
|
||||||
}
|
}
|
||||||
for(auto &fOp : fn->ops())
|
for(auto &fOp : fn->body().ops())
|
||||||
{
|
{
|
||||||
GenerateOp(fOp);
|
GenerateOp(fOp);
|
||||||
}
|
}
|
||||||
|
|||||||
35
include/ir/block.hpp
Normal file
35
include/ir/block.hpp
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "ir/op.hpp"
|
||||||
|
|
||||||
|
namespace IR
|
||||||
|
{
|
||||||
|
|
||||||
|
using OpView = View<Op*>;
|
||||||
|
|
||||||
|
using BlockID = unsigned int;
|
||||||
|
|
||||||
|
class Block
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Block(BlockID id, OpView&& ops)
|
||||||
|
: m_id(id), m_ops(ops) {}
|
||||||
|
public:
|
||||||
|
const OpView& ops() const { return m_ops; }
|
||||||
|
public:
|
||||||
|
StringView Format(int indent) const
|
||||||
|
{
|
||||||
|
StringBuilder sb;
|
||||||
|
sb.AppendIndent(indent);
|
||||||
|
sb.AppendFormat("b%d:\n", m_id);
|
||||||
|
for (size_t i = 0; i < m_ops.size; ++i)
|
||||||
|
{
|
||||||
|
sb << m_ops.data[i]->Format(indent + 2) << '\n';
|
||||||
|
}
|
||||||
|
return sb.view();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
BlockID m_id;
|
||||||
|
OpView m_ops;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace IR
|
||||||
@@ -5,240 +5,29 @@
|
|||||||
#include "ir/slot.hpp"
|
#include "ir/slot.hpp"
|
||||||
#include "ir/allocator.hpp"
|
#include "ir/allocator.hpp"
|
||||||
#include "ir/value.hpp"
|
#include "ir/value.hpp"
|
||||||
|
#include "ir/ops.hpp"
|
||||||
|
|
||||||
namespace IR
|
namespace IR
|
||||||
{
|
{
|
||||||
|
|
||||||
enum class OpType
|
|
||||||
{
|
|
||||||
EXTERN = 0,
|
|
||||||
FN,
|
|
||||||
LOAD_CONST,
|
|
||||||
LOAD,
|
|
||||||
STORE,
|
|
||||||
ADD,
|
|
||||||
CALL,
|
|
||||||
COUNT_OPS,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define OP_TYPE(x) \
|
|
||||||
OpType GetType() const override { return OpType::x; }
|
|
||||||
|
|
||||||
class Op
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual OpType GetType() const = 0;
|
|
||||||
virtual ~Op() {}
|
|
||||||
|
|
||||||
virtual StringView Format(int indent) const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
using OpView = View<Op*>;
|
|
||||||
using OpBuilder = Builder<Op*>;
|
|
||||||
|
|
||||||
class Valued
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Valued(Value dest)
|
|
||||||
: m_dest(dest) {}
|
|
||||||
~Valued() = default;
|
|
||||||
public:
|
|
||||||
Value result() const { return m_dest; }
|
|
||||||
private:
|
|
||||||
Value m_dest;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExternOp : public Op
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ExternOp(StringView symbol)
|
|
||||||
: m_symbol(symbol) {}
|
|
||||||
~ExternOp() {}
|
|
||||||
|
|
||||||
OP_TYPE(EXTERN)
|
|
||||||
public:
|
|
||||||
StringView Format(int indent) const override
|
|
||||||
{
|
|
||||||
StringBuilder sb;
|
|
||||||
sb.AppendIndent(indent);
|
|
||||||
sb << "EXTRN " << m_symbol.c_str();
|
|
||||||
return sb.view();
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
const StringView& symbol() const { return m_symbol; }
|
|
||||||
private:
|
|
||||||
StringView m_symbol;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FnOp : public Op
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
FnOp(StringView name, const CompoundNode* body, const View<StringView>& params);
|
|
||||||
~FnOp() {}
|
|
||||||
|
|
||||||
OP_TYPE(FN)
|
|
||||||
public:
|
|
||||||
StringView Format(int indent) const override
|
|
||||||
{
|
|
||||||
StringBuilder sb;
|
|
||||||
sb.AppendIndent(indent);
|
|
||||||
sb << "LABEL " << m_name.c_str() << ':' << '\n';
|
|
||||||
for (size_t i = 0; i < m_ops.size; ++i)
|
|
||||||
{
|
|
||||||
sb << m_ops.data[i]->Format(indent + 2) << '\n';
|
|
||||||
}
|
|
||||||
return sb.view();
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
const StringView& name() const { return m_name; }
|
|
||||||
const OpView& ops() const { return m_ops; }
|
|
||||||
const View<StringView>& params() const { return m_params; }
|
|
||||||
private:
|
|
||||||
StringView m_name;
|
|
||||||
OpView m_ops;
|
|
||||||
ValueView m_slots;
|
|
||||||
View<StringView> m_params;
|
|
||||||
};
|
|
||||||
|
|
||||||
class LoadConstOp : public Op, public Valued
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
LoadConstOp(Value dest, long value)
|
|
||||||
: Valued(dest), m_value(value) {}
|
|
||||||
~LoadConstOp() {}
|
|
||||||
|
|
||||||
OP_TYPE(LOAD_CONST)
|
|
||||||
public:
|
|
||||||
StringView Format(int indent) const override
|
|
||||||
{
|
|
||||||
StringBuilder sb;
|
|
||||||
sb.AppendIndent(indent);
|
|
||||||
sb << result().Format() << " = LOAD_CONST " << m_value;
|
|
||||||
return sb.view();
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
long value() const { return m_value; }
|
|
||||||
private:
|
|
||||||
long m_value;
|
|
||||||
};
|
|
||||||
|
|
||||||
class LoadOp : public Op, public Valued
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
LoadOp(Value dest, StringView addr)
|
|
||||||
: Valued(dest), m_addr(addr) {}
|
|
||||||
~LoadOp() {}
|
|
||||||
|
|
||||||
OP_TYPE(LOAD)
|
|
||||||
public:
|
|
||||||
StringView Format(int indent) const override
|
|
||||||
{
|
|
||||||
StringBuilder sb;
|
|
||||||
sb.AppendIndent(indent);
|
|
||||||
sb << result().Format() << " = LOAD \"" << m_addr.c_str() << "\"";
|
|
||||||
return sb.view();
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
const StringView& addr() const { return m_addr; }
|
|
||||||
private:
|
|
||||||
StringView m_addr;
|
|
||||||
};
|
|
||||||
|
|
||||||
class StoreOp : public Op
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
StoreOp(StringView addr, Value src)
|
|
||||||
: m_addr(addr), m_src(src) {}
|
|
||||||
~StoreOp() {}
|
|
||||||
|
|
||||||
OP_TYPE(STORE)
|
|
||||||
public:
|
|
||||||
StringView Format(int indent) const override
|
|
||||||
{
|
|
||||||
StringBuilder sb;
|
|
||||||
sb.AppendIndent(indent);
|
|
||||||
sb << "STORE \"" << m_addr.c_str() << "\", " << m_src.Format();
|
|
||||||
return sb.view();
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
const StringView& addr() const { return m_addr; }
|
|
||||||
Value src() const { return m_src; }
|
|
||||||
private:
|
|
||||||
StringView m_addr;
|
|
||||||
Value m_src;
|
|
||||||
};
|
|
||||||
|
|
||||||
class AddOp : public Op, public Valued
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AddOp(Value dest, Value lhs, Value rhs)
|
|
||||||
: Valued(dest), m_lhs(lhs), m_rhs(rhs) {}
|
|
||||||
~AddOp() {}
|
|
||||||
|
|
||||||
OP_TYPE(ADD)
|
|
||||||
public:
|
|
||||||
StringView Format(int indent) const override
|
|
||||||
{
|
|
||||||
StringBuilder sb;
|
|
||||||
sb.AppendIndent(indent);
|
|
||||||
sb << result().Format() << " = ADD " << m_lhs.Format() << ", " << m_rhs.Format();
|
|
||||||
return sb.view();
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
Value lhs() const { return m_lhs; }
|
|
||||||
Value rhs() const { return m_rhs; }
|
|
||||||
private:
|
|
||||||
Value m_lhs;
|
|
||||||
Value m_rhs;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CallOp : public Op, public Valued
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CallOp(Value dest, StringView callee, ValueView args)
|
|
||||||
: Valued(dest), m_callee(callee), m_args(args) {}
|
|
||||||
~CallOp() {}
|
|
||||||
|
|
||||||
OP_TYPE(CALL)
|
|
||||||
public:
|
|
||||||
StringView Format(int indent) const override
|
|
||||||
{
|
|
||||||
StringBuilder sb;
|
|
||||||
for (size_t i = 0; i < m_args.size; ++i)
|
|
||||||
{
|
|
||||||
sb.AppendIndent(indent);
|
|
||||||
sb << "PARAM " << m_args.data[i].Format() << '\n';
|
|
||||||
}
|
|
||||||
sb.AppendIndent(indent);
|
|
||||||
sb << result().Format() << " = CALL " << m_callee.c_str();
|
|
||||||
return sb.view();
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
const StringView& callee() const { return m_callee; }
|
|
||||||
const ValueView& args() const { return m_args; }
|
|
||||||
private:
|
|
||||||
StringView m_callee;
|
|
||||||
ValueView m_args;
|
|
||||||
};
|
|
||||||
|
|
||||||
class IRBuilder
|
class IRBuilder
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
IRBuilder(const Node* root)
|
IRBuilder(const Node* root)
|
||||||
: m_root(root) {}
|
: m_root(root), m_ops(new OpBuilder()) {}
|
||||||
public:
|
public:
|
||||||
// TODO: support other literals
|
// TODO: support other literals
|
||||||
Value ParseIntLiteral(const IntLiteralNode* literal)
|
Value ParseIntLiteral(const IntLiteralNode* literal)
|
||||||
{
|
{
|
||||||
auto dst = AllocateRegister();
|
auto dst = AllocateRegister();
|
||||||
m_ops.Push(new LoadConstOp(dst, literal->integer()));
|
m_ops->Push(new LoadConstOp(dst, literal->integer()));
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
Value ParseVariable(const VariableNode* var)
|
Value ParseVariable(const VariableNode* var)
|
||||||
{
|
{
|
||||||
// auto dst = AllocateRegister();
|
// auto dst = AllocateRegister();
|
||||||
// m_ops.Push(new LoadOp(dst, var->name()));
|
// m_ops->Push(new LoadOp(dst, var->name()));
|
||||||
if (m_locals.find(var->name()) == m_locals.end())
|
if (m_locals.find(var->name()) == m_locals.end())
|
||||||
{
|
{
|
||||||
// TODO: throw proper error
|
// TODO: throw proper error
|
||||||
@@ -257,7 +46,7 @@ public:
|
|||||||
argRegs.Push(arg);
|
argRegs.Push(arg);
|
||||||
}
|
}
|
||||||
auto dst = AllocateRegister();
|
auto dst = AllocateRegister();
|
||||||
m_ops.Push(new CallOp(dst, fn->name(), argRegs.view()));
|
m_ops->Push(new CallOp(dst, fn->name(), argRegs.view()));
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,7 +76,7 @@ public:
|
|||||||
assert(4 == static_cast<int>(ExpressionNode::Operator::COUNT_OPERATORS) && "some operators may not be handled");
|
assert(4 == static_cast<int>(ExpressionNode::Operator::COUNT_OPERATORS) && "some operators may not be handled");
|
||||||
switch (expr->op())
|
switch (expr->op())
|
||||||
{
|
{
|
||||||
case ExpressionNode::Operator::Plus: m_ops.Push(new AddOp(dst, lhs, rhs)); break;
|
case ExpressionNode::Operator::Plus: m_ops->Push(new AddOp(dst, lhs, rhs)); break;
|
||||||
default: assert(0 && "TODO: implement other operations"); break;
|
default: assert(0 && "TODO: implement other operations"); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,12 +89,13 @@ public:
|
|||||||
void ParseVarDecl(const VarDeclNode* varDecl)
|
void ParseVarDecl(const VarDeclNode* varDecl)
|
||||||
{
|
{
|
||||||
auto value = ParseExpression(varDecl->value());
|
auto value = ParseExpression(varDecl->value());
|
||||||
// m_ops.Push(new StoreOp(varDecl->name(), value));
|
// m_ops->Push(new StoreOp(varDecl->name(), value));
|
||||||
m_locals.insert(std::make_pair(varDecl->name(), value));
|
m_locals.insert(std::make_pair(varDecl->name(), value));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ParseBlock(const CompoundNode* compound)
|
Block ParseBlock(const CompoundNode* compound)
|
||||||
{
|
{
|
||||||
|
StartBlock();
|
||||||
for (auto &statement : *compound)
|
for (auto &statement : *compound)
|
||||||
{
|
{
|
||||||
switch(statement->GetType())
|
switch(statement->GetType())
|
||||||
@@ -314,6 +104,10 @@ public:
|
|||||||
default: ParseExpression(statement); continue;
|
default: ParseExpression(statement); continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
auto ops = EndBlock();
|
||||||
|
auto block = Block(m_block_counter++, std::move(ops->view()));
|
||||||
|
operator delete(ops);
|
||||||
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
OpView Build()
|
OpView Build()
|
||||||
@@ -324,32 +118,50 @@ public:
|
|||||||
// Externs
|
// Externs
|
||||||
for (auto &extrn : program->externs())
|
for (auto &extrn : program->externs())
|
||||||
{
|
{
|
||||||
m_ops.Push(new ExternOp(extrn->symbol()));
|
m_ops->Push(new ExternOp(extrn->symbol()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
for (auto &fn : program->funcs())
|
for (auto &fn : program->funcs())
|
||||||
{
|
{
|
||||||
m_ops.Push(new FnOp(fn->name(), fn->body(), fn->params()));
|
auto block = ParseBlock(fn->body());
|
||||||
|
m_ops->Push(new FnOp(fn->name(), fn->params(), std::move(block)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return OpView(m_ops.data, m_ops.size);
|
return OpView(m_ops->data, m_ops->size);
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
// TODO: think about safety (copying m_ops.data before giving)
|
// TODO: think about safety (copying m_ops->data before giving)
|
||||||
OpView ops() const { return OpView(m_ops.data, m_ops.size); }
|
OpView ops() const { return OpView(m_ops->data, m_ops->size); }
|
||||||
|
private:
|
||||||
|
void StartBlock()
|
||||||
|
{
|
||||||
|
m_containers.Push(m_ops);
|
||||||
|
m_ops = new OpBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
|
OpBuilder* EndBlock()
|
||||||
|
{
|
||||||
|
assert(m_containers.size > 0 && "containers stack is empty");
|
||||||
|
auto current = m_ops;
|
||||||
|
m_ops = m_containers.data[m_containers.size - 1];
|
||||||
|
m_containers.size--;
|
||||||
|
return current;
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
Value AllocateRegister()
|
Value AllocateRegister()
|
||||||
{
|
{
|
||||||
return Value(m_value_counter++);
|
return Value(m_value_counter++);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
OpBuilder m_ops;
|
|
||||||
const Node* m_root = nullptr;
|
const Node* m_root = nullptr;
|
||||||
|
|
||||||
|
OpBuilder* m_ops = nullptr;
|
||||||
unsigned int m_value_counter = 0;
|
unsigned int m_value_counter = 0;
|
||||||
|
unsigned int m_block_counter = 0;
|
||||||
std::unordered_map<StringView, Value> m_locals;
|
std::unordered_map<StringView, Value> m_locals;
|
||||||
|
|
||||||
|
Builder<OpBuilder*> m_containers;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace IR
|
} // namespace IR
|
||||||
|
|||||||
50
include/ir/op.hpp
Normal file
50
include/ir/op.hpp
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "prelude/string.hpp"
|
||||||
|
#include "ir/value.hpp"
|
||||||
|
|
||||||
|
namespace IR
|
||||||
|
{
|
||||||
|
|
||||||
|
enum class OpType
|
||||||
|
{
|
||||||
|
EXTERN = 0,
|
||||||
|
FN,
|
||||||
|
LOAD_CONST,
|
||||||
|
LOAD,
|
||||||
|
STORE,
|
||||||
|
ADD,
|
||||||
|
CALL,
|
||||||
|
COUNT_OPS,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define OP_TYPE(x) \
|
||||||
|
OpType GetType() const override { return OpType::x; }
|
||||||
|
|
||||||
|
class Op
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual OpType GetType() const = 0;
|
||||||
|
virtual bool Valued() const { return false; };
|
||||||
|
virtual ~Op() {}
|
||||||
|
|
||||||
|
virtual StringView Format(int indent) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
using OpView = View<Op*>;
|
||||||
|
using OpBuilder = Builder<Op*>;
|
||||||
|
|
||||||
|
class OpValued : public Op
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OpValued(Value dest)
|
||||||
|
: m_dest(dest) {}
|
||||||
|
~OpValued() = default;
|
||||||
|
public:
|
||||||
|
Value result() const { return m_dest; }
|
||||||
|
protected:
|
||||||
|
bool Valued() const override { return true; }
|
||||||
|
private:
|
||||||
|
Value m_dest;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace IR
|
||||||
183
include/ir/ops.hpp
Normal file
183
include/ir/ops.hpp
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "prelude/string.hpp"
|
||||||
|
#include "parser/nodes.hpp"
|
||||||
|
#include "ir/value.hpp"
|
||||||
|
#include "ir/op.hpp"
|
||||||
|
#include "ir/block.hpp"
|
||||||
|
|
||||||
|
namespace IR
|
||||||
|
{
|
||||||
|
|
||||||
|
class ExternOp : public Op
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ExternOp(StringView symbol)
|
||||||
|
: m_symbol(symbol) {}
|
||||||
|
~ExternOp() {}
|
||||||
|
|
||||||
|
OP_TYPE(EXTERN)
|
||||||
|
public:
|
||||||
|
StringView Format(int indent) const override
|
||||||
|
{
|
||||||
|
StringBuilder sb;
|
||||||
|
sb.AppendIndent(indent);
|
||||||
|
sb << "EXTRN " << m_symbol.c_str();
|
||||||
|
return sb.view();
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
const StringView& symbol() const { return m_symbol; }
|
||||||
|
private:
|
||||||
|
StringView m_symbol;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Make function return value (i.e. inhreit the OpValued class instead)
|
||||||
|
class FnOp : public Op
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FnOp(StringView name, const View<StringView>& params, Block&& block)
|
||||||
|
: m_name(name), m_params(params), m_body(block) {}
|
||||||
|
~FnOp() {}
|
||||||
|
|
||||||
|
OP_TYPE(FN)
|
||||||
|
public:
|
||||||
|
StringView Format(int indent) const override
|
||||||
|
{
|
||||||
|
StringBuilder sb;
|
||||||
|
sb.AppendIndent(indent);
|
||||||
|
sb << "LABEL " << m_name.c_str() << ':' << '\n';
|
||||||
|
sb << m_body.Format(indent);
|
||||||
|
return sb.view();
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
const StringView& name() const { return m_name; }
|
||||||
|
const Block& body() const { return m_body; }
|
||||||
|
const View<StringView>& params() const { return m_params; }
|
||||||
|
private:
|
||||||
|
StringView m_name;
|
||||||
|
ValueView m_slots;
|
||||||
|
View<StringView> m_params;
|
||||||
|
Block m_body;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LoadConstOp : public OpValued
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LoadConstOp(Value dest, long value)
|
||||||
|
: OpValued(dest), m_value(value) {}
|
||||||
|
~LoadConstOp() {}
|
||||||
|
|
||||||
|
OP_TYPE(LOAD_CONST)
|
||||||
|
public:
|
||||||
|
StringView Format(int indent) const override
|
||||||
|
{
|
||||||
|
StringBuilder sb;
|
||||||
|
sb.AppendIndent(indent);
|
||||||
|
sb << result().Format() << " = LOAD_CONST " << m_value;
|
||||||
|
return sb.view();
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
long value() const { return m_value; }
|
||||||
|
private:
|
||||||
|
long m_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LoadOp : public OpValued
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
LoadOp(Value dest, StringView addr)
|
||||||
|
: OpValued(dest), m_addr(addr) {}
|
||||||
|
~LoadOp() {}
|
||||||
|
|
||||||
|
OP_TYPE(LOAD)
|
||||||
|
public:
|
||||||
|
StringView Format(int indent) const override
|
||||||
|
{
|
||||||
|
StringBuilder sb;
|
||||||
|
sb.AppendIndent(indent);
|
||||||
|
sb << result().Format() << " = LOAD \"" << m_addr.c_str() << "\"";
|
||||||
|
return sb.view();
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
const StringView& addr() const { return m_addr; }
|
||||||
|
private:
|
||||||
|
StringView m_addr;
|
||||||
|
};
|
||||||
|
|
||||||
|
class StoreOp : public Op
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
StoreOp(StringView addr, Value src)
|
||||||
|
: m_addr(addr), m_src(src) {}
|
||||||
|
~StoreOp() {}
|
||||||
|
|
||||||
|
OP_TYPE(STORE)
|
||||||
|
public:
|
||||||
|
StringView Format(int indent) const override
|
||||||
|
{
|
||||||
|
StringBuilder sb;
|
||||||
|
sb.AppendIndent(indent);
|
||||||
|
sb << "STORE \"" << m_addr.c_str() << "\", " << m_src.Format();
|
||||||
|
return sb.view();
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
const StringView& addr() const { return m_addr; }
|
||||||
|
Value src() const { return m_src; }
|
||||||
|
private:
|
||||||
|
StringView m_addr;
|
||||||
|
Value m_src;
|
||||||
|
};
|
||||||
|
|
||||||
|
class AddOp : public OpValued
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AddOp(Value dest, Value lhs, Value rhs)
|
||||||
|
: OpValued(dest), m_lhs(lhs), m_rhs(rhs) {}
|
||||||
|
~AddOp() {}
|
||||||
|
|
||||||
|
OP_TYPE(ADD)
|
||||||
|
public:
|
||||||
|
StringView Format(int indent) const override
|
||||||
|
{
|
||||||
|
StringBuilder sb;
|
||||||
|
sb.AppendIndent(indent);
|
||||||
|
sb << result().Format() << " = ADD " << m_lhs.Format() << ", " << m_rhs.Format();
|
||||||
|
return sb.view();
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
Value lhs() const { return m_lhs; }
|
||||||
|
Value rhs() const { return m_rhs; }
|
||||||
|
private:
|
||||||
|
Value m_lhs;
|
||||||
|
Value m_rhs;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CallOp : public OpValued
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CallOp(Value dest, StringView callee, ValueView args)
|
||||||
|
: OpValued(dest), m_callee(callee), m_args(args) {}
|
||||||
|
~CallOp() {}
|
||||||
|
|
||||||
|
OP_TYPE(CALL)
|
||||||
|
public:
|
||||||
|
StringView Format(int indent) const override
|
||||||
|
{
|
||||||
|
StringBuilder sb;
|
||||||
|
for (size_t i = 0; i < m_args.size; ++i)
|
||||||
|
{
|
||||||
|
sb.AppendIndent(indent);
|
||||||
|
sb << "PARAM " << m_args.data[i].Format() << '\n';
|
||||||
|
}
|
||||||
|
sb.AppendIndent(indent);
|
||||||
|
sb << result().Format() << " = CALL " << m_callee.c_str();
|
||||||
|
return sb.view();
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
const StringView& callee() const { return m_callee; }
|
||||||
|
const ValueView& args() const { return m_args; }
|
||||||
|
private:
|
||||||
|
StringView m_callee;
|
||||||
|
ValueView m_args;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace IR
|
||||||
@@ -3,222 +3,7 @@
|
|||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "parser/lexer.hpp"
|
#include "parser/lexer.hpp"
|
||||||
|
#include "parser/nodes.hpp"
|
||||||
enum class NodeType
|
|
||||||
{
|
|
||||||
Expression = 0,
|
|
||||||
// TODO: abstract "Literal" node type
|
|
||||||
IntLiteral,
|
|
||||||
Extern,
|
|
||||||
FnDecl,
|
|
||||||
FnCall,
|
|
||||||
Variable,
|
|
||||||
VarDecl,
|
|
||||||
Compound,
|
|
||||||
Program,
|
|
||||||
COUNT_NODES,
|
|
||||||
};
|
|
||||||
|
|
||||||
#define NODE_TYPE(x) \
|
|
||||||
NodeType GetType() const override { return NodeType::x; }
|
|
||||||
|
|
||||||
class Node
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual NodeType GetType() const = 0;
|
|
||||||
virtual ~Node() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExpressionNode : public Node
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum class Operator
|
|
||||||
{
|
|
||||||
Plus = 0,
|
|
||||||
Minus,
|
|
||||||
Divide,
|
|
||||||
Multiply,
|
|
||||||
COUNT_OPERATORS,
|
|
||||||
};
|
|
||||||
public:
|
|
||||||
ExpressionNode(Node* left, Node* right, Operator op)
|
|
||||||
: m_left(left), m_right(right), m_op(op) {}
|
|
||||||
~ExpressionNode() override {
|
|
||||||
delete m_left;
|
|
||||||
delete m_right;
|
|
||||||
}
|
|
||||||
|
|
||||||
NODE_TYPE(Expression)
|
|
||||||
public:
|
|
||||||
Node* left() const { return m_left; }
|
|
||||||
Node* right() const { return m_right; }
|
|
||||||
Operator op() const { return m_op; }
|
|
||||||
private:
|
|
||||||
Node* m_left;
|
|
||||||
Node* m_right;
|
|
||||||
Operator m_op;
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: Maybe just LiteralNode with double or int literals support
|
|
||||||
class IntLiteralNode : public Node
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
IntLiteralNode(long value)
|
|
||||||
: m_int_value(value) {}
|
|
||||||
~IntLiteralNode() override {}
|
|
||||||
|
|
||||||
NODE_TYPE(IntLiteral)
|
|
||||||
public:
|
|
||||||
long integer() const { return m_int_value; }
|
|
||||||
private:
|
|
||||||
long m_int_value;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ExternNode : public Node
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// TODO: support multiple extern symbols
|
|
||||||
ExternNode(StringView symbol)
|
|
||||||
: m_symbol(symbol) {}
|
|
||||||
~ExternNode() override = default;
|
|
||||||
|
|
||||||
NODE_TYPE(Extern)
|
|
||||||
public:
|
|
||||||
const StringView& symbol() const { return m_symbol; }
|
|
||||||
private:
|
|
||||||
StringView m_symbol;
|
|
||||||
};
|
|
||||||
|
|
||||||
class CompoundNode : public Node
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
CompoundNode() = default;
|
|
||||||
|
|
||||||
NODE_TYPE(Compound)
|
|
||||||
|
|
||||||
// --- Iteration ---
|
|
||||||
auto begin() { return m_nodes.begin(); }
|
|
||||||
auto end() { return m_nodes.end(); }
|
|
||||||
auto begin() const { return m_nodes.begin(); }
|
|
||||||
auto end() const { return m_nodes.end(); }
|
|
||||||
|
|
||||||
// --- Access by index ---
|
|
||||||
Node* operator[](size_t i) { return m_nodes[i]; }
|
|
||||||
const Node* operator[](size_t i) const { return m_nodes[i]; }
|
|
||||||
|
|
||||||
Node* at(size_t i) { return m_nodes.at(i); }
|
|
||||||
const Node* at(size_t i) const { return m_nodes.at(i); }
|
|
||||||
|
|
||||||
// --- Modifiers ---
|
|
||||||
void addNode(Node* n) { m_nodes.push_back(n); }
|
|
||||||
void removeNode(size_t idx) { m_nodes.erase(m_nodes.begin() + idx); }
|
|
||||||
|
|
||||||
// If you want full expose for iteration but not modification
|
|
||||||
const std::vector<Node*>& nodes() const { return m_nodes; }
|
|
||||||
|
|
||||||
size_t size() const { return m_nodes.size(); }
|
|
||||||
bool empty() const { return m_nodes.empty(); }
|
|
||||||
private:
|
|
||||||
std::vector<Node*> m_nodes;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FnDeclNode : public Node
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// TODO: support parameters
|
|
||||||
FnDeclNode(const StringView& name, CompoundNode* body, View<StringView> params)
|
|
||||||
: m_name(name), m_body(body), m_params(params) {}
|
|
||||||
~FnDeclNode() override {
|
|
||||||
delete m_body;
|
|
||||||
}
|
|
||||||
|
|
||||||
NODE_TYPE(FnDecl)
|
|
||||||
public:
|
|
||||||
const StringView& name() const { return m_name; }
|
|
||||||
const CompoundNode* body() const { return m_body; }
|
|
||||||
const View<StringView>& params() const { return m_params; }
|
|
||||||
private:
|
|
||||||
StringView m_name;
|
|
||||||
CompoundNode* m_body;
|
|
||||||
View<StringView> m_params;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FnCallNode : public Node
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
// TODO: support multiple arguments
|
|
||||||
FnCallNode(const StringView& name, Node* arg)
|
|
||||||
: m_name(name), m_arg(arg) {}
|
|
||||||
~FnCallNode() override {
|
|
||||||
delete m_arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
NODE_TYPE(FnCall)
|
|
||||||
public:
|
|
||||||
const StringView& name() const { return m_name; }
|
|
||||||
// TODO: support multiple args
|
|
||||||
const Node* arg() const { return m_arg; }
|
|
||||||
private:
|
|
||||||
StringView m_name;
|
|
||||||
Node* m_arg;
|
|
||||||
};
|
|
||||||
|
|
||||||
class VariableNode : public Node
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VariableNode(const StringView& name)
|
|
||||||
: m_name(name) {}
|
|
||||||
~VariableNode() override = default;
|
|
||||||
|
|
||||||
NODE_TYPE(Variable)
|
|
||||||
public:
|
|
||||||
const StringView& name() const { return m_name; }
|
|
||||||
private:
|
|
||||||
StringView m_name;
|
|
||||||
};
|
|
||||||
|
|
||||||
class VarDeclNode : public Node
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VarDeclNode(const StringView& name, Node* value)
|
|
||||||
: m_name(name), m_value(value) {}
|
|
||||||
~VarDeclNode() override {
|
|
||||||
delete m_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
NODE_TYPE(VarDecl)
|
|
||||||
public:
|
|
||||||
const StringView& name() const { return m_name; }
|
|
||||||
const Node* value() const { return m_value; }
|
|
||||||
private:
|
|
||||||
StringView m_name;
|
|
||||||
Node* m_value;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ProgramNode : public Node
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ProgramNode() = default;
|
|
||||||
|
|
||||||
NODE_TYPE(Program)
|
|
||||||
public:
|
|
||||||
void PushFunction(FnDeclNode* fn)
|
|
||||||
{
|
|
||||||
m_funcs.push_back(fn);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PushExtern(ExternNode* extrn)
|
|
||||||
{
|
|
||||||
m_externs.push_back(extrn);
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
const std::vector<ExternNode*> externs() const { return m_externs; }
|
|
||||||
const std::vector<FnDeclNode*> funcs() const { return m_funcs; }
|
|
||||||
private:
|
|
||||||
std::vector<FnDeclNode*> m_funcs;
|
|
||||||
std::vector<ExternNode*> m_externs;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class AstParser
|
class AstParser
|
||||||
{
|
{
|
||||||
|
|||||||
217
include/parser/nodes.hpp
Normal file
217
include/parser/nodes.hpp
Normal file
@@ -0,0 +1,217 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "prelude/string.hpp"
|
||||||
|
|
||||||
|
enum class NodeType
|
||||||
|
{
|
||||||
|
Expression = 0,
|
||||||
|
// TODO: abstract "Literal" node type
|
||||||
|
IntLiteral,
|
||||||
|
Extern,
|
||||||
|
FnDecl,
|
||||||
|
FnCall,
|
||||||
|
Variable,
|
||||||
|
VarDecl,
|
||||||
|
Compound,
|
||||||
|
Program,
|
||||||
|
COUNT_NODES,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NODE_TYPE(x) \
|
||||||
|
NodeType GetType() const override { return NodeType::x; }
|
||||||
|
|
||||||
|
class Node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual NodeType GetType() const = 0;
|
||||||
|
virtual ~Node() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpressionNode : public Node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class Operator
|
||||||
|
{
|
||||||
|
Plus = 0,
|
||||||
|
Minus,
|
||||||
|
Divide,
|
||||||
|
Multiply,
|
||||||
|
COUNT_OPERATORS,
|
||||||
|
};
|
||||||
|
public:
|
||||||
|
ExpressionNode(Node* left, Node* right, Operator op)
|
||||||
|
: m_left(left), m_right(right), m_op(op) {}
|
||||||
|
~ExpressionNode() override {
|
||||||
|
delete m_left;
|
||||||
|
delete m_right;
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_TYPE(Expression)
|
||||||
|
public:
|
||||||
|
Node* left() const { return m_left; }
|
||||||
|
Node* right() const { return m_right; }
|
||||||
|
Operator op() const { return m_op; }
|
||||||
|
private:
|
||||||
|
Node* m_left;
|
||||||
|
Node* m_right;
|
||||||
|
Operator m_op;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: Maybe just LiteralNode with double or int literals support
|
||||||
|
class IntLiteralNode : public Node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IntLiteralNode(long value)
|
||||||
|
: m_int_value(value) {}
|
||||||
|
~IntLiteralNode() override {}
|
||||||
|
|
||||||
|
NODE_TYPE(IntLiteral)
|
||||||
|
public:
|
||||||
|
long integer() const { return m_int_value; }
|
||||||
|
private:
|
||||||
|
long m_int_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExternNode : public Node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// TODO: support multiple extern symbols
|
||||||
|
ExternNode(StringView symbol)
|
||||||
|
: m_symbol(symbol) {}
|
||||||
|
~ExternNode() override = default;
|
||||||
|
|
||||||
|
NODE_TYPE(Extern)
|
||||||
|
public:
|
||||||
|
const StringView& symbol() const { return m_symbol; }
|
||||||
|
private:
|
||||||
|
StringView m_symbol;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CompoundNode : public Node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CompoundNode() = default;
|
||||||
|
|
||||||
|
NODE_TYPE(Compound)
|
||||||
|
|
||||||
|
// --- Iteration ---
|
||||||
|
auto begin() { return m_nodes.begin(); }
|
||||||
|
auto end() { return m_nodes.end(); }
|
||||||
|
auto begin() const { return m_nodes.begin(); }
|
||||||
|
auto end() const { return m_nodes.end(); }
|
||||||
|
|
||||||
|
// --- Access by index ---
|
||||||
|
Node* operator[](size_t i) { return m_nodes[i]; }
|
||||||
|
const Node* operator[](size_t i) const { return m_nodes[i]; }
|
||||||
|
|
||||||
|
Node* at(size_t i) { return m_nodes.at(i); }
|
||||||
|
const Node* at(size_t i) const { return m_nodes.at(i); }
|
||||||
|
|
||||||
|
// --- Modifiers ---
|
||||||
|
void addNode(Node* n) { m_nodes.push_back(n); }
|
||||||
|
void removeNode(size_t idx) { m_nodes.erase(m_nodes.begin() + idx); }
|
||||||
|
|
||||||
|
// If you want full expose for iteration but not modification
|
||||||
|
const std::vector<Node*>& nodes() const { return m_nodes; }
|
||||||
|
|
||||||
|
size_t size() const { return m_nodes.size(); }
|
||||||
|
bool empty() const { return m_nodes.empty(); }
|
||||||
|
private:
|
||||||
|
std::vector<Node*> m_nodes;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FnDeclNode : public Node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// TODO: support parameters
|
||||||
|
FnDeclNode(const StringView& name, CompoundNode* body, View<StringView> params)
|
||||||
|
: m_name(name), m_body(body), m_params(params) {}
|
||||||
|
~FnDeclNode() override {
|
||||||
|
delete m_body;
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_TYPE(FnDecl)
|
||||||
|
public:
|
||||||
|
const StringView& name() const { return m_name; }
|
||||||
|
const CompoundNode* body() const { return m_body; }
|
||||||
|
const View<StringView>& params() const { return m_params; }
|
||||||
|
private:
|
||||||
|
StringView m_name;
|
||||||
|
CompoundNode* m_body;
|
||||||
|
View<StringView> m_params;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FnCallNode : public Node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// TODO: support multiple arguments
|
||||||
|
FnCallNode(const StringView& name, Node* arg)
|
||||||
|
: m_name(name), m_arg(arg) {}
|
||||||
|
~FnCallNode() override {
|
||||||
|
delete m_arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_TYPE(FnCall)
|
||||||
|
public:
|
||||||
|
const StringView& name() const { return m_name; }
|
||||||
|
// TODO: support multiple args
|
||||||
|
const Node* arg() const { return m_arg; }
|
||||||
|
private:
|
||||||
|
StringView m_name;
|
||||||
|
Node* m_arg;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VariableNode : public Node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VariableNode(const StringView& name)
|
||||||
|
: m_name(name) {}
|
||||||
|
~VariableNode() override = default;
|
||||||
|
|
||||||
|
NODE_TYPE(Variable)
|
||||||
|
public:
|
||||||
|
const StringView& name() const { return m_name; }
|
||||||
|
private:
|
||||||
|
StringView m_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VarDeclNode : public Node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VarDeclNode(const StringView& name, Node* value)
|
||||||
|
: m_name(name), m_value(value) {}
|
||||||
|
~VarDeclNode() override {
|
||||||
|
delete m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
NODE_TYPE(VarDecl)
|
||||||
|
public:
|
||||||
|
const StringView& name() const { return m_name; }
|
||||||
|
const Node* value() const { return m_value; }
|
||||||
|
private:
|
||||||
|
StringView m_name;
|
||||||
|
Node* m_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ProgramNode : public Node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ProgramNode() = default;
|
||||||
|
|
||||||
|
NODE_TYPE(Program)
|
||||||
|
public:
|
||||||
|
void PushFunction(FnDeclNode* fn)
|
||||||
|
{
|
||||||
|
m_funcs.push_back(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushExtern(ExternNode* extrn)
|
||||||
|
{
|
||||||
|
m_externs.push_back(extrn);
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
const std::vector<ExternNode*> externs() const { return m_externs; }
|
||||||
|
const std::vector<FnDeclNode*> funcs() const { return m_funcs; }
|
||||||
|
private:
|
||||||
|
std::vector<FnDeclNode*> m_funcs;
|
||||||
|
std::vector<ExternNode*> m_externs;
|
||||||
|
};
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
#include "ir/ir.hpp"
|
|
||||||
|
|
||||||
IR::FnOp::FnOp(StringView name, const CompoundNode* body, const View<StringView>& params)
|
|
||||||
: m_name(name), m_params(params)
|
|
||||||
{
|
|
||||||
IRBuilder ir(body); // Now IRBuilder is complete → OK
|
|
||||||
ir.ParseBlock(body);
|
|
||||||
m_ops = std::move(ir.ops());
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user