Skip to content

Commit

Permalink
Merge branch 'feature/parser/switch' into develop
Browse files Browse the repository at this point in the history
# Conflicts:
#	include/codegen/il2mips.hpp
#	src/codegen/il2mips.cpp
#	test/parser/testProgram.c
  • Loading branch information
EthanSK committed Mar 26, 2019
2 parents 48bef36 + bcbc77b commit aaadef1
Show file tree
Hide file tree
Showing 39 changed files with 481 additions and 60 deletions.
6 changes: 5 additions & 1 deletion include/ast/blocks/scopeBlock.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@

#include "sequenceBlock.hpp"

class ScopeBlock;
typedef const ScopeBlock* ScopeBlockPtr;

class ScopeBlock : public SequenceBlock //aka compound statement, used to represent content between curly braces everywhere eg loops, conditions, pure scope, etc...
{
public:
using SequenceBlock::SequenceBlock;
void generatePython(std::ostream &os, PythonContext &context, int scopeDepth = 0) const override;
void generateIL(std::vector<Instr> &instrs, ILContext &context, std::string destReg) const override;
virtual void generateIL(std::vector<Instr> &instrs, ILContext &context, std::string destReg) const override;
std::vector<StatementPtr> getBranches() const;

protected:
void printC(std::ostream &os) const override;
Expand Down
2 changes: 1 addition & 1 deletion include/ast/blocks/sequenceBlock.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class SequenceBlock : public Statement
void generateIL(std::vector<Instr> &instrs, ILContext &context, std::string destReg) const override;

protected:
void printC(std::ostream &os) const override;
virtual void printC(std::ostream &os) const override;
};

#endif
27 changes: 27 additions & 0 deletions include/ast/conditions/switch/switchCase.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#ifndef switchCondition_hpp
#define switchCondition_hpp

#include <vector>
#include <string>
#include <iostream>
#include <memory>
#include "statement.hpp"
#include "rvalue.hpp"
#include "utils.hpp"

class SwitchCase;
typedef const SwitchCase *SwitchCasePtr;

class SwitchCase : public Statement
{
public:
SwitchCase(StatementPtr condition, StatementPtr scopeBlock);
virtual void generateIL(std::vector<Instr> &instrs, ILContext &context, std::string destReg) const override;
StatementPtr getCondition() const; //the thing for the case that it needs to equal to
StatementPtr getScopeBlock() const; //execution block

protected:
virtual void printC(std::ostream &os) const override;
};

#endif
23 changes: 23 additions & 0 deletions include/ast/conditions/switch/switchDefault.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#ifndef switchDefault_hpp
#define switchDefault_hpp

#include <vector>
#include <string>
#include <iostream>
#include <memory>
#include "switchCase.hpp"

class SwitchDefault;
typedef const SwitchDefault* SwitchDefaultPtr;

class SwitchDefault : public SwitchCase
{
public:
SwitchDefault(StatementPtr scopeBlock);
void generateIL(std::vector<Instr> &instrs, ILContext &context, std::string destReg) const override;

protected:
void printC(std::ostream &os) const override;
};

#endif
29 changes: 29 additions & 0 deletions include/ast/conditions/switch/switchStatement.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#ifndef switch_hpp
#define switch_hpp

#include <vector>
#include <string>
#include <iostream>
#include <memory>
#include "statement.hpp"
#include "scopeBlock.hpp"

#include "utils.hpp"

class SwitchStatement;
typedef const SwitchStatement* SwitchStatementPtr;

class SwitchStatement : public Statement
{
public:
SwitchStatement(StatementPtr caseExpr, StatementPtr switchBlock);
void generateIL(std::vector<Instr> &instrs, ILContext &context, std::string destReg) const override;

protected:
StatementPtr getCase() const; //as in the a in switch(a)
StatementPtr getSwitchBlock() const; //contains cases and maybe default. just a regular scope block

void printC(std::ostream &os) const override;
};

#endif
2 changes: 2 additions & 0 deletions include/codegen/il2mips.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ class IL2MIPS //one IL may map to many MIPS
static void gt(Instr instr, MIPSContext &context);
static void gte(Instr instr, MIPSContext &context);
static void b(Instr instr, MIPSContext &context);
static void beq(Instr instr, MIPSContext &context);
static void bez(Instr instr, MIPSContext &context);
static void bgz(Instr instr, MIPSContext &context);
static void bne(Instr instr, MIPSContext &context);
static void bnez(Instr instr, MIPSContext &context);
static void xorM(Instr instr, MIPSContext &context);
static void andM(Instr instr, MIPSContext &context);
Expand Down
8 changes: 4 additions & 4 deletions include/context/ilContext.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ typedef const Statement *StatementPtr;

class ILContext : public Context
{
public:
std::string makeName(std::string name);
std::string makeLabelName(std::string name);
void compileInput(StatementPtr input, std::vector<Instr> &instrs, std::string destReg);
public:
std::string makeName(std::string name);
std::string makeLabelName(std::string name);
void compileInput(StatementPtr input, std::vector<Instr> &instrs, std::string destReg);

void registerFuncSymbol(std::string symbolName);
bool isFuncSymbolDefined(std::string symbolName) const;
Expand Down
3 changes: 3 additions & 0 deletions include/headers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,7 @@
#include "continueKeyword.hpp"
#include "returnKeyword.hpp"
#include "breakKeyword.hpp"
#include "switchStatement.hpp"
#include "switchCase.hpp"
#include "switchDefault.hpp"
#endif
15 changes: 10 additions & 5 deletions src/ast/blocks/scopeBlock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
void ScopeBlock::printC(std::ostream &os) const
{
os << "\n{\n";
for(size_t i = 0; i < branches.size(); i++)
for (size_t i = 0; i < branches.size(); i++)
{
os << branches[i] << ";\n";
}
Expand All @@ -19,21 +19,26 @@ void ScopeBlock::generatePython(std::ostream &os, PythonContext &context, int sc
}
else
{
for(size_t i = 0; i < branches.size(); i++)
for (size_t i = 0; i < branches.size(); i++)
{
context.indentStream(os, scopeDepth);
branches[i]->generatePython(os, context, scopeDepth);
}
os <<std::flush;
os << std::flush;
}
}

void ScopeBlock::generateIL(std::vector<Instr> &instrs, ILContext &context, std::string destReg) const
{
instrs.push_back(Instr("scu"));
for(size_t i = 0; i < branches.size(); i++)
for (size_t i = 0; i < branches.size(); i++)
{
branches[i]->generateIL(instrs, context, destReg);
}
instrs.push_back(Instr("scd"));
}
}

std::vector<StatementPtr> ScopeBlock::getBranches() const
{
return branches;
}
29 changes: 29 additions & 0 deletions src/ast/conditions/switch/switchCase.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#include "switchCase.hpp"

SwitchCase::SwitchCase(StatementPtr condition, StatementPtr scopeBlock)
{
branches.push_back(condition);
branches.push_back(scopeBlock);
}

StatementPtr SwitchCase::getCondition() const
{
return branches[0];
}
StatementPtr SwitchCase::getScopeBlock() const
{
return branches[1];
}
void SwitchCase::printC(std::ostream &os) const
{
os << "case " << getCondition() << ": " << getScopeBlock(); //wont technically be correct as scope block in case doesn't have {} but doesn't really matter for printing
}

void SwitchCase::generateIL(std::vector<Instr> &instrs, ILContext &context, std::string destReg) const
{
RValuePtr rvalue = Utils::tryCast<RValue>(getCondition(), "condition of switch case must be an rvalue");
if (!rvalue->isConstant()) { throw "condition of switch case must be a constant"; }

int caseConstant = rvalue->evalConst();
instrs.push_back(Instr("li", destReg, std::to_string(caseConstant)));//switch case returned through destReg
}
17 changes: 17 additions & 0 deletions src/ast/conditions/switch/switchDefault.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include "switchDefault.hpp"
#include "integerLiteral.hpp"

SwitchDefault::SwitchDefault(StatementPtr scopeBlock) : SwitchCase(new IntegerLiteral(1), scopeBlock)
{

}

void SwitchDefault::printC(std::ostream &os) const
{
os << "default: " << getScopeBlock();
}

void SwitchDefault::generateIL(std::vector<Instr> &instrs, ILContext &context, std::string destReg) const
{
//do nothing - there is no constant to evaluate and scope block generated from switch statement loop
}
95 changes: 95 additions & 0 deletions src/ast/conditions/switch/switchStatement.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#include "switchStatement.hpp"
#include "switchCase.hpp"
#include "switchDefault.hpp"

SwitchStatement::SwitchStatement(StatementPtr caseExpr, StatementPtr switchBlock)
{
branches.push_back(caseExpr);
branches.push_back(switchBlock);
}

StatementPtr SwitchStatement::getCase() const
{
return branches[0];
}
StatementPtr SwitchStatement::getSwitchBlock() const
{
return branches[1];
}
void SwitchStatement::printC(std::ostream &os) const
{
os << "switch (" << getCase() << ")" << getSwitchBlock(); //getSwitchBlock is a regular scope block
}

void SwitchStatement::generateIL(std::vector<Instr> &instrs, ILContext &context, std::string destReg) const
{
ScopeBlockPtr switchBlock = Utils::tryCast<ScopeBlock>(getSwitchBlock(), "switch block must be a scope block"); //just to get access to branches
std::vector<StatementPtr> switchBlockBranches = switchBlock->getBranches();
std::string switchEnd_lb = context.makeLabelName("switchEnd"); //the a in switch (a)
context.pushLoopLabels("NULL", switchEnd_lb);

//we could set up labels and scope blocks first, the branch past all that, then beq back...nah would mess up at the end.

//first set up beq's for switch cases
//keep track of labels being created, maybe ith a map of nodeid : label ?
std::vector<std::string> labels;
Instr branchToDefaultInstr;
bool hasDefault = false;
for (size_t i = 0; i < switchBlockBranches.size(); i++)
{
try
{ //is a switch case (or default)
SwitchCasePtr switchCase = Utils::tryCast<SwitchCase>(switchBlockBranches[i], "node is not a switch case");
std::string switchCaseReg = context.makeName("switchCase"); //the a in switch (a)
std::string case_lb = context.makeLabelName("case_lb");

try
{ //is default
Utils::tryCast<SwitchDefault>(switchBlockBranches[i], "node is not a default class");
hasDefault = true;
branchToDefaultInstr = Instr("b", case_lb);
}
catch (std::string)
{ //is not default
getCase()->generateIL(instrs, context, switchCaseReg);
switchCase->generateIL(instrs, context, "$t0"); //switch case generateIL just returns the condition constant
instrs.push_back(Instr("beq", case_lb, switchCaseReg, "$t0"));
}
labels.push_back(case_lb); //even if it's from default, it should stay in place as if there is no break it can continue executing the other lines
}
catch (std::string)
{ //not a switch case or default
}
}
if (hasDefault)
{
instrs.push_back(branchToDefaultInstr);
}
instrs.push_back(Instr("b", switchEnd_lb));

//now set up the branch labels with the corresponding block IL
int labelIndex = 0;
bool deadCode = true;
for (size_t i = 0; i < switchBlockBranches.size(); i++)
{
//if there is corresponding label for node, make label
try
{ //is a switch case or default
SwitchCasePtr switchCase = Utils::tryCast<SwitchCase>(switchBlockBranches[i], "node is not a switch case");
deadCode = false;
std::string label = labels[labelIndex++];
instrs.push_back(Instr::makeLabel(label));
switchCase->getScopeBlock()->generateIL(instrs, context, destReg);
//need to somehow store the label for later us
}
catch (std::string)
{ //not a switch case or default
if (!deadCode)
{
switchBlockBranches[i]->generateIL(instrs, context, destReg);
}
}
}
instrs.push_back(Instr::makeLabel(switchEnd_lb));
context.popLoopLabels();
}
4 changes: 2 additions & 2 deletions src/ast/keywords/continueKeyword.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ void ContinueKeyword::printC(std::ostream &os) const
void ContinueKeyword::generateIL(std::vector<Instr> &instrs, ILContext &context, std::string destReg) const
{
//need to jump to label of begining of function, which can be found in context
std::string endLoopLabel = std::get<0>(context.getLastLoopLabel());
instrs.push_back(Instr("b", endLoopLabel, "", "", {"#continue"}));
std::string startLoopLabel = std::get<0>(context.getLastLoopLabel());
instrs.push_back(Instr("b", startLoopLabel, "", "", {"#continue"}));
}
10 changes: 5 additions & 5 deletions src/c_parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
%type <expr> PARAMETER_DECLARATION INIT_DECLARATOR


%type <expr> TYPE_NAME ABSTRACT_DECLARATOR DIRECT_ABSTRACT_DECLARATOR STATEMENT COMPOUND_STATEMENT
%type <expr> TYPE_NAME ABSTRACT_DECLARATOR DIRECT_ABSTRACT_DECLARATOR STATEMENT COMPOUND_STATEMENT LABELED_STATEMENT
%type <expr> EXPRESSION_STATEMENT SELECTION_STATEMENT ITERATION_STATEMENT JUMP_STATEMENT EXTERNAL_DECLARATION FUNCTION_DEFINITION

%type <exprList> STATEMENT_LIST PARAMETER_LIST TRANSLATION_UNIT DECLARATION_LIST ARGUMENT_EXPRESSION_LIST IDENTIFIER_LIST
Expand Down Expand Up @@ -452,9 +452,9 @@ STATEMENT

//Switch statements
LABELED_STATEMENT
: T_IDENTIFIER T_COLON STATEMENT
| T_CASE CONSTANT_EXPRESSION T_COLON STATEMENT
| T_DEFAULT T_COLON STATEMENT
//: T_IDENTIFIER T_COLON STATEMENT { $$ = new SwitchCase($1, $3); }
: T_CASE CONSTANT_EXPRESSION T_COLON STATEMENT { $$ = new SwitchCase($2, $4); }
| T_DEFAULT T_COLON STATEMENT { $$ = new SwitchDefault($3); }
;

//Scope stuff
Expand Down Expand Up @@ -493,7 +493,7 @@ EXPRESSION_STATEMENT
SELECTION_STATEMENT
: T_IF T_LBRACKET EXPRESSION T_RBRACKET STATEMENT { $$ = new IfElseStatement($3, $5, new ScopeBlock()); }
| T_IF T_LBRACKET EXPRESSION T_RBRACKET STATEMENT T_ELSE STATEMENT { $$ = new IfElseStatement($3, $5, $7); }
| T_SWITCH T_LBRACKET EXPRESSION T_RBRACKET STATEMENT
| T_SWITCH T_LBRACKET EXPRESSION T_RBRACKET STATEMENT { $$ = new SwitchStatement($3, $5); }
;

//Loops - while,do,for
Expand Down
6 changes: 6 additions & 0 deletions src/codegen/ILtoMIPS/beq.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include "il2mips.hpp"

void IL2MIPS::beq(Instr instr, MIPSContext &context)
{
context.addBranchInstr(Instr("beq", instr.input1, instr.input2, instr.dest), instr.label);
}
6 changes: 6 additions & 0 deletions src/codegen/ILtoMIPS/bne.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include "il2mips.hpp"

void IL2MIPS::bne(Instr instr, MIPSContext &context)
{
context.addBranchInstr(Instr("bne", instr.input1, instr.input2, instr.dest), instr.label);
}
2 changes: 2 additions & 0 deletions src/codegen/il2mips.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,10 @@ void IL2MIPS::convertInstr(Instr &instr, MIPSContext &context)
else if (instr.opcode == "gt") { IL2MIPS::gt(instr, context); }
else if (instr.opcode == "gte") { IL2MIPS::gte(instr, context); }
else if (instr.opcode == "b") { IL2MIPS::b(instr, context); }
else if (instr.opcode == "beq") { IL2MIPS::beq(instr, context); }
else if (instr.opcode == "bez") { IL2MIPS::bez(instr, context); }
else if (instr.opcode == "bgz") { IL2MIPS::bgz(instr, context); }
else if (instr.opcode == "bne") { IL2MIPS::bne(instr, context); }
else if (instr.opcode == "bnez") { IL2MIPS::bnez(instr, context); }
else if (instr.opcode == "xor") { IL2MIPS::xorM(instr, context); }
else if (instr.opcode == "and") { IL2MIPS::andM(instr, context); }
Expand Down
Loading

0 comments on commit aaadef1

Please sign in to comment.