Commit 9f4bdacd authored by zygzagZ's avatar zygzagZ

WIP code generation

parent 0c32bb1e
CC=g++ CC=g++
CCFLAGS=-g -W -Wall -O0 -std=c++2a -Wno-unused-parameter CCFLAGS=-g -W -Wall -O0 -std=c++2a -Wno-unused-parameter
OBJS=Absyn.o Lexer.o Parser.o Printer.o TypeCheck.o Info.o Skeleton.o ParseError.o Compiler.o Quadruple.o OBJS=Absyn.o Lexer.o Parser.o Printer.o TypeCheck.o Info.o Skeleton.o ParseError.o Compiler.o Quadruple.o BasicBlock.o
.PHONY : clean distclean .PHONY : clean distclean
...@@ -32,7 +32,7 @@ Skeleton.o : src/Skeleton.cpp src/Skeleton.h src/Absyn.h ...@@ -32,7 +32,7 @@ Skeleton.o : src/Skeleton.cpp src/Skeleton.h src/Absyn.h
TypeCheck.o : src/TypeCheck.cpp src/TypeCheck.h src/Info.h src/InfoList.h src/Absyn.h src/ParseError.h TypeCheck.o : src/TypeCheck.cpp src/TypeCheck.h src/Info.h src/InfoList.h src/Absyn.h src/ParseError.h
${CC} ${CCFLAGS} -c src/TypeCheck.cpp ${CC} ${CCFLAGS} -c src/TypeCheck.cpp
Compiler.o : src/Compiler.cpp src/Compiler.h src/TypeCheck.h src/Info.h src/InfoList.h src/Absyn.h src/ParseError.h Compiler.o : src/Compiler.cpp src/Compiler.h src/TypeCheck.h src/Info.h src/InfoList.h src/Absyn.h src/ParseError.h src/codeGen/Quadruple.h src/codeGen/Variable.h
${CC} ${CCFLAGS} -c src/Compiler.cpp ${CC} ${CCFLAGS} -c src/Compiler.cpp
Info.o : src/Info.cpp src/Info.h src/InfoList.h src/Absyn.h Info.o : src/Info.cpp src/Info.h src/InfoList.h src/Absyn.h
...@@ -47,6 +47,9 @@ Quadruple.o : src/codeGen/Quadruple.cpp src/Info.h src/InfoList.h src/Absyn.h sr ...@@ -47,6 +47,9 @@ Quadruple.o : src/codeGen/Quadruple.cpp src/Info.h src/InfoList.h src/Absyn.h sr
Variable.o : src/codeGen/Quadruple.h src/codeGen/Variable.cpp src/Info.h src/InfoList.h src/Absyn.h Variable.o : src/codeGen/Quadruple.h src/codeGen/Variable.cpp src/Info.h src/InfoList.h src/Absyn.h
${CC} ${CCFLAGS} -c src/codeGen/Variable.cpp ${CC} ${CCFLAGS} -c src/codeGen/Variable.cpp
BasicBlock.o : src/codeGen/Quadruple.h src/codeGen/BasicBlock.h src/codeGen/BasicBlock.cpp src/codeGen/Variable.h src/Info.h src/InfoList.h src/Absyn.h
${CC} ${CCFLAGS} -c src/codeGen/BasicBlock.cpp
Latte.o : src/Latte.cpp src/Parser.h src/Printer.h src/Absyn.h src/ParseError.h src/TypeCheck.h src/Compiler.h src/Info.h src/InfoList.h Latte.o : src/Latte.cpp src/Parser.h src/Printer.h src/Absyn.h src/ParseError.h src/TypeCheck.h src/Compiler.h src/Info.h src/InfoList.h
${CC} ${CCFLAGS} -c src/Latte.cpp ${CC} ${CCFLAGS} -c src/Latte.cpp
......
...@@ -12,6 +12,8 @@ hello: ...@@ -12,6 +12,8 @@ hello:
_start: _start:
pushl %ebp pushl %ebp
movl %esp, %ebp movl %esp, %ebp
# subl $8, %esp
andl $-16, %esp
call main call main
pushl %eax pushl %eax
call exit call exit
...@@ -24,3 +26,6 @@ call printStr ...@@ -24,3 +26,6 @@ call printStr
movl $0, %eax movl $0, %eax
leave leave
ret ret
"fun test::label XD":
ret
...@@ -45,3 +45,21 @@ void error() { ...@@ -45,3 +45,21 @@ void error() {
puts("runtime error"); puts("runtime error");
exit(1); exit(1);
} }
char* __latte_mem_init(size_t size, void* virtTab) {
char *buf = calloc(len, size);
if (!buf) error();
*((void**)buf) = virtTab;
return buf;
}
char* __latte_mem_init_array(int len, size_t size, void* virtTab) {
if (len < 0) error();
char *buf = calloc(len, size);
if (!buf) error();
if (virtTab) {
for (size_t i = 0; i < len; i++) {
*((void**)(buf + i * size)) = virtTab;
}
}
return buf;
}
...@@ -192,7 +192,7 @@ public: ...@@ -192,7 +192,7 @@ public:
class Block : public Visitable class Block : public Visitable
{ {
public: public:
std::weak_ptr<Binding> binding; std::shared_ptr<Binding> binding;
std::weak_ptr<FunctionInfo> function; std::weak_ptr<FunctionInfo> function;
virtual Block *clone() const = 0; virtual Block *clone() const = 0;
...@@ -234,13 +234,14 @@ public: ...@@ -234,13 +234,14 @@ public:
bool isEqual(shared_ptr<T> f, bool sub = false) const { return isEqual((T*)&*f, sub); }; bool isEqual(shared_ptr<T> f, bool sub = false) const { return isEqual((T*)&*f, sub); };
bool operator==(Type const & f) const { return isEqual(&f); } bool operator==(Type const & f) const { return isEqual(&f); }
bool operator!=(Type const & f) const { return !isEqual(&f); } bool operator!=(Type const & f) const { return !isEqual(&f); }
virtual size_t size() const = 0;
}; };
class Expr : public Visitable class Expr : public Visitable
{ {
public: public:
virtual Expr *clone() const = 0; virtual Expr *clone() const = 0;
shared_ptr<Type> type;
}; };
class AddOp : public Visitable class AddOp : public Visitable
...@@ -656,6 +657,7 @@ public: ...@@ -656,6 +657,7 @@ public:
return true; return true;
return false; return false;
} }
size_t size() const override { return 4; };
}; };
class Str : public Type class Str : public Type
...@@ -674,6 +676,7 @@ public: ...@@ -674,6 +676,7 @@ public:
return true; return true;
return false; return false;
} }
size_t size() const override { return 4; };
}; };
class Bool : public Type class Bool : public Type
...@@ -693,6 +696,7 @@ public: ...@@ -693,6 +696,7 @@ public:
return true; return true;
return false; return false;
} }
size_t size() const override { return 4; };
}; };
class Void : public Type class Void : public Type
...@@ -712,6 +716,7 @@ public: ...@@ -712,6 +716,7 @@ public:
return true; return true;
return false; return false;
} }
size_t size() const override { return 0; };
}; };
class Array : public Type class Array : public Type
...@@ -733,6 +738,7 @@ public: ...@@ -733,6 +738,7 @@ public:
return type_->isEqual(casted->type_, sub); return type_->isEqual(casted->type_, sub);
return false; return false;
} }
size_t size() const { return 4; } // wskaźnik na stertę
}; };
class ClassT : public Type class ClassT : public Type
...@@ -750,6 +756,7 @@ public: ...@@ -750,6 +756,7 @@ public:
void swap(ClassT &); void swap(ClassT &);
std::string printName() const { return pident_ ? ("class " + pident_->string_) : "class"; } std::string printName() const { return pident_ ? ("class " + pident_->string_) : "class"; }
bool isEqual(Type const *other, bool sub = false) const; bool isEqual(Type const *other, bool sub = false) const;
size_t size() const override { return 4; };
}; };
class Fun : public Type class Fun : public Type
...@@ -768,6 +775,7 @@ public: ...@@ -768,6 +775,7 @@ public:
void swap(Fun &); void swap(Fun &);
std::string printName() const; std::string printName() const;
bool isEqual(Type const *other, bool sub = false) const; bool isEqual(Type const *other, bool sub = false) const;
size_t size() const override { return 0; };
}; };
class EVar : public Expr class EVar : public Expr
......
#include "Compiler.h" #include "Compiler.h"
#include "codeGen/Quadruple.h"
#include <filesystem> #include <filesystem>
#include <iostream> #include <iostream>
#include <cassert>
extern std::filesystem::path binaryPath; extern std::filesystem::path binaryPath;
const std::string Compiler::extension = "s"; const std::string Compiler::extension = "s";
...@@ -20,14 +22,394 @@ void Compiler::externalCommand(std::filesystem::path lat) { ...@@ -20,14 +22,394 @@ void Compiler::externalCommand(std::filesystem::path lat) {
} }
std::string Compiler::compile(Visitable *v) { std::string Compiler::compile(Visitable *v) {
for (auto i : {"printStr", "printInt", "readInt", "readStr", "error", "exit", "_start"}) { buf <<
buf << ".globl " << i << "\n"; ".globl _start\n"
} ".globl exit\n"
buf << "_start:\n" "_start:\n"
"pushl %%ebp\n" " pushl %ebp\n"
"movl %%esp, %%ebp\n" " movl %esp, %ebp\n"
"call main\n" " call main\n"
"pushl %%eax\n" " pushl %eax\n"
"call exit\n"; " call exit\n";
for (auto c : scope->classes) {
c->calculateSize();
}
for (auto f : scope->functions) {
compileFunction(f);
}
return buf.str(); return buf.str();
} }
\ No newline at end of file
void Compiler::compileFunction(FunctionInfoPtr f) {
std::string name = mangleFunctionName(f);
buf << ".globl \"" << name << "\"\n";
if (!f->block) return;
// TODO: jeśli funkcja jest klasowa, ustawić self na ... wartosc z ecx
// c++ thiscall ecx, stack right-to-left (push c, push b, push a)
buf << "\"" << name << "\":\n";
scope->currentFunction = f;
f->block->accept(this);
int id = 1;
for (auto v : vars) {
if (v->constExpr && !v->info) {
v->name = std::to_string(v->val);
continue;
}
v->name = "@" + std::to_string(id);
if (v->info) {
v->name += "." + v->info->name + ":" + to_string(v->info->lineLocation);
}
id++;
}
int label = 1;
for (auto q : quads) {
if (auto l = dynamic_pointer_cast<QLabel>(q)) {
if (!l->label.empty())
l->label = to_string(label++) + "_" + l->label;
else
l->label = to_string(label++);
}
}
for (auto q : quads) {
buf << q->toString() << endl;
}
for (auto v : vars) {
if (v->info)
v->info->loc = nullptr;
}
quads.clear();
scope->currentFunction = nullptr;
}
void Compiler::endBasicBlock() {
for (auto v : vars) {
if (v->info) v->info->loc = nullptr;
}
}
/// expressions
void Compiler::visitEVar(EVar *p) {
lastVar = alloc(p->pident_->var.lock());
}
void Compiler::visitELitInt(ELitInt *p) {
lastVar = alloc(p->integer_);
}
void Compiler::visitELitTrue(ELitTrue *p) {
lastVar = alloc(1);
}
void Compiler::visitELitFalse(ELitFalse *p) {
lastVar = alloc(0);
}
void Compiler::visitEString(EString *p) {
// TODO: zrobic liste stringow per app
lastVar = alloc();
}
void Compiler::visitNullCast(NullCast *p) {
lastVar = alloc(0);
}
// unary ops
void Compiler::visitNeg(Neg *p) {
auto var = evalExpr(p->expr_);
lastVar = alloc();
quads.emplace_back(make_shared<QAssign>(lastVar, Op::Neg, var));
}
void Compiler::visitNot(Not *p) {
auto var = evalExpr(p->expr_);
lastVar = alloc();
quads.emplace_back(make_shared<QAssign>(lastVar, Op::Not, var));
}
// binary ops
void Compiler::visitEMul(EMul *p) {
auto l = evalExpr(p->expr_1);
auto r = evalExpr(p->expr_2);
lastVar = alloc();
p->mulop_->accept(this);
quads.emplace_back(make_shared<QAssign>(lastVar, l, op, r));
}
void Compiler::visitEAdd(EAdd *p) {
auto l = evalExpr(p->expr_1);
auto r = evalExpr(p->expr_2);
lastVar = alloc();
p->addop_->accept(this);
quads.emplace_back(make_shared<QAssign>(lastVar, l, op, r));
}
void Compiler::visitERel(ERel *p) {
auto l = evalExpr(p->expr_1);
auto r = evalExpr(p->expr_2);
lastVar = alloc();
p->relop_->accept(this);
quads.emplace_back(make_shared<QAssign>(lastVar, l, op, r));
}
// lazy bools
void Compiler::visitEAnd(EAnd *p) {
auto l = evalExpr(p->expr_1);
auto labelLeft = make_shared<QLabel>("use_left");
auto labelAfter = make_shared<QLabel>("end_and");
quads.emplace_back(make_shared<QJumpCond>(labelLeft, Op::Not, l));
auto r = evalExpr(p->expr_2);
lastVar = alloc();
quads.emplace_back(make_shared<QAssign>(lastVar, Op::Copy, r));
quads.emplace_back(make_shared<QJump>(labelAfter));
quads.emplace_back(labelLeft);
quads.emplace_back(make_shared<QAssign>(lastVar, Op::Copy, l));
quads.emplace_back(labelAfter);
}
void Compiler::visitEOr(EOr *p) {
auto l = evalExpr(p->expr_1);
auto labelLeft = make_shared<QLabel>("use_left");
auto labelAfter = make_shared<QLabel>("end_or");
quads.emplace_back(make_shared<QJumpCond>(labelLeft, Op::Copy, l));
auto r = evalExpr(p->expr_2);
lastVar = alloc();
quads.emplace_back(make_shared<QAssign>(lastVar, Op::Copy, r));
quads.emplace_back(make_shared<QJump>(labelAfter));
quads.emplace_back(labelLeft);
quads.emplace_back(make_shared<QAssign>(lastVar, Op::Copy, l));
quads.emplace_back(labelAfter);
}
// complex extensions
void Compiler::visitEIndexAcc(EIndexAcc *p) {
auto lhs = evalExpr(p->expr_1);
auto index = evalExpr(p->expr_2);
lastVar = alloc();
auto type = dynamic_pointer_cast<Array>(lhs->type);
if (!type) {
throw ParseError("compiler evalExpr Variable has no Array type", p->expr_1);
}
if (!type->type_) {
throw ParseError("compiler evalExpr Variable is Array of no type", p->expr_1);
}
if (type->type_->size() > 4) {
// calculate quantifier, we multiply index because size is larger than 4
auto q = alloc(type->type_->size() / 4);
// calculate var = index * quantifier
quads.emplace_back(make_shared<QAssign>(lastVar, index, Op::Mul, q));
// allocate new lastVar, index is now calculated multiplied index
index = alloc();
swap(index, lastVar);
}
auto quad = make_shared<QAccess>(lastVar, lhs, index, 4, 0);
quads.emplace_back(quad);
}
void Compiler::visitEClsMmbr(EClsMmbr *p) {
auto l = evalExpr(p->expr_);
auto var = p->pident_->var.lock();
assert(var);
// it cannot be function, as function might only be used in EApp and are handled directly there
assert(!var->toFunction());
size_t offset = var->offset;
// TODO: Array length calculation
// if ()
if (dynamic_cast<EIndexAcc*>(p->expr_)) {
// opt if EIndexAcc is used inside visitEClsMmbr
auto access = dynamic_pointer_cast<QAccess>(quads.back());
access->offset += offset;
lastVar = l;
} else {
lastVar = alloc();
auto quad = make_shared<QAccess>(lastVar, l, alloc(0), 0, offset);
quads.emplace_back(quad);
}
}
void Compiler::visitEApp(EApp *p) {
auto funType = static_pointer_cast<Fun>(p->expr_->type);
FunctionInfoPtr info;
VariablePtr self;
if (auto mem = dynamic_cast<EClsMmbr*>(p->expr_)) {
// call tab[i].fun()
// call obj.fun()
self = evalExpr(mem->expr_);
info = static_pointer_cast<FunctionInfo>(mem->pident_->var.lock());
} else if (auto ident = dynamic_cast<EVar*>(p->expr_)) {
auto klass = scope->currentFunction->klass.lock();
info = static_pointer_cast<FunctionInfo>(ident->pident_->var.lock());
auto otherClass = info->klass.lock();
if (otherClass) {
// call fun() = self.fun()
assert(otherClass == klass);
auto binding = scope->currentFunction->binding.lock();
assert(binding);
auto selfInfo = binding->variables.local("self");
assert(selfInfo);
self = alloc(selfInfo);
} else {
// call main()
}
} else {
throw ParseError("Unimplemented EApp instantiation (neither EClsMmbr nor EVar", p);
}
int i = 1;
for (auto param : *p->listexpr_) {
auto var = evalExpr(param);
quads.emplace_back(make_shared<QParam>(var, i++));
}
if (self) {
quads.emplace_back(make_shared<QParam>(self, 0));
}
lastVar = alloc();
quads.emplace_back(make_shared<QCall>(lastVar, info, i, self));
}
void Compiler::visitENewArray(ENewArray *p) {
// allocate enough memory with calloc, if it is class then init each entry...
auto type = p->type_;
size_t size = type->size();
std::string virtSymbol;
if (auto klass = dynamic_cast<ClassT*>(type)) {
auto info = klass->pident_->var.lock()->toClass();
size = info->size;
virtSymbol = getVirtName(info);
}
auto count = evalExpr(p->expr_);
lastVar = alloc();
quads.emplace_back(make_shared<QAlloc>(lastVar, size, virtSymbol, count));
}
void Compiler::visitENewClass(ENewClass *p) {
// allocate enough memory with calloc, setup virt table pointer.
auto info = p->pident_->var.lock()->toClass();
size_t size = info->size;
std::string virtSymbol = getVirtName(info);
lastVar = alloc();
quads.emplace_back(make_shared<QAlloc>(lastVar, size, virtSymbol));
}
/// statements
void Compiler::visitInit(Init *p) {
auto info = p->pident_->var.lock();
assert(info);
auto var = evalExpr(p->expr_);
quads.emplace_back(make_shared<QAssign>(alloc(info), Op::Copy, var));
}
void Compiler::visitAss(Ass *p) {
auto dest = evalExpr(p->expr_1);
quads.emplace_back(make_shared<QAssign>(dest, Op::Copy, evalExpr(p->expr_2)));
}
void Compiler::visitIncr(Incr *p) {
auto dest = evalExpr(p->expr_);
auto lhs = evalExpr(p->expr_);
quads.emplace_back(make_shared<QAssign>(dest, lhs, Op::Plus, alloc(1)));
}
void Compiler::visitDecr(Decr *p) {
auto dest = evalExpr(p->expr_);
auto lhs = evalExpr(p->expr_);
quads.emplace_back(make_shared<QAssign>(dest, lhs, Op::Minus, alloc(1)));
}
void Compiler::visitRet(Ret *p) {
auto var = evalExpr(p->expr_);
endBasicBlock();
quads.emplace_back(make_shared<QReturn>(var));
}
void Compiler::visitVRet(VRet *p) {
endBasicBlock();
quads.emplace_back(make_shared<QReturn>(nullptr));
}
void Compiler::visitCond(Cond *p) {
auto var = evalExpr(p->expr_);
auto after = make_shared<QLabel>("end_if");
endBasicBlock(); // possible jump -> after
quads.emplace_back(make_shared<QJumpCond>(after, Op::Not, var));
p->stmt_->accept(this);
endBasicBlock(); // possible jump <- cond
quads.emplace_back(after);
}
void Compiler::visitCondElse(CondElse *p) {
auto elseBranch = make_shared<QLabel>("else");
auto after = make_shared<QLabel>("end_else");
auto var = evalExpr(p->expr_);
endBasicBlock(); // possible jump -> else
quads.emplace_back(make_shared<QJumpCond>(elseBranch, Op::Not, var));
p->stmt_1->accept(this);
endBasicBlock(); // jump -> after
quads.emplace_back(make_shared<QJump>(after));
quads.emplace_back(elseBranch);
p->stmt_2->accept(this);
endBasicBlock(); // jump <- cond
quads.emplace_back(after);
}
void Compiler::visitWhile(While *p) {
auto cond = make_shared<QLabel>("cond");
endBasicBlock(); // jump <- loop -> cond
quads.emplace_back(make_shared<QJump>(cond));
// jump <- loop
auto loop = make_shared<QLabel>("loop");
quads.emplace_back(loop);
p->stmt_->accept(this);
endBasicBlock(); // jump <- cond
quads.emplace_back(cond);
auto var = evalExpr(p->expr_);
endBasicBlock(); // jump -> loop
quads.emplace_back(make_shared<QJumpCond>(loop, Op::Copy, var));
}
void Compiler::visitSExp(SExp *p) {
evalExpr(p->expr_);
}
void Compiler::visitForEach(ForEach *p) {
auto tab = evalExpr(p->expr_);
throw ParseError("Unimplemented instruction!", p);
// TODO: implement
}
...@@ -9,7 +9,10 @@ ...@@ -9,7 +9,10 @@
#include "codeGen/Variable.h" #include "codeGen/Variable.h"
#include "ParseError.h" #include "ParseError.h"
#include "Info.h" #include "Info.h"
#include "codeGen/Quadruple.h"
#include "codeGen/BasicBlock.h"
using Op = Quadruple::Op;
class Compiler : public Skeleton class Compiler : public Skeleton
{ {
public: public:
...@@ -23,9 +26,14 @@ private: ...@@ -23,9 +26,14 @@ private:
std::filesystem::path file; std::filesystem::path file;
std::stringstream buf; std::stringstream buf;
shared_ptr<Scope> scope; shared_ptr<Scope> scope;
vector<VariablePtr> vars;
vector<QuadruplePtr> quads;
Quadruple::Op op;
VariablePtr lastVar; VariablePtr lastVar;
void compileFunction(FunctionInfoPtr f);
VariablePtr evalExpr(Visitable *expr) { VariablePtr evalExpr(Visitable *expr) {
if (!expr) throw runtime_error("No expr to eval"); if (!expr) throw runtime_error("No expr to eval");
lastVar = nullptr; lastVar = nullptr;
...@@ -39,6 +47,80 @@ private: ...@@ -39,6 +47,80 @@ private:
lastVar = nullptr; lastVar = nullptr;
return ret; return ret;
}; };
std::string mangleFunctionName(FunctionInfoPtr f) const {
if (auto c = f->klass.lock()) {
return c->name + "::" + f->name;
}
return f->name;
};
std::string getVirtName(ClassInfoPtr c) const {
return c->name + ":virt_table";
};
VariablePtr alloc(VarInfoPtr info) {
if (info->loc) {
return info->loc;
}
auto v = make_shared<Variable>(info);
vars.emplace_back(v);
info->loc = v;
return v;
}
template<typename... Args> VariablePtr alloc(Args... args) {
auto v = make_shared<Variable>(args...);
vars.emplace_back(v);
return v;
}
void endBasicBlock();
void visitEVar(EVar *p) override;
void visitEIndexAcc(EIndexAcc *p) override;
void visitEClsMmbr(EClsMmbr *p) override;
void visitEApp(EApp *p) override;
void visitELitInt(ELitInt *p) override;
void visitELitTrue(ELitTrue *p) override;
void visitELitFalse(ELitFalse *p) override;
void visitEString(EString *p) override;
void visitENewArray(ENewArray *p) override;
void visitENewClass(ENewClass *p) override;
void visitNullCast(NullCast *p) override;
void visitNeg(Neg *p) override;
void visitNot(Not *p) override;
void visitEMul(EMul *p) override;
void visitEAdd(EAdd *p) override;
void visitERel(ERel *p) override;
void visitEAnd(EAnd *p) override;
void visitEOr(EOr *p) override;
void visitInit(Init *p) override;
void visitAss(Ass *p) override;
void visitIncr(Incr *p) override;
void visitDecr(Decr *p) override;
void visitRet(Ret *p) override;
void visitVRet(VRet *p) override;
void visitCond(Cond *p) override;
void visitCondElse(CondElse *p) override;
void visitWhile(While *p) override;
void visitSExp(SExp *p) override;
void visitForEach(ForEach *p) override;
void visitPlus(Plus *p) override { op = Op::Plus; };
void visitMinus(Minus *p) override { op = Op::Minus; };
void visitTimes(Times *p) override { op = Op::Mul; };
void visitDiv(Div *p) override { op = Op::Div; };
void visitMod(Mod *p) override { op = Op::Mod; };
void visitLTH(LTH *p) override { op = Op::LT; };
void visitLE(LE *p) override { op = Op::LE; };
void visitGTH(GTH *p) override { op = Op::GT; };
void visitGE(GE *p) override { op = Op::GE; };
void visitEQU(EQU *p) override { op = Op::EQ; };
void visitNE(NE *p) override { op = Op::NEQ; };
}; };
#endif #endif
...@@ -24,14 +24,35 @@ Binding::Binding(shared_ptr<Binding> parent) ...@@ -24,14 +24,35 @@ Binding::Binding(shared_ptr<Binding> parent)
} }
ClassInfo::ClassInfo(PIdent *ident, BindingPtr parent /*= nullptr*/) ClassInfo::ClassInfo(PIdent *ident, BindingPtr parent /*= nullptr*/)
: VarInfo(ident), : VarInfo(ident),
Binding(parent) Binding(parent),
size(0), functionCount(0)
{ {
type = make_shared<ClassT>(ident->clone()); type = make_shared<ClassT>(ident->clone());
type->binding = parent; type->binding = parent;
}
size_t ClassInfo::calculateSize() {
if (size) return size;
size = 4; // pointer to virtual methods table
if (auto p = getParent()) { // parent already has virt pointer included
p->calculateSize();
size = p->size;
functionCount = p->functionCount;
}
for (const auto& var : variables) {
var->offset = size;
size += var->type->size();
}
for (auto f : functions) {
f->offset = functionCount++;
}
return size;
}; };
Scope::Scope() Scope::Scope()
......
...@@ -26,6 +26,9 @@ public: ...@@ -26,6 +26,9 @@ public:
string name; string name;
TypePtr type; TypePtr type;
int lineLocation; int lineLocation;
size_t offset;
VariablePtr loc;
bool operator<(const VarInfo &other) const { bool operator<(const VarInfo &other) const {
return name != other.name ? name < other.name : type < other.type; return name != other.name ? name < other.name : type < other.type;
...@@ -58,7 +61,7 @@ public: ...@@ -58,7 +61,7 @@ public:
Binding(BindingPtr parent = nullptr); Binding(BindingPtr parent = nullptr);
virtual ~Binding() {}; virtual ~Binding() {};
BindingPtr getParent() const { return parent.lock(); }; BindingPtr getParent() { return parent.lock(); };
}; };
class ClassInfo : public VarInfo, public Binding class ClassInfo : public VarInfo, public Binding
...@@ -68,7 +71,9 @@ public: ...@@ -68,7 +71,9 @@ public:
ClassInfo(PIdent *ident, BindingPtr parent = nullptr); ClassInfo(PIdent *ident, BindingPtr parent = nullptr);
virtual string kind() const { return "class"; } virtual string kind() const { return "class"; }
ClassInfoPtr getParent() const { return dynamic_pointer_cast<ClassInfo>(parent.lock()); }; ClassInfoPtr getParent() { return dynamic_pointer_cast<ClassInfo>(parent.lock()); };
size_t calculateSize();
size_t size, functionCount;
}; };
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include <stdexcept> #include <stdexcept>
#include "Printer.h" #include "Printer.h"
#include <climits> #include <climits>
#include <cassert>
void TypeCheck::visitClassDef(ClassDef *t) { void TypeCheck::visitClassDef(ClassDef *t) {
const string name = t->getName()->string_; const string name = t->getName()->string_;
...@@ -116,7 +117,7 @@ void TypeCheck::visitClassFld(ClassFld *decl) ...@@ -116,7 +117,7 @@ void TypeCheck::visitClassFld(ClassFld *decl)
void TypeCheck::visitBlk(Blk *blk) void TypeCheck::visitBlk(Blk *blk)
{ {
BindingPtr binding = blk->binding.lock(); BindingPtr binding = blk->binding/*.lock()*/;
if (!binding) { if (!binding) {
binding = make_shared<Binding>(scope->currentBinding); binding = make_shared<Binding>(scope->currentBinding);
blk->binding = binding; blk->binding = binding;
...@@ -317,13 +318,12 @@ void TypeCheck::visitEClsMmbr(EClsMmbr *e_cls_mmbr) ...@@ -317,13 +318,12 @@ void TypeCheck::visitEClsMmbr(EClsMmbr *e_cls_mmbr)
throw ParseError("Class expected", e_cls_mmbr->expr_); throw ParseError("Class expected", e_cls_mmbr->expr_);
} }
ClassInfoPtr klass = scope->classes[type->pident_]; ClassInfoPtr klass = scope->classes[type->pident_];
if (klass != type->pident_->var.lock()) { assert(klass == type->pident_->var.lock());
throw ParseError("ej lol inny var");
}
VarInfoPtr var = klass->variables[e_cls_mmbr->pident_]; VarInfoPtr var = klass->variables[e_cls_mmbr->pident_];
if (!var || var == scope->variables.local(e_cls_mmbr->pident_->string_)) { if (!var || var == scope->variables.local(e_cls_mmbr->pident_->string_)) {
throw UndefinedError(e_cls_mmbr->pident_); throw UndefinedError(e_cls_mmbr->pident_);
} }
e_cls_mmbr->pident_->var = var;
lastType = var->type; lastType = var->type;
} }
...@@ -392,19 +392,11 @@ void TypeCheck::visitENewArray(ENewArray *e) ...@@ -392,19 +392,11 @@ void TypeCheck::visitENewArray(ENewArray *e)
void TypeCheck::visitENewClass(ENewClass *e_new_class) void TypeCheck::visitENewClass(ENewClass *e_new_class)
{ {
// e_new_class->pident_->accept(this); e_new_class->pident_->accept(this);
lastType = evalExpr<ClassT>(e_new_class->pident_); if (!dynamic_pointer_cast<ClassT>(lastType)) {
// if (!e_new_class->pident_->var.lock()) { ClassT expect;
throw InvalidTypeError(expect, {lastType}, e_new_class);
// } }
// ClassInfoPtr klass = dynamic_pointer_cast<ClassInfo>(e_new_class->pident_->var.lock());
// if (!klass) {
// throw ParseError("Class expected", e_new_class->pident_);
// }
// auto ret = make_shared<ClassT>(e_new_class->pident_); // make type
// ret->binding = scope->currentBinding;
// lastType = ret;
} }
void TypeCheck::visitNullCast(NullCast *null_cast) void TypeCheck::visitNullCast(NullCast *null_cast)
......
...@@ -29,7 +29,7 @@ class TypeCheck : public Visitor ...@@ -29,7 +29,7 @@ class TypeCheck : public Visitor
void setupEnv(); void setupEnv();
template<typename T> template<typename T>
shared_ptr<T> evalExpr(Visitable *expr) { shared_ptr<T> evalExpr(Expr *expr) {
if (!expr) throw runtime_error("No expr to eval"); if (!expr) throw runtime_error("No expr to eval");
lastType = nullptr; lastType = nullptr;
try { try {
...@@ -42,11 +42,12 @@ class TypeCheck : public Visitor ...@@ -42,11 +42,12 @@ class TypeCheck : public Visitor
T expect; T expect;
throw InvalidTypeError(expect, {lastType}, expr); throw InvalidTypeError(expect, {lastType}, expr);
} }
expr->type = lastType;
lastType = nullptr; lastType = nullptr;
return ret; return ret;
}; };
shared_ptr<Type> evalExpr(Visitable *expr) { shared_ptr<Type> evalExpr(Expr *expr) {
if (!expr) throw runtime_error("No expr to eval"); if (!expr) throw runtime_error("No expr to eval");
try { try {
expr->accept(this); expr->accept(this);
...@@ -54,9 +55,12 @@ class TypeCheck : public Visitor ...@@ -54,9 +55,12 @@ class TypeCheck : public Visitor
throw ParseError(err, expr); throw ParseError(err, expr);
} }
if (!lastType) throw ParseError("No expression type", expr); if (!lastType) throw ParseError("No expression type", expr);
auto ret = lastType; if (auto fun = dynamic_pointer_cast<Fun>(lastType)) {
throw ParseError("Unexpected function access", expr);
}
expr->type = lastType;
lastType = nullptr; lastType = nullptr;
return ret; return expr->type;
}; };
public: public:
BindingPtr getParentBinding() const { return scope->currentClass ? static_pointer_cast<Binding>(scope->currentClass) : static_pointer_cast<Binding>(scope); } BindingPtr getParentBinding() const { return scope->currentClass ? static_pointer_cast<Binding>(scope->currentClass) : static_pointer_cast<Binding>(scope); }
......
...@@ -6,16 +6,21 @@ ...@@ -6,16 +6,21 @@
using namespace std; using namespace std;
class VarInfo; class VarInfo;
class FunctionInfo;
class ClassInfo;
class Binding;
class Type;
using VarInfoPtr = shared_ptr<VarInfo>; using VarInfoPtr = shared_ptr<VarInfo>;
class FunctionInfo;
using FunctionInfoPtr = shared_ptr<FunctionInfo>; using FunctionInfoPtr = shared_ptr<FunctionInfo>;
class ClassInfo;
using ClassInfoPtr = shared_ptr<ClassInfo>; using ClassInfoPtr = shared_ptr<ClassInfo>;
class Binding;
using BindingPtr = shared_ptr<Binding>; using BindingPtr = shared_ptr<Binding>;
class Type;
using TypePtr = shared_ptr<Type>; using TypePtr = shared_ptr<Type>;
class Variable;
using VariablePtr = shared_ptr<Variable>;
class Quadruple;
using QuadruplePtr = shared_ptr<Quadruple>;
class BasicBlock;
using BasicBlockPtr = shared_ptr<BasicBlock>;
class Visitable; class Visitable;
class Program; class Program;
......
//
// Created by zygzagz on 03.01.2021.
//
#include "BasicBlock.h"
//
// Created by zygzagz on 03.01.2021.
//
#ifndef ZAD2_BASICBLOCK_H
#define ZAD2_BASICBLOCK_H
#include "../TypeDefs.h"
#include <vector>
using namespace std;
class BasicBlock {
vector<QuadruplePtr> quads;
vector<BasicBlockPtr> in, out;
};
#endif //ZAD2_BASICBLOCK_H
#ifndef ZAD2_QUAD_H #ifndef ZAD2_QUAD_H
#define ZAD2_QUAD_H #define ZAD2_QUAD_H
#include <string> #include <string>
#include <utility>
#include "../Info.h" #include "../Info.h"
#include "Variable.h" #include "Variable.h"
using namespace std; using namespace std;
class Quadruple { static const std::string opNames[] = { "_U", "-", "!", "", "_UE",
public: "_B", "+", "-", "*", "/", "%", "&", "|", "^", "_BE",
enum Op { "_C", "<", "<=", "==", "!=", ">=", ">", "_CE"};
UNARY,
Neg, class Quadruple : std::enable_shared_from_this<Quadruple> {
Not, public:
BINARY, class Op {
Plus, public:
Minus, enum OpType {
Mul, UNARY,
Div, Neg, Not, Copy, UNARY_END,
And, BINARY,
Or, Plus, Minus, Mul, Div, Mod, And, Or, Xor, BINARY_END,
Xor, CMP,
LT, LE, EQ, NEQ, GE, GT, CMP_END
};
OpType op;
Op(OpType op = UNARY) : op(op) {};
operator OpType() const { return op; };
static OpType kind(OpType op) {
if (op <= UNARY_END) return UNARY;
if (op <= BINARY_END) return BINARY;
return CMP;
};
static const std::string& name(OpType op) {
return opNames[op];
}
}; };
string label; virtual ~Quadruple() {};
virtual std::string toString() const = 0;
}; };
class QAssign : Quadruple { class QWriteVar : public Quadruple {
public:
VariablePtr loc; VariablePtr loc;
explicit QWriteVar(VariablePtr loc) : Quadruple(), loc(std::move(loc)) {};
std::string toString() const override { return loc ? ("\t" + loc->name + " := ") : "\t"; }
};
class QLabel : public Quadruple {
public:
string label;
std::string toString() const override { return "\"" + label + "\":"; }
QLabel(std::string comment) : label(comment) {}
};
class QAssign : public QWriteVar {
public:
Op op; Op op;
vector<VariablePtr> args; vector<VariablePtr> args;
VarInfoPtr varInfo;
QAssign(VariablePtr loc, Op op, vector<VariablePtr> list) : QWriteVar(std::move(loc)), op(op), args(std::move(list)) {};
QAssign(VariablePtr loc, VariablePtr l, Op op, VariablePtr r) : QWriteVar(std::move(loc)), op(op), args({std::move(l), std::move(r)}) {};
QAssign(VariablePtr loc, Op op, VariablePtr x) : QWriteVar(std::move(loc)), op(op), args({std::move(x)}) {};
std::string toString() const override {
if (args.size() == 1)
return QWriteVar::toString() + Op::name(op) + " " + args[0]->name;
else
return QWriteVar::toString() + args[0]->name + " " + Op::name(op) + " " + args[1]->name;
}
};
class QJump : public Quadruple {
public:
shared_ptr<QLabel> target;
explicit QJump(shared_ptr<QLabel> target) : target(std::move(target)) {};
std::string toString() const override {
return "\tjump " + target->label;
}
};
class QJumpCond : public QJump {
public:
VariablePtr left;
Op op;
VariablePtr right;
QJumpCond(shared_ptr<QLabel> to, VariablePtr left, Op op, VariablePtr right)
: QJump(std::move(to)), left(std::move(left)), op(op), right(std::move(right)) {};
QJumpCond(shared_ptr<QLabel> to, Op op, VariablePtr right)
: QJumpCond(std::move(to), nullptr, op, std::move(right)) {};
std::string toString() const override {
if (!left)
return "\tjump \"" + target->label + "\" if " + Op::name(op) + " " + right->name;
else
return "\tjump \"" + target->label + "\" if " + left->name + " " + Op::name(op) + " " + right->name;
}
};
class QParam : public Quadruple {
public:
VariablePtr param;
int num;
QParam(VariablePtr param, int num) : param(std::move(param)), num(num) {};
std::string toString() const override {
if (num == 0) {
return "\tparam self " + param->name;
} else {
return "\tparam #" + to_string(num) + " <- " + param->name;
}
}
};
class QCall : public QWriteVar {
public:
FunctionInfoPtr fn;
int params;
VariablePtr self;
QCall(VariablePtr loc, FunctionInfoPtr fn, int params, VariablePtr self)
: QWriteVar(std::move(loc)), fn(std::move(fn)), params(params), self(std::move(self)) {};
std::string toString() const override {
if (self) {
return QWriteVar::toString() + "call " + fn->name + " of " + self->name + " with " + to_string(params) + " params";
} else {
return QWriteVar::toString() + "call " + fn->name + " with " + to_string(params) + " params";
}
}
};
class QReturn : public Quadruple {
public:
VariablePtr ret;
explicit QReturn(VariablePtr ret) : ret(std::move(ret)) {};
std::string toString() const override {
if (ret) {
return "\treturn " + ret->name;
} else {
return "\treturn";
}
}
};
class QAccess : public QWriteVar {
public:
QAccess(VariablePtr loc, VariablePtr base, VariablePtr index, int multiplier, int offset)
: QWriteVar(std::move(loc)), base(std::move(base)), index(std::move(index)), multiplier(multiplier), offset(offset)
{};
// leal 8(,%eax,4), %eax # Arithmetic: multiply eax by 4 and add 8
// leal (%edx,%eax,2), %eax # Arithmetic: multiply eax by 2 and add edx
VariablePtr base;
VariablePtr index;
int multiplier;
int offset;
std::string toString() const override {
auto ret = QWriteVar::toString() + "[" + base->name;
if (multiplier || !(index->constExpr || !index->val)) ret += " + " + to_string(multiplier) + "*" + index->name;
if (offset) ret += " + " + to_string(offset);
return ret + "]";
}
};
class QAlloc : public QWriteVar {
public:
size_t size;
VariablePtr count;
std::string virtSymbol;
QAlloc(VariablePtr loc, size_t size, std::string virtSymbol, VariablePtr count = nullptr)
: QWriteVar(std::move(loc)), size(size), count(std::move(count)), virtSymbol(std::move(virtSymbol)) {};
std::string toString() const override {
std::string ret = QWriteVar::toString() + "alloc (" + to_string(size) + ")";
if (count) { ret += " [" + count->name + "]"; }
if (!virtSymbol.empty()) { ret += " " + virtSymbol; }
return ret;
}
}; };
......
...@@ -5,14 +5,26 @@ ...@@ -5,14 +5,26 @@
#ifndef ZAD2_VARIABLE_H #ifndef ZAD2_VARIABLE_H
#define ZAD2_VARIABLE_H #define ZAD2_VARIABLE_H
#include <utility>
#include "../TypeDefs.h"
class Variable : std::enable_shared_from_this<Variable> { class Variable : std::enable_shared_from_this<Variable> {
public:
Variable() = default;
explicit Variable(VarInfoPtr info) : info(std::move(info)), constExpr(false), val(0) {};
explicit Variable(int constVal) : type(new Int), constExpr(true), val(constVal) {};
explicit Variable(std::string symbolName) {};
VarInfoPtr info;
TypePtr type;
bool constExpr;
int val;
std::string name;
// chcemy znać lokalizację w pamięci gdzie zapisać z powrotem i gdzie leży ogólnie
// lok. może nie być, jeśli to tymczasowa
// registers // registers
// is mem? // is mem?
// where in mem - id or offset // where in mem - id or offset
}; };
using VariablePtr = shared_ptr<Variable>;
#endif //ZAD2_VARIABLE_H #endif //ZAD2_VARIABLE_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment