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

Generator Visitor #6

Merged
merged 19 commits into from
Jul 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,23 @@ jobs:
- name: Checkout
uses: actions/checkout@v2

- name: Cache LLVM
id: cache-llvm
uses: actions/cache@v2
with:
path: /home/runner/work/spice/llvm
key: llvm-12-0-1

- name: Setup LLVM
if: steps.cache-llvm.outputs.cache-hit != 'true'
run: |
cd ..
git clone https://github.com/llvm/llvm-project llvm
mkdir ./llvm/build
cd ./llvm/build
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_CXX_FLAGS_RELEASE="-O2" -G "Unix Makefiles" ../llvm
cmake --build .

- name: Download Libs
run: |
mkdir -p ./compiler/lib
Expand All @@ -23,8 +40,10 @@ jobs:
git clone https://github.com/antlr/antlr4.git

- name: Build
env:
LLVM_DIR: /home/runner/work/spice/llvm/build/lib/cmake/llvm
run: |
mkdir bin
cd bin
cmake -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" -DWITH_TESTS=ON ../compiler
cmake --build . --target Spice_run -- -j 6
cmake --build . --target Spice_run -- -j 6
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,15 @@ The Spice grammar can be found [here](./compiler/src/grammar/Spice.g4) as a ANTL
- [x] Additive operators are only applied to some type combinations
- [x] Multiplicative operators are only applied to some type combinations
- [x] Prefix/postfix unary operators are only applied to integers
- [ ] Program contains main function
- [ ] `++` and `--` are only applied on identifiers

## Special language features
- Something like `"Test" * 3` is valid and will evaluate to `"TestTestTest"`
- Alternatively to the return statement in a function, you can also assign variable `result` with a value, which was automatically declared by the function header
- Unary minus has to be applied without a space between (e.g.: `-3.4`) and binary minus has to be applied with a space beween (e.g.: `n - 5`)
- Default values of function/procedure parameters are possible e.g.: `f<int> test(int param = 2) {}`
- Default values of function/procedure parameters are possible e.g.: `f<int> test(int param = 2) {}`

## CMake instructions for building
`cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DCMAKE_CXX_FLAGS_RELEASE="-O2" -G "CodeBlocks - MinGW Makefiles" ../llvm`
`cmake --build .`
2 changes: 1 addition & 1 deletion build.bat
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
mkdir bin 2> NUL
cd bin

cmake -DCMAKE_BUILD_TYPE=Release -G "CodeBlocks - MinGW Makefiles" ../compiler
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -G "CodeBlocks - MinGW Makefiles" ../compiler
cmake --build . --target Spice_run -- -j 6

move src\Spice_run.exe spicec.exe
Expand Down
7 changes: 7 additions & 0 deletions compiler/.run/Spice_run.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Spice_run" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS="&quot;../../../media/test.spice&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">
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
</method>
</configuration>
</component>
38 changes: 36 additions & 2 deletions compiler/src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
set(BINARY ${CMAKE_PROJECT_NAME})
set(LLVM_DIR $ENV{LLVM_DIR})

LIST(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)

Expand All @@ -9,6 +10,15 @@ set(ANTLR_EXECUTABLE ${CMAKE_CURRENT_SOURCE_DIR}/thirdparty/antlr/antlr-4.9.2-co
find_package(ANTLR REQUIRED)
antlr_target(Spice ${CMAKE_CURRENT_SOURCE_DIR}/grammar/Spice.g4 VISITOR)

find_package(LLVM REQUIRED CONFIG)

message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")

include_directories(${LLVM_INCLUDE_DIRS})
separate_arguments(LLVM_DEFINITIONS_LIST NATIVE_COMMAND ${LLVM_DEFINITIONS})
add_definitions(${LLVM_DEFINITIONS_LIST})

set(SOURCES
main.cpp
analyzer/AnalyzerVisitor.cpp
Expand All @@ -17,14 +27,38 @@ set(SOURCES
analyzer/SymbolTable.h
analyzer/SymbolTableEntry.cpp
analyzer/SymbolTableEntry.h
generator/GeneratorVisitor.cpp
generator/GeneratorVisitor.h
exception/SemanticError.cpp
exception/SemanticError.h)
exception/SemanticError.h
exception/IRError.cpp
exception/IRError.h)

add_executable(${BINARY}_run ${SOURCES} ${ANTLR_Spice_CXX_OUTPUTS})

llvm_map_components_to_libnames(LLVM_LIBS aarch64asmparser aarch64codegen aarch64desc aarch64disassembler
aarch64info aarch64utils amdgpuasmparser amdgpucodegen amdgpudesc amdgpudisassembler
amdgpuinfo amdgpuutils armasmparser armcodegen armdesc armdisassembler arminfo armutils asmparser
asmprinter avrasmparser avrcodegen avrdesc avrdisassembler avrinfo
bpfasmparser bpfcodegen bpfdesc bpfdisassembler bpfinfo codegen core
hexagonasmparser hexagoncodegen hexagondesc hexagondisassembler hexagoninfo
irreader lanaiasmparser lanaicodegen lanaidesc lanaidisassembler lanaiinfo
mipsasmparser mipscodegen mipsdesc mipsdisassembler mipsinfo
mirparser msp430asmparser msp430codegen msp430desc msp430disassembler msp430info
nvptxcodegen nvptxdesc nvptxinfo
powerpcasmparser powerpccodegen powerpcdesc powerpcdisassembler powerpcinfo riscvasmparser
riscvcodegen riscvdesc riscvdisassembler riscvinfo sparcasmparser
sparccodegen sparcdesc sparcdisassembler sparcinfo support systemzasmparser systemzcodegen
systemzdesc systemzdisassembler systemzinfo
webassemblyasmparser webassemblycodegen webassemblydesc webassemblydisassembler webassemblyinfo
webassemblyutils x86asmparser x86codegen x86desc x86disassembler x86info xcorecodegen xcoredesc
xcoredisassembler xcoreinfo)

include_directories(${ANTLR4CPP_INCLUDE_DIRS})
include_directories(${ANTLR_Spice_OUTPUT_DIR})
include_directories(../lib/antlr4/runtime/Cpp/runtime/src)

target_link_libraries(${BINARY}_run antlr4_static)
add_library(${BINARY}_lib STATIC ${SOURCES} exception/SemanticError.cpp exception/SemanticError.h analyzer/SymbolTableEntry.cpp analyzer/SymbolTableEntry.h)
target_link_libraries(${BINARY}_run ${LLVM_LIBS})

add_library(${BINARY}_lib STATIC ${SOURCES} ${ANTLR_Spice_CXX_OUTPUTS})
47 changes: 38 additions & 9 deletions compiler/src/analyzer/AnalyzerVisitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,29 @@ antlrcpp::Any AnalyzerVisitor::visitEntry(SpiceParser::EntryContext *ctx) {
return currentScope;
}

antlrcpp::Any AnalyzerVisitor::visitMainFunctionDef(SpiceParser::MainFunctionDefContext *ctx) {
// Insert function name into the root symbol table
currentScope->insert("main", TYPE_FUNCTION, INITIALIZED, true, false);
// Create a new scope
std::string scopeId = "f:main";
currentScope = currentScope->createChildBlock(scopeId);
// Declare variable for the return value
SymbolType returnType = TYPE_INT;
currentScope->insert(RETURN_VARIABLE_NAME, returnType, DECLARED, false, false);
// Visit parameters
parameterMode = true;
if (ctx->paramLstDef()) visit(ctx->paramLstDef());
parameterMode = false;
// Visit statements in new scope
visit(ctx->stmtLst());
// Check if return variable is now initialized
if (currentScope->lookup(RETURN_VARIABLE_NAME)->getState() == DECLARED)
throw SemanticError(FUNCTION_WITHOUT_RETURN_STMT, "Function without return statement");
// Return to old scope
currentScope = currentScope->getParent();
return returnType;
}

antlrcpp::Any AnalyzerVisitor::visitFunctionDef(SpiceParser::FunctionDefContext *ctx) {
// Insert function name into the root symbol table
std::string functionName = ctx->IDENTIFIER()->toString();
Expand Down Expand Up @@ -146,15 +169,17 @@ antlrcpp::Any AnalyzerVisitor::visitFunctionCall(SpiceParser::FunctionCallContex
SymbolTable* symbolTable = rootTable->getChild(scopeId);
std::vector<std::string> paramNames = symbolTable->getParamNames();
// Check if types match for parameter list
for (int i = 0; i < ctx->paramLstCall()->assignment().size(); i++) {
SymbolType type = visit(ctx->paramLstCall()->assignment()[i]).as<SymbolType>();
SymbolTableEntry* param = symbolTable->lookup(paramNames[i]);
if (!param)
throw SemanticError(REFERENCED_UNDEFINED_VARIABLE,
"Parameter '" + paramNames[i] + "' was not found in declaration");
if (type != param->getType())
throw SemanticError(PARAMETER_TYPES_DO_NOT_MATCH,
"Type of parameter '" + paramNames[i] + "' does not match the declaration");
if (ctx->paramLstCall()) {
for (int i = 0; i < ctx->paramLstCall()->assignment().size(); i++) {
SymbolType type = visit(ctx->paramLstCall()->assignment()[i]).as<SymbolType>();
SymbolTableEntry* param = symbolTable->lookup(paramNames[i]);
if (!param)
throw SemanticError(REFERENCED_UNDEFINED_VARIABLE,
"Parameter '" + paramNames[i] + "' was not found in declaration");
if (type != param->getType())
throw SemanticError(PARAMETER_TYPES_DO_NOT_MATCH,
"Type of parameter '" + paramNames[i] + "' does not match the declaration");
}
}
return symbolTable->lookup(RETURN_VARIABLE_NAME)->getType();
}
Expand All @@ -180,6 +205,10 @@ antlrcpp::Any AnalyzerVisitor::visitReturnStmt(SpiceParser::ReturnStmtContext *c
return returnType;
}

antlrcpp::Any AnalyzerVisitor::visitPrintfStmt(SpiceParser::PrintfStmtContext *ctx) {
return SpiceBaseVisitor::visitPrintfStmt(ctx);
}

antlrcpp::Any AnalyzerVisitor::visitAssignment(SpiceParser::AssignmentContext *ctx) {
// Check if there is an assign operator applied
if (ctx->children.size() > 1) {
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/analyzer/AnalyzerVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class AnalyzerVisitor : public SpiceBaseVisitor {
public:
// Public methods
antlrcpp::Any visitEntry(SpiceParser::EntryContext *ctx) override;
antlrcpp::Any visitMainFunctionDef(SpiceParser::MainFunctionDefContext *ctx) override;
antlrcpp::Any visitFunctionDef(SpiceParser::FunctionDefContext *ctx) override;
antlrcpp::Any visitProcedureDef(SpiceParser::ProcedureDefContext *ctx) override;
antlrcpp::Any visitForLoop(SpiceParser::ForLoopContext *ctx) override;
Expand All @@ -23,6 +24,7 @@ class AnalyzerVisitor : public SpiceBaseVisitor {
antlrcpp::Any visitFunctionCall(SpiceParser::FunctionCallContext *ctx) override;
antlrcpp::Any visitImportStmt(SpiceParser::ImportStmtContext *ctx) override;
antlrcpp::Any visitReturnStmt(SpiceParser::ReturnStmtContext *ctx) override;
antlrcpp::Any visitPrintfStmt(SpiceParser::PrintfStmtContext *ctx) override;
antlrcpp::Any visitAssignment(SpiceParser::AssignmentContext *ctx) override;
antlrcpp::Any visitTernary(SpiceParser::TernaryContext *ctx) override;
antlrcpp::Any visitLogicalOrExpr(SpiceParser::LogicalOrExprContext *ctx) override;
Expand Down
7 changes: 7 additions & 0 deletions compiler/src/exception/IRError.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Copyright (c) 2021 ChilliBits. All rights reserved.

#include "IRError.h"

const char *IRError::what() const noexcept {
return errorMessage.c_str();
}
38 changes: 38 additions & 0 deletions compiler/src/exception/IRError.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) 2021 ChilliBits. All rights reserved.

#pragma once

#include <exception>
#include <string>

enum IRErrorType {
TARGET_NOT_AVAILABLE,
CANT_OPEN_OUTPUT_FILE,
WRONG_TYPE,
};

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;
}
errorMessage = messagePrefix + ": " + message;
}

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