feat: migrate from OpView to DoubleLinkedList<Op*> + multiple
funciton arguments
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
extern putchar
|
extern putchar
|
||||||
|
extern iadd
|
||||||
|
|
||||||
fn hello() {
|
fn hello() {
|
||||||
local h = 72
|
local h = 72
|
||||||
@@ -14,5 +15,6 @@ fn hello() {
|
|||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
hello()
|
hello()
|
||||||
putchar(3 * 3 + 1)
|
local newline = iadd(3*3, 1)
|
||||||
|
putchar(newline)
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "ir/op.hpp"
|
#include "ir/op.hpp"
|
||||||
|
#include "prelude/linkedlist.hpp"
|
||||||
#include "prelude/string.hpp"
|
#include "prelude/string.hpp"
|
||||||
|
|
||||||
class CodeGenerator
|
class CodeGenerator
|
||||||
@@ -9,7 +10,7 @@ public:
|
|||||||
virtual ~CodeGenerator() {}
|
virtual ~CodeGenerator() {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual bool Generate(const IR::OpView* ops) = 0;
|
virtual bool Generate(const DoubleLinkedList<IR::Op*>* ops) = 0;
|
||||||
StringView GetOutput() { return output().view(); }
|
StringView GetOutput() { return output().view(); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|||||||
@@ -13,30 +13,35 @@ public:
|
|||||||
FasmX86_64Generator() = default;
|
FasmX86_64Generator() = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool Generate(const IR::OpView* ops) override
|
bool Generate(const DoubleLinkedList<IR::Op*>* ops) override
|
||||||
{
|
{
|
||||||
|
m_ops = ops;
|
||||||
|
|
||||||
output().Extend("format ELF64\n");
|
output().Extend("format ELF64\n");
|
||||||
output().Extend("section '.text' executable\n");
|
output().Extend("section '.text' executable\n");
|
||||||
|
|
||||||
for (size_t i = 0; i < ops->size; ++i)
|
for (m_current = m_ops->Begin(); m_current != nullptr; node_next())
|
||||||
{
|
{
|
||||||
GenerateStatement(ops->data[i]);
|
GenerateStatement();
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void GenerateExtern(IR::ExternOp* extrn)
|
void GenerateExtern()
|
||||||
{
|
{
|
||||||
|
auto extrn = current<IR::ExternOp>();
|
||||||
// TODO: instead of __<symbol, use some random UID or hash string
|
// TODO: instead of __<symbol, use some random UID or hash string
|
||||||
// for safety and collision considerations
|
// for safety and collision considerations
|
||||||
output().AppendFormat("extrn '%s' as __%s\n", extrn->symbol().c_str(), extrn->symbol().c_str());
|
output().AppendFormat("extrn '%s' as __%s\n", extrn->symbol().c_str(), extrn->symbol().c_str());
|
||||||
output().AppendFormat("%s = PLT __%s\n", extrn->symbol().c_str(), extrn->symbol().c_str());
|
output().AppendFormat("%s = PLT __%s\n", extrn->symbol().c_str(), extrn->symbol().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateFunction(IR::FnOp* fn)
|
void GenerateFunction()
|
||||||
{
|
{
|
||||||
|
auto fn = current<IR::FnOp>();
|
||||||
|
|
||||||
m_slots.clear();
|
m_slots.clear();
|
||||||
m_stackCounter = 0;
|
m_stackCounter = 0;
|
||||||
|
|
||||||
@@ -45,17 +50,23 @@ private:
|
|||||||
output().Extend(" push rbp\n");
|
output().Extend(" push rbp\n");
|
||||||
output().Extend(" mov rbp, rsp\n");
|
output().Extend(" mov rbp, rsp\n");
|
||||||
|
|
||||||
for (auto cur = fn->body().ops().Begin(); cur != nullptr; cur = cur->next)
|
auto fnNode = node<IR::Op>();
|
||||||
|
auto ops = m_ops;
|
||||||
|
m_ops = &fn->body().ops();
|
||||||
|
for (m_current = m_ops->Begin(); m_current != nullptr; node_next())
|
||||||
{
|
{
|
||||||
GenerateStatement(cur->value);
|
GenerateStatement();
|
||||||
}
|
}
|
||||||
|
m_ops = ops;
|
||||||
|
m_current = fnNode;
|
||||||
|
|
||||||
output().Extend(" leave\n");
|
output().Extend(" leave\n");
|
||||||
output().Extend(" ret\n");
|
output().Extend(" ret\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateCall(IR::CallOp* call)
|
void GenerateCall()
|
||||||
{
|
{
|
||||||
|
auto call = current<IR::CallOp>();
|
||||||
// TODO: support stack spilled arguments
|
// TODO: support stack spilled arguments
|
||||||
assert(call->args().size < 7 && "stack arguments not supported yet");
|
assert(call->args().size < 7 && "stack arguments not supported yet");
|
||||||
const char *regs[6] = {"edi", "esi", "edx", "ecx","e8", "e9"};
|
const char *regs[6] = {"edi", "esi", "edx", "ecx","e8", "e9"};
|
||||||
@@ -77,16 +88,29 @@ private:
|
|||||||
output().AppendFormat(" mov %s [rbp-%d], eax\n", size, sp);
|
output().AppendFormat(" mov %s [rbp-%d], eax\n", size, sp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateAllocate(IR::AllocateOp* alloc)
|
void GenerateAllocate()
|
||||||
{
|
{
|
||||||
// TODO: support other types
|
auto totalAllocSize = 0;
|
||||||
assert(alloc->Type()->kind == IR::ValueHandle::Type::Kind::Int);
|
while (current<IR::Op>()->GetType() == IR::OpType::ALLOCATE)
|
||||||
|
{
|
||||||
|
auto alloc = current<IR::AllocateOp>();
|
||||||
|
// TODO: support other types
|
||||||
|
assert(alloc->Type()->kind == IR::ValueHandle::Type::Kind::Int);
|
||||||
|
// TODO: dynamic size + alignment
|
||||||
|
auto allocSize = 4;
|
||||||
|
totalAllocSize += allocSize;
|
||||||
|
m_stackCounter += allocSize;
|
||||||
|
m_slots.insert(std::make_pair(alloc->result()->GetId(), m_stackCounter));
|
||||||
|
|
||||||
EnsureSlot(alloc->result());
|
if (seek<IR::Op>() && seek<IR::Op>()->get()->GetType() == IR::OpType::ALLOCATE) node_next();
|
||||||
|
else break;
|
||||||
|
};
|
||||||
|
output().AppendFormat(" sub rsp, %d\n", totalAllocSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateStore(IR::StoreOp* store)
|
void GenerateStore()
|
||||||
{
|
{
|
||||||
|
auto store = current<IR::StoreOp>();
|
||||||
auto sp = EnsureSlot(store->dst());
|
auto sp = EnsureSlot(store->dst());
|
||||||
|
|
||||||
// TODO: support other types
|
// TODO: support other types
|
||||||
@@ -103,8 +127,9 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateLoad(IR::LoadOp* load)
|
void GenerateLoad()
|
||||||
{
|
{
|
||||||
|
auto load = current<IR::LoadOp>();
|
||||||
auto sp = EnsureSlot(load->Ptr());
|
auto sp = EnsureSlot(load->Ptr());
|
||||||
|
|
||||||
// TODO: support other types
|
// TODO: support other types
|
||||||
@@ -115,8 +140,9 @@ private:
|
|||||||
output().AppendFormat(" mov dword [rbp-%d], eax\n", sp);
|
output().AppendFormat(" mov dword [rbp-%d], eax\n", sp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateMath(IR::MathOp* math)
|
void GenerateMath()
|
||||||
{
|
{
|
||||||
|
auto math = current<IR::MathOp>();
|
||||||
StringBuilder sb;
|
StringBuilder sb;
|
||||||
|
|
||||||
switch(math->GetType())
|
switch(math->GetType())
|
||||||
@@ -157,30 +183,31 @@ private:
|
|||||||
output().AppendFormat(" mov %s [rbp-%d], eax\n", size, sp);
|
output().AppendFormat(" mov %s [rbp-%d], eax\n", size, sp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateStatement(IR::Op* op)
|
void GenerateStatement()
|
||||||
{
|
{
|
||||||
switch(op->GetType())
|
auto op = current<IR::Op>();
|
||||||
{
|
switch(op->GetType())
|
||||||
case IR::OpType::EXTERN:
|
{
|
||||||
return GenerateExtern(reinterpret_cast<IR::ExternOp*>(op));
|
case IR::OpType::EXTERN:
|
||||||
case IR::OpType::FN:
|
return GenerateExtern();
|
||||||
return GenerateFunction(reinterpret_cast<IR::FnOp*>(op));
|
case IR::OpType::FN:
|
||||||
case IR::OpType::CALL:
|
return GenerateFunction();
|
||||||
return GenerateCall(reinterpret_cast<IR::CallOp*>(op));
|
case IR::OpType::CALL:
|
||||||
case IR::OpType::ALLOCATE:
|
return GenerateCall();
|
||||||
return GenerateAllocate(reinterpret_cast<IR::AllocateOp*>(op));
|
case IR::OpType::ALLOCATE:
|
||||||
case IR::OpType::STORE:
|
return GenerateAllocate();
|
||||||
return GenerateStore(reinterpret_cast<IR::StoreOp*>(op));
|
case IR::OpType::STORE:
|
||||||
case IR::OpType::LOAD:
|
return GenerateStore();
|
||||||
return GenerateLoad(reinterpret_cast<IR::LoadOp*>(op));
|
case IR::OpType::LOAD:
|
||||||
case IR::OpType::ADD:
|
return GenerateLoad();
|
||||||
case IR::OpType::SUB:
|
case IR::OpType::ADD:
|
||||||
case IR::OpType::MUL:
|
case IR::OpType::SUB:
|
||||||
case IR::OpType::DIV:
|
case IR::OpType::MUL:
|
||||||
return GenerateMath(reinterpret_cast<IR::MathOp*>(op));
|
case IR::OpType::DIV:
|
||||||
// TODO:
|
return GenerateMath();
|
||||||
default: output().AppendFormat(" ; %d not implemented\n", op->GetType());
|
// TODO:
|
||||||
}
|
default: output().AppendFormat(" ; %d not implemented\n", op->GetType());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -202,6 +229,19 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
template<typename T>
|
||||||
|
ListNode<T*>* node() { return reinterpret_cast<ListNode<T*>*>(m_current); }
|
||||||
|
template<typename T>
|
||||||
|
ListNode<T*>* seek() { return m_current && m_current->next ? reinterpret_cast<ListNode<T*>*>(m_current->next) : nullptr; }
|
||||||
|
|
||||||
|
void node_next() { assert(m_current); m_current = m_current->next; }
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T* current() const { return reinterpret_cast<T*>(m_current->value); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const DoubleLinkedList<IR::Op*>* m_ops;
|
||||||
|
ListNode<IR::Op*>* m_current;
|
||||||
std::unordered_map<uint32_t, uint32_t> m_slots;
|
std::unordered_map<uint32_t, uint32_t> m_slots;
|
||||||
uint32_t m_stackCounter = 0;
|
uint32_t m_stackCounter = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ using BlockID = unsigned int;
|
|||||||
class Block
|
class Block
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Block(BlockID id, const OpView& ops)
|
Block(BlockID id, DoubleLinkedList<Op*> ops)
|
||||||
: m_id(id), m_ops(DoubleLinkedList<Op*>::FromView(ops)) {}
|
: m_id(id), m_ops(ops) {}
|
||||||
public:
|
public:
|
||||||
DoubleLinkedList<Op*>& ops() { return m_ops; }
|
DoubleLinkedList<Op*>& ops() { return m_ops; }
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include "parser/nodes.hpp"
|
#include "parser/nodes.hpp"
|
||||||
#include "prelude/error.hpp"
|
#include "prelude/error.hpp"
|
||||||
|
#include "prelude/linkedlist.hpp"
|
||||||
#include "prelude/string.hpp"
|
#include "prelude/string.hpp"
|
||||||
#include "ir/value.hpp"
|
#include "ir/value.hpp"
|
||||||
#include "ir/ops.hpp"
|
#include "ir/ops.hpp"
|
||||||
@@ -13,7 +14,7 @@ namespace IR
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
IRBuilder(const StringView &filename, const Node *root)
|
IRBuilder(const StringView &filename, const Node *root)
|
||||||
: m_root(root), m_ops(new OpBuilder()), m_filename(filename) {}
|
: m_root(root), m_ops(new DoubleLinkedList<Op*>), m_filename(filename) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// TODO: support other literals
|
// TODO: support other literals
|
||||||
@@ -28,8 +29,8 @@ namespace IR
|
|||||||
auto value = ParseExpression(varDecl->value());
|
auto value = ParseExpression(varDecl->value());
|
||||||
// TODO: gather type information from var decl signature, aka local <int> v = 0;
|
// TODO: gather type information from var decl signature, aka local <int> v = 0;
|
||||||
auto dst = AllocateNamed<Pointer>(value->GetType());
|
auto dst = AllocateNamed<Pointer>(value->GetType());
|
||||||
m_ops->Push(new AllocateOp(dst, value->GetType()));
|
m_ops->Append(m_ops->New(new AllocateOp(dst, value->GetType())));
|
||||||
m_ops->Push(new StoreOp(value, reinterpret_cast<Pointer *>(dst)));
|
m_ops->Append(m_ops->New(new StoreOp(value, reinterpret_cast<Pointer *>(dst))));
|
||||||
m_locals.insert(std::make_pair(varDecl->name(), reinterpret_cast<Pointer *>(dst)));
|
m_locals.insert(std::make_pair(varDecl->name(), reinterpret_cast<Pointer *>(dst)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,22 +43,21 @@ namespace IR
|
|||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
auto dst = AllocateNamed<Instruction>(m_locals[var->name()]->GetValueType());
|
auto dst = AllocateNamed<Instruction>(m_locals[var->name()]->GetValueType());
|
||||||
m_ops->Push(new LoadOp(dst, m_locals[var->name()]));
|
m_ops->Append(m_ops->New(new LoadOp(dst, m_locals[var->name()])));
|
||||||
return reinterpret_cast<ValueHandle *>(dst);
|
return reinterpret_cast<ValueHandle *>(dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
ValueHandle *ParseFnCall(const FnCallNode *fn)
|
ValueHandle *ParseFnCall(const FnCallNode *fn)
|
||||||
{
|
{
|
||||||
// TODO: support multiple args
|
auto args = ValueBuilder();
|
||||||
auto argRegs = ValueBuilder();
|
for (size_t i = 0; i < fn->args().size; ++i)
|
||||||
if (fn->arg() != nullptr)
|
|
||||||
{
|
{
|
||||||
auto arg = ParseExpression(fn->arg());
|
auto arg = ParseExpression(fn->args().data[i]);
|
||||||
argRegs.Push(arg);
|
args.Push(arg);
|
||||||
}
|
}
|
||||||
// TODO: gather return type of the function
|
// TODO: gather return type of the function
|
||||||
auto dst = AllocateNamed<Instruction>(new ValueHandle::Type {ValueHandle::Type::Kind::Int});
|
auto dst = AllocateNamed<Instruction>(new ValueHandle::Type {ValueHandle::Type::Kind::Int});
|
||||||
m_ops->Push(new CallOp(dst, fn->name(), argRegs.view()));
|
m_ops->Append(m_ops->New(new CallOp(dst, fn->name(), args.view())));
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,16 +93,16 @@ namespace IR
|
|||||||
switch (expr->op())
|
switch (expr->op())
|
||||||
{
|
{
|
||||||
case ExpressionNode::Operator::Plus:
|
case ExpressionNode::Operator::Plus:
|
||||||
m_ops->Push(new MathOp(dst, lhs, rhs, OpType::ADD));
|
m_ops->Append(m_ops->New(new MathOp(dst, lhs, rhs, OpType::ADD)));
|
||||||
break;
|
break;
|
||||||
case ExpressionNode::Operator::Multiply:
|
case ExpressionNode::Operator::Multiply:
|
||||||
m_ops->Push(new MathOp(dst, lhs, rhs, OpType::MUL));
|
m_ops->Append(m_ops->New(new MathOp(dst, lhs, rhs, OpType::MUL)));
|
||||||
break;
|
break;
|
||||||
case ExpressionNode::Operator::Minus:
|
case ExpressionNode::Operator::Minus:
|
||||||
m_ops->Push(new MathOp(dst, lhs, rhs, OpType::SUB));
|
m_ops->Append(m_ops->New(new MathOp(dst, lhs, rhs, OpType::SUB)));
|
||||||
break;
|
break;
|
||||||
case ExpressionNode::Operator::Divide:
|
case ExpressionNode::Operator::Divide:
|
||||||
m_ops->Push(new MathOp(dst, lhs, rhs, OpType::DIV));
|
m_ops->Append(m_ops->New(new MathOp(dst, lhs, rhs, OpType::DIV)));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert(0 && "unreachable");
|
assert(0 && "unreachable");
|
||||||
@@ -131,12 +131,12 @@ namespace IR
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto ops = EndBlock();
|
auto ops = EndBlock();
|
||||||
auto block = Block(m_block_counter++, std::move(ops->view()));
|
auto block = Block(m_block_counter++, *ops);
|
||||||
operator delete(ops);
|
operator delete(ops);
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
OpView Build()
|
DoubleLinkedList<Op*>* Build()
|
||||||
{
|
{
|
||||||
assert(m_root->GetType() == NodeType::Program && "root should be a program");
|
assert(m_root->GetType() == NodeType::Program && "root should be a program");
|
||||||
auto program = reinterpret_cast<const ProgramNode *>(m_root);
|
auto program = reinterpret_cast<const ProgramNode *>(m_root);
|
||||||
@@ -144,30 +144,30 @@ namespace IR
|
|||||||
// Externs
|
// Externs
|
||||||
for (auto &extrn : program->externs())
|
for (auto &extrn : program->externs())
|
||||||
{
|
{
|
||||||
m_ops->Push(new ExternOp(extrn->symbol()));
|
m_ops->Append(m_ops->New(new ExternOp(extrn->symbol())));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Functions
|
// Functions
|
||||||
for (auto &fn : program->funcs())
|
for (auto &fn : program->funcs())
|
||||||
{
|
{
|
||||||
auto block = ParseBlock(fn->body());
|
auto block = ParseBlock(fn->body());
|
||||||
m_ops->Push(new FnOp(fn->name(), fn->params(), std::move(block)));
|
m_ops->Append(m_ops->New(new FnOp(fn->name(), fn->params(), std::move(block))));
|
||||||
}
|
}
|
||||||
|
|
||||||
return OpView(m_ops->data, m_ops->size);
|
return m_ops;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
OpView ops() const { return OpView(m_ops->data, m_ops->size); }
|
const DoubleLinkedList<Op*>* ops() const { return m_ops; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void StartBlock()
|
void StartBlock()
|
||||||
{
|
{
|
||||||
m_containers.Push(m_ops);
|
m_containers.Push(m_ops);
|
||||||
m_ops = new OpBuilder();
|
m_ops = new DoubleLinkedList<Op*>;
|
||||||
}
|
}
|
||||||
|
|
||||||
OpBuilder *EndBlock()
|
DoubleLinkedList<Op*> *EndBlock()
|
||||||
{
|
{
|
||||||
assert(m_containers.size > 0 && "containers stack is empty");
|
assert(m_containers.size > 0 && "containers stack is empty");
|
||||||
auto current = m_ops;
|
auto current = m_ops;
|
||||||
@@ -193,13 +193,13 @@ namespace IR
|
|||||||
const Node *m_root = nullptr;
|
const Node *m_root = nullptr;
|
||||||
StringView m_filename;
|
StringView m_filename;
|
||||||
|
|
||||||
OpBuilder *m_ops = nullptr;
|
DoubleLinkedList<Op*> *m_ops = nullptr;
|
||||||
unsigned int m_value_counter = 0;
|
unsigned int m_value_counter = 0;
|
||||||
unsigned int m_block_counter = 0;
|
unsigned int m_block_counter = 0;
|
||||||
|
|
||||||
std::unordered_map<StringView, Pointer *> m_locals;
|
std::unordered_map<StringView, Pointer *> m_locals;
|
||||||
|
|
||||||
Builder<OpBuilder *> m_containers;
|
Builder<DoubleLinkedList<Op*>*> m_containers;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace IR
|
} // namespace IR
|
||||||
|
|||||||
@@ -45,14 +45,15 @@ public:
|
|||||||
// m_lexer->NextExpect(TokenType::Id);
|
// m_lexer->NextExpect(TokenType::Id);
|
||||||
// char* name = strdup(m_lexer->token().string);
|
// char* name = strdup(m_lexer->token().string);
|
||||||
m_lexer->NextExpect('(');
|
m_lexer->NextExpect('(');
|
||||||
Node* arg = nullptr;
|
Builder<Node*> args;
|
||||||
// TODO: support multiple arguments
|
while (m_lexer->seek_token()->token != ')')
|
||||||
if (m_lexer->seek_token()->token != ')')
|
|
||||||
{
|
{
|
||||||
arg = ParseExpression();
|
auto arg = ParseExpression();
|
||||||
|
args.Push(arg);
|
||||||
|
if (m_lexer->seek_token()->token == ',') assert(m_lexer->NextToken());
|
||||||
}
|
}
|
||||||
m_lexer->NextExpect(')');
|
m_lexer->NextExpect(')');
|
||||||
return new FnCallNode(name, arg);
|
return new FnCallNode(name, std::move(args.view()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Node* ParseFactor()
|
Node* ParseFactor()
|
||||||
|
|||||||
@@ -144,20 +144,17 @@ class FnCallNode : public Node
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// TODO: support multiple arguments
|
// TODO: support multiple arguments
|
||||||
FnCallNode(const StringView& name, Node* arg)
|
FnCallNode(const StringView& name, View<Node*>&& arg)
|
||||||
: m_name(name), m_arg(arg) {}
|
: m_name(name), m_args(arg) {}
|
||||||
~FnCallNode() override {
|
~FnCallNode() override = default;
|
||||||
delete m_arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
NODE_TYPE(FnCall)
|
NODE_TYPE(FnCall)
|
||||||
public:
|
public:
|
||||||
const StringView& name() const { return m_name; }
|
const StringView& name() const { return m_name; }
|
||||||
// TODO: support multiple args
|
const View<Node*>& args() const { return m_args; }
|
||||||
const Node* arg() const { return m_arg; }
|
|
||||||
private:
|
private:
|
||||||
StringView m_name;
|
StringView m_name;
|
||||||
Node* m_arg;
|
View<Node*> m_args;
|
||||||
};
|
};
|
||||||
|
|
||||||
class VariableNode : public Node
|
class VariableNode : public Node
|
||||||
|
|||||||
@@ -8,12 +8,16 @@ struct ListNode
|
|||||||
T value;
|
T value;
|
||||||
ListNode* prev = nullptr;
|
ListNode* prev = nullptr;
|
||||||
ListNode* next = nullptr;
|
ListNode* next = nullptr;
|
||||||
|
public:
|
||||||
|
T& get() noexcept { return value; }
|
||||||
|
const T& get() const noexcept { return value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class DoubleLinkedList {
|
class DoubleLinkedList {
|
||||||
public:
|
public:
|
||||||
DoubleLinkedList() = default;
|
DoubleLinkedList() = default;
|
||||||
|
~DoubleLinkedList() = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static DoubleLinkedList<T> FromView(const View<T> &view)
|
static DoubleLinkedList<T> FromView(const View<T> &view)
|
||||||
@@ -26,7 +30,6 @@ public:
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
View<T> ToView()
|
View<T> ToView()
|
||||||
{
|
{
|
||||||
Builder<T> b;
|
Builder<T> b;
|
||||||
@@ -37,6 +40,9 @@ public:
|
|||||||
return b.view();
|
return b.view();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
ListNode<T>* New(T value) const { return new ListNode<T>(value); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void Append(ListNode<T>* node)
|
void Append(ListNode<T>* node)
|
||||||
{
|
{
|
||||||
|
|||||||
10
src/main.cpp
10
src/main.cpp
@@ -61,9 +61,9 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
auto ops = irBuilder.Build();
|
auto ops = irBuilder.Build();
|
||||||
|
|
||||||
for (size_t i = 0; i < ops.size; ++i)
|
for (auto cur = ops->Begin(); cur != nullptr; cur = cur->next)
|
||||||
{
|
{
|
||||||
auto op = ops.data[i];
|
auto op = cur->value;
|
||||||
if (op->GetType() == IR::OpType::FN)
|
if (op->GetType() == IR::OpType::FN)
|
||||||
{
|
{
|
||||||
auto fn = reinterpret_cast<IR::FnOp*>(op);
|
auto fn = reinterpret_cast<IR::FnOp*>(op);
|
||||||
@@ -73,15 +73,15 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < ops.size; ++i)
|
for (auto cur = ops->Begin(); cur != nullptr; cur = cur->next)
|
||||||
{
|
{
|
||||||
auto op = ops.data[i];
|
auto op = cur->value;
|
||||||
printf("%s\n", op->Format(0).c_str());
|
printf("%s\n", op->Format(0).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
FasmX86_64Generator gen;
|
FasmX86_64Generator gen;
|
||||||
|
|
||||||
gen.Generate(&ops);
|
gen.Generate(ops);
|
||||||
|
|
||||||
auto output = File::Open("example.asm", File::Mode::WRITE);
|
auto output = File::Open("example.asm", File::Mode::WRITE);
|
||||||
if (!output.Write(gen.GetOutput()))
|
if (!output.Write(gen.GetOutput()))
|
||||||
|
|||||||
Reference in New Issue
Block a user