Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Break & continue statements #25

Merged
merged 11 commits into from
Aug 9, 2021
14 changes: 14 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,20 @@ updates:
timezone: Europe/Berlin
open-pull-requests-limit: 15
target-branch: main
reviewers:
- chillibits/compiler-team
assignees:
- chillibits/compiler-team

# Dockerfile
- package-ecosystem: docker
directory: /
schedule:
interval: daily
time: "04:00"
timezone: Europe/Berlin
open-pull-requests-limit: 15
target-branch: main
reviewers:
- chillibits/compiler-team
assignees:
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
FROM alpine:3.14.0
FROM alpine:3.14.1
WORKDIR /spice/out

ENV TERM="xterm-256color"
ENV SPICE_DOCKERIZED=1

ARG COMPILER_PATH=linux-amd64

RUN apk update && apk add --no-cache libc6-compat libstdc++ libncurses5 && rm -rf /var/cache/apk/*
RUN apk update && apk add --no-cache alpine-sdk libncurses5 && rm -rf /var/cache/apk/*
RUN ln -s /lib64/ld-linux-x86-64.so.2 /lib/ld-linux-x86-64.so.2

COPY spice /usr/bin/spice
Expand Down
2 changes: 1 addition & 1 deletion compiler/.run/Spice_run.run.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Spice_run" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="&quot;../../../media/fibonacci.spice&quot; &quot;&quot; &quot;output.o&quot; &quot;true&quot;" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Spice" TARGET_NAME="Spice_run" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="Spice" RUN_TARGET_NAME="Spice_run">
<configuration default="false" name="Spice_run" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="&quot;../../../media/test.spice&quot; &quot;&quot; &quot;output.o&quot; &quot;true&quot;" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" PASS_PARENT_ENVS_2="true" PROJECT_NAME="Spice" TARGET_NAME="Spice_run" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="Spice" RUN_TARGET_NAME="Spice_run">
<envs>
<env name="WITH_TESTS" value="OFF" />
</envs>
Expand Down
217 changes: 153 additions & 64 deletions compiler/src/analyzer/AnalyzerVisitor.cpp

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions compiler/src/analyzer/AnalyzerVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@ class AnalyzerVisitor : public SpiceBaseVisitor {
antlrcpp::Any visitFunctionDef(SpiceParser::FunctionDefContext* ctx) override;
antlrcpp::Any visitProcedureDef(SpiceParser::ProcedureDefContext* ctx) override;
antlrcpp::Any visitForLoop(SpiceParser::ForLoopContext* ctx) override;
/*antlrcpp::Any visitForeachLoop(SpiceParser::ForeachLoopContext* ctx) override;*/
antlrcpp::Any visitWhileLoop(SpiceParser::WhileLoopContext* ctx) override;
antlrcpp::Any visitIfStmt(SpiceParser::IfStmtContext* ctx) override;
antlrcpp::Any visitParamLstDef(SpiceParser::ParamLstDefContext *ctx) override;
antlrcpp::Any visitDeclStmt(SpiceParser::DeclStmtContext* ctx) override;
antlrcpp::Any visitFunctionCall(SpiceParser::FunctionCallContext* ctx) override;
antlrcpp::Any visitImportStmt(SpiceParser::ImportStmtContext* ctx) override;
antlrcpp::Any visitReturnStmt(SpiceParser::ReturnStmtContext* ctx) override;
antlrcpp::Any visitBreakStmt(SpiceParser::BreakStmtContext* ctx) override;
antlrcpp::Any visitContinueStmt(SpiceParser::ContinueStmtContext* ctx) override;
antlrcpp::Any visitPrintfStmt(SpiceParser::PrintfStmtContext* ctx) override;
antlrcpp::Any visitAssignment(SpiceParser::AssignmentContext* ctx) override;
antlrcpp::Any visitTernary(SpiceParser::TernaryContext* ctx) override;
Expand All @@ -39,13 +40,13 @@ class AnalyzerVisitor : public SpiceBaseVisitor {
antlrcpp::Any visitMultiplicativeExpr(SpiceParser::MultiplicativeExprContext* ctx) override;
antlrcpp::Any visitPrefixUnary(SpiceParser::PrefixUnaryContext* ctx) override;
antlrcpp::Any visitPostfixUnary(SpiceParser::PostfixUnaryContext* ctx) override;
antlrcpp::Any visitAtomicExpr(SpiceParser::AtomicExprContext* ctx) override;
antlrcpp::Any visitValue(SpiceParser::ValueContext* ctx) override;
private:
// Members
SymbolTable* currentScope = new SymbolTable(nullptr);
bool parameterMode = false;
bool hasMainFunction = false;
int nestedLoopCounter = 0;

// Private functions
static SymbolType getSymbolTypeFromDataType(SpiceParser::DataTypeContext*);
Expand Down
34 changes: 25 additions & 9 deletions compiler/src/analyzer/SymbolTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,6 @@ bool SymbolTable::hasChild(const std::string& scopeId) {
return children.find(scopeId) != children.end();
}

std::string SymbolTable::toString() {
std::string symbolsString, childrenString;
for (auto& symbol : symbols)
symbolsString.append("(" + symbol.second.toString() + ")\n");
for (auto& child : children)
childrenString.append(child.first + ": " + child.second.toString() + "\n");
return "SymbolTable(\n" + symbolsString + ") {\n" + childrenString + "}";
}

void SymbolTable::pushSignature(const FunctionSignature& signature) {
functionSignatures.push(signature);
}
Expand All @@ -79,3 +70,28 @@ FunctionSignature SymbolTable::popSignature() {
functionSignatures.pop();
return signature;
}

llvm::BasicBlock* SymbolTable::getContinueBlock() const {
return continueBlock;
}

void SymbolTable::setContinueBlock(llvm::BasicBlock* block) {
continueBlock = block;
}

llvm::BasicBlock* SymbolTable::getBreakBlock() const {
return breakBlock;
}

void SymbolTable::setBreakBlock(llvm::BasicBlock* block) {
breakBlock = block;
}

std::string SymbolTable::toString() {
std::string symbolsString, childrenString;
for (auto& symbol : symbols)
symbolsString.append("(" + symbol.second.toString() + ")\n");
for (auto& child : children)
childrenString.append(child.first + ": " + child.second.toString() + "\n");
return "SymbolTable(\n" + symbolsString + ") {\n" + childrenString + "}";
}
7 changes: 7 additions & 0 deletions compiler/src/analyzer/SymbolTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <vector>
#include <queue>
#include <util/FunctionSignature.h>
#include <llvm/IR/BasicBlock.h>
#include "SymbolTableEntry.h"

class SymbolTable {
Expand All @@ -26,6 +27,10 @@ class SymbolTable {
bool hasChild(const std::string&);
void pushSignature(const FunctionSignature&);
FunctionSignature popSignature();
llvm::BasicBlock* getContinueBlock() const;
void setContinueBlock(llvm::BasicBlock*);
llvm::BasicBlock* getBreakBlock() const;
void setBreakBlock(llvm::BasicBlock*);
std::string toString();
private:
// Members
Expand All @@ -34,4 +39,6 @@ class SymbolTable {
std::map<std::string, SymbolTableEntry> symbols;
std::vector<std::string> paramNames;
std::queue<FunctionSignature> functionSignatures;
llvm::BasicBlock* continueBlock = nullptr;
llvm::BasicBlock* breakBlock = nullptr;
};
3 changes: 1 addition & 2 deletions compiler/src/analyzer/SymbolTableEntry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ void SymbolTableEntry::updateState(SymbolState newState) {
if (state == INITIALIZED && isConstant)
throw SemanticError(REASSIGN_CONST_VARIABLE, "Not re-assignable variable '" + name + "'");
if (newState == INITIALIZED && type == TYPE_DYN)
throw SemanticError(OPERATOR_WRONG_DATA_TYPE,
"Internal compiler error: could not determine type of variable '" + name + "'");
throw std::runtime_error("Internal compiler error: could not determine type of variable '" + name + "'");
state = newState;
}

Expand Down
23 changes: 23 additions & 0 deletions compiler/src/exception/IRError.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,29 @@

#include "IRError.h"

IRError::IRError(const antlr4::Token& token, IRErrorType type, const std::string& message) {
auto codeLoc = std::to_string(token.getLine()) + ":" + std::to_string(token.getCharPositionInLine() + 1);
errorMessage = "Internal compiler error at " + codeLoc + " - " + getMessagePrefix(type) + ": " + message;
}

IRError::IRError(IRErrorType type, const std::string& message) {
errorMessage = "Internal compiler error - " + getMessagePrefix(type) + ": " + message;
}

const char *IRError::what() const noexcept {
return errorMessage.c_str();
}

std::string IRError::getMessagePrefix(IRErrorType type) {
switch (type) {
case TARGET_NOT_AVAILABLE: return "Selected target not available";
case CANT_OPEN_OUTPUT_FILE: return "Could not open output file";
case WRONG_TYPE: return "Wrong type of output file";
case UNEXPECTED_DYN_TYPE: return "Unexpected type of dyn. Symbol table incomplete";
case PRINTF_NULL_TYPE: return "Printf has null type";
case VARIABLE_NOT_FOUND: return "Variable not found";
case INVALID_FUNCTION: return "Invalid function";
case INVALID_MODULE: return "Invalid module";
}
return "Unknown error";
}
34 changes: 4 additions & 30 deletions compiler/src/exception/IRError.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <exception>
#include <string>
#include <Token.h>

enum IRErrorType {
TARGET_NOT_AVAILABLE,
Expand All @@ -19,40 +20,13 @@ enum IRErrorType {
class IRError : public std::exception {
public:
// Constructors
explicit IRError(IRErrorType type, const std::string& message) {
std::string messagePrefix;
switch (type) {
case TARGET_NOT_AVAILABLE:
messagePrefix = "Selected target not available";
break;
case CANT_OPEN_OUTPUT_FILE:
messagePrefix = "Could not open output file";
break;
case WRONG_TYPE:
messagePrefix = "Wrong type of output file";
break;
case UNEXPECTED_DYN_TYPE:
messagePrefix = "Unexpected type of dyn. Symbol table incomplete";
break;
case PRINTF_NULL_TYPE:
messagePrefix = "Printf has null type";
break;
case VARIABLE_NOT_FOUND:
messagePrefix = "Variable not found";
break;
case INVALID_FUNCTION:
messagePrefix = "Invalid function";
break;
case INVALID_MODULE:
messagePrefix = "Invalid module";
break;
}
errorMessage = "Internal compiler error - " + messagePrefix + ": " + message;
}
explicit IRError(const antlr4::Token&, IRErrorType, const std::string&);
explicit IRError(IRErrorType, const std::string&);

// Public methods
const char * what() const noexcept override;
private:
// Members
std::string errorMessage {};
static std::string getMessagePrefix(IRErrorType);
};
30 changes: 29 additions & 1 deletion compiler/src/exception/SemanticError.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,34 @@

#include "SemanticError.h"

SemanticError::SemanticError(const antlr4::Token& token, SemanticErrorType type, const std::string &message) {
auto codeLoc = std::to_string(token.getLine()) + ":" + std::to_string(token.getCharPositionInLine() + 1);
errorMessage = "Semantic error at " + codeLoc + ": " + getMessagePrefix(type) + ": " + message;
}

SemanticError::SemanticError(SemanticErrorType type, const std::string &message) {
errorMessage = "Semantic error - " + getMessagePrefix(type) + ": " + message;
}

const char *SemanticError::what() const noexcept {
return errorMessage.c_str();
}
}

std::string SemanticError::getMessagePrefix(SemanticErrorType type) {
switch (type) {
case REFERENCED_UNDEFINED_FUNCTION_OR_PROCEDURE: return "Referenced undefined function";
case REFERENCED_UNDEFINED_VARIABLE: return "Referenced undefined variable";
case VARIABLE_DECLARED_TWICE: return "Multiple declarations of the same variable";
case FUNCTION_WITHOUT_RETURN_STMT: return "Missing return statement";
case RETURN_STMT_WITHOUT_FUNCTION: return "Return statement outside function";
case OPERATOR_WRONG_DATA_TYPE: return "Wrong data type for operator";
case REASSIGN_CONST_VARIABLE: return "Cannot re-assign constant variable";
case CONDITION_MUST_BE_BOOL: return "Condition must be bool";
case MISSING_MAIN_FUNCTION: return "Spice programs must contain a main function";
case FCT_PARAM_IS_TYPE_DYN: return "Parameter type dyn not valid in function/procedure definition without default value";
case INVALID_BREAK_NUMBER: return "Invalid number of break calls";
case INVALID_CONTINUE_NUMBER: return "Invalid number of continue calls";
case PRINTF_TYPE_ERROR: return "Types of printf call not matching";
}
return "Unknown error";
}
44 changes: 8 additions & 36 deletions compiler/src/exception/SemanticError.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#include <exception>
#include <string>
#include <TokenSource.h>
#include <Token.h>

enum SemanticErrorType {
REFERENCED_UNDEFINED_FUNCTION_OR_PROCEDURE,
Expand All @@ -16,51 +18,21 @@ enum SemanticErrorType {
CONDITION_MUST_BE_BOOL,
MISSING_MAIN_FUNCTION,
FCT_PARAM_IS_TYPE_DYN,
INVALID_BREAK_NUMBER,
INVALID_CONTINUE_NUMBER,
PRINTF_TYPE_ERROR
};

class SemanticError : public std::exception {
public:
// Constructors
explicit SemanticError(SemanticErrorType type, const std::string& message) {
std::string messagePrefix;
switch (type) {
case REFERENCED_UNDEFINED_FUNCTION_OR_PROCEDURE:
messagePrefix = "Referenced undefined function";
break;
case REFERENCED_UNDEFINED_VARIABLE:
messagePrefix = "Referenced undefined variable";
break;
case VARIABLE_DECLARED_TWICE:
messagePrefix = "Multiple declarations of the same variable";
break;
case FUNCTION_WITHOUT_RETURN_STMT:
messagePrefix = "Missing return statement";
break;
case RETURN_STMT_WITHOUT_FUNCTION:
messagePrefix = "Return statement outside function";
break;
case OPERATOR_WRONG_DATA_TYPE:
messagePrefix = "Wrong data type for operator";
break;
case REASSIGN_CONST_VARIABLE:
messagePrefix = "Cannot re-assign constant variable";
break;
case CONDITION_MUST_BE_BOOL:
messagePrefix = "Condition must be bool";
break;
case MISSING_MAIN_FUNCTION:
messagePrefix = "Spice programs must contain a main function";
break;
case FCT_PARAM_IS_TYPE_DYN:
messagePrefix = "Parameter type dyn not valid in function/procedure definition without default value";
break;
}
errorMessage = messagePrefix + ": " + message;
}
explicit SemanticError(const antlr4::Token& token, SemanticErrorType type, const std::string& message);
explicit SemanticError(SemanticErrorType type, const std::string& message);

// Public methods
const char * what() const noexcept override;
private:
// Members
std::string errorMessage {};
static std::string getMessagePrefix(SemanticErrorType);
};
Loading