Skip to content
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
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ project(bort)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

set(BORT_BUILD_TESTS OFF)
option(BORT_BUILD_TESTS "Enable testing (requires python3)")

include_directories(include)

Expand Down Expand Up @@ -106,5 +106,6 @@ target_link_libraries(${PROJECT_NAME} PRIVATE Boost::functional Boost::assert
Boost::stacktrace Boost::range)

if(${BORT_BUILD_TESTS})
message(STATUS "Testing enabled")
add_subdirectory(tests)
endif()
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@
**bort** is a cross-platform Small-C language cross compiler for RISC-V architecture.

## Global TODOs
- Global variables
- for-loops
- global variables
- goto
- switch
- compound assignment (`+=`, `*=`, ...)
- compound variable declaration (`int a = 5, b, c = d;`)
- testing

Expand Down
3 changes: 2 additions & 1 deletion dev.sh
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ fi
cmake -S . \
-B build \
-G Ninja \
-DBORT_BUILD_TESTS=ON \
-DCMAKE_CXX_COMPILER=clang++ \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_FLAGS="-fsanitize=address,undefined -Wall -Wextra -pedantic" \
Expand All @@ -46,5 +47,5 @@ cp -f build/compile_commands.json .
if [ $# -ne 0 ] && [ "$1" == "run" ]; then
echo -e "----------------------------------\n"
set -eux
./build/bort --dump-ast --emit-ir --dump-codegen-info -o - ./tests/corpus/arrays.c
./build/bort --dump-ast --emit-ir --dump-codegen-info -o - ./tests/corpus/loops.c
fi
2 changes: 2 additions & 0 deletions include/bort/AST/ASTNode.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ enum class NodeKind {
IfStmt,
WhileStmt,
ReturnStmt,
BreakStmt,
ContinueStmt,
ASTRoot,
NUM_NODES
};
Expand Down
3 changes: 3 additions & 0 deletions include/bort/AST/BinOpExpr.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ class BinOpExpr final : public ExpressionNode {
/// @todo bitwise operators
return m_Op == TokenKind::Plus || m_Op == TokenKind::Minus ||
m_Op == TokenKind::Star || m_Op == TokenKind::Div ||
m_Op == TokenKind::Mod || m_Op == TokenKind::LShift ||
m_Op == TokenKind::RShift || m_Op == TokenKind::Amp ||
m_Op == TokenKind::Pipe || m_Op == TokenKind::Xor ||
m_Op == TokenKind::Amp || m_Op == TokenKind::Pipe;
}
[[nodiscard]] constexpr auto isLogical() const -> bool {
Expand Down
16 changes: 16 additions & 0 deletions include/bort/AST/BreakStmt.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once
#include "bort/AST/ASTNode.hpp"

namespace bort::ast {

class BreakStmt final : public Statement {
private:
BreakStmt()
: Statement{ NodeKind::BreakStmt } {
}

public:
friend class ASTRoot;
};

} // namespace bort::ast
16 changes: 16 additions & 0 deletions include/bort/AST/ContinueStmt.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once
#include "bort/AST/ASTNode.hpp"

namespace bort::ast {

class ContinueStmt final : public Statement {
private:
ContinueStmt()
: Statement{ NodeKind::ContinueStmt } {
}

public:
friend class ASTRoot;
};

} // namespace bort::ast
4 changes: 4 additions & 0 deletions include/bort/AST/Visitors/ASTPrinter.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#pragma once
#include "bort/AST/BreakStmt.hpp"
#include "bort/AST/ContinueStmt.hpp"
#include "bort/AST/IndexationExpr.hpp"
#include "bort/AST/InitializerList.hpp"
#include "bort/AST/UnaryOpExpr.hpp"
Expand Down Expand Up @@ -32,6 +34,8 @@ class ASTPrinter : public StructureAwareASTVisitor {
void visit(const Ref<IfStmt>& ifStmtNode) override;
void visit(const Ref<WhileStmt>& whileStmtNode) override;
void visit(const Ref<ReturnStmt>& returnStmtNode) override;
void visit(const Ref<BreakStmt>& breakStmtNode) override;
void visit(const Ref<ContinueStmt>& continueStmtNode) override;
void visit(const Ref<FunctionCallExpr>& functionCallExpr) override;

void push();
Expand Down
8 changes: 8 additions & 0 deletions include/bort/AST/Visitors/ASTVisitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ class ExpressionStmt;
class IfStmt;
class WhileStmt;
class ReturnStmt;
class BreakStmt;
class ContinueStmt;

class ASTVisitorBase {
public:
Expand Down Expand Up @@ -80,6 +82,12 @@ class StructureAwareASTVisitor : public ASTVisitorBase {
virtual void visit(const Ref<CharExpr>& /* charNode */) {
// leaf
}
virtual void visit(const Ref<BreakStmt>& /* breakNode */) {
// leaf
}
virtual void visit(const Ref<ContinueStmt>& /* continueNode */) {
// leaf
}
virtual void visit(const Ref<VarDecl>& varDeclNode);
virtual void visit(const Ref<InitializerList>& initializerListNode);
virtual void visit(const Ref<IndexationExpr>& indexationExpr);
Expand Down
2 changes: 2 additions & 0 deletions include/bort/AST/Visitors/TypePropagationVisitor.hpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#pragma once
#include "bort/AST/ASTNode.hpp"
#include "bort/AST/BinOpExpr.hpp"
#include "bort/AST/IndexationExpr.hpp"
#include "bort/AST/UnaryOpExpr.hpp"
Expand Down Expand Up @@ -32,6 +33,7 @@ class TypePropagationVisitor : public StructureAwareASTVisitor {
void visit(const Ref<IndexationExpr>& indexationNode) override;
void visit(const Ref<VarDecl>& varDeclNode) override;

void assertLvalue(const Ref<Node>& node);
void promoteAssignmentOperands(const TypeRef& lhsTy, TypeRef& rhsTy,
const ASTDebugInfo& debugInfo);

Expand Down
10 changes: 10 additions & 0 deletions include/bort/AST/Visitors/Utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#include "bort/AST/ASTNode.hpp"
#include "bort/AST/BinOpExpr.hpp"
#include "bort/AST/BreakStmt.hpp"
#include "bort/AST/ContinueStmt.hpp"
#include "bort/AST/ExpressionStmt.hpp"
#include "bort/AST/FunctionCallExpr.hpp"
#include "bort/AST/FunctionDecl.hpp"
Expand Down Expand Up @@ -83,6 +85,14 @@ auto callHandler(const Ref<Node>& node, F&& visit) {
bort_assert_nomsg(dynCastRef<ReturnStmt>(node));
return visit(dynCastRef<ReturnStmt>(node));
break;
case NodeKind::BreakStmt:
bort_assert_nomsg(dynCastRef<BreakStmt>(node));
return visit(dynCastRef<BreakStmt>(node));
break;
case NodeKind::ContinueStmt:
bort_assert_nomsg(dynCastRef<ContinueStmt>(node));
return visit(dynCastRef<ContinueStmt>(node));
break;
case NodeKind::ASTRoot:
bort_assert_nomsg(dynCastRef<ASTRoot>(node));
return visit(dynCastRef<ASTRoot>(node));
Expand Down
10 changes: 10 additions & 0 deletions include/bort/Codegen/RISCVCodegen.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,16 @@ struct RVInstInfo final : public ir::Metadata {
std::string InstName;
};

struct RVOpAdditionalInfo final : public ir::Metadata {
explicit RVOpAdditionalInfo(bool isSingleOp)
: IsSingleOp{ isSingleOp } {
}

[[nodiscard]] auto toString() const -> std::string override;

bool IsSingleOp;
};

struct RARSMacroDefinitions final : public ir::Metadata {
[[nodiscard]] auto toString() const -> std::string override;

Expand Down
7 changes: 6 additions & 1 deletion include/bort/IR/IRCodegen.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#pragma once
#include "bort/AST/ASTNode.hpp"
#include "bort/AST/BinOpExpr.hpp"
#include "bort/AST/BreakStmt.hpp"
#include "bort/AST/ContinueStmt.hpp"
#include "bort/AST/FunctionCallExpr.hpp"
#include "bort/AST/IfStmt.hpp"
#include "bort/AST/IndexationExpr.hpp"
Expand Down Expand Up @@ -47,11 +49,14 @@ class IRCodegen {
auto visit(const Ref<ast::IfStmt>& ifStmtNode) -> ValueRef;
auto visit(const Ref<ast::WhileStmt>& whileStmtNode) -> ValueRef;
auto visit(const Ref<ast::ReturnStmt>& returnStmt) -> ValueRef;
auto visit(const Ref<ast::BreakStmt>& breakStmt) -> ValueRef;
auto visit(const Ref<ast::ContinueStmt>& continueStmt) -> ValueRef;
auto visit(const Ref<ast::FunctionCallExpr>& funcCallExpr) -> ValueRef;

auto genBranchFromCondition(const Ref<ast::ExpressionNode>& cond,
bool negate = false) -> Ref<BranchInst>;
auto genArrayPtr(const ValueRef& arr) -> std::pair<Ref<PointerType>, ValueRef>;
auto genArrayPtr(const ValueRef& arr)
-> std::pair<Ref<PointerType>, ValueRef>;

template <typename T>
requires std::is_base_of_v<Instruction, T>
Expand Down
5 changes: 5 additions & 0 deletions include/bort/IR/Metadata.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ class MDList {
return node;
}

template <MetadataClass T>
void remove() {
m_Registry.erase(typeid(T));
}

auto nodes() {
return std::views::values(m_Registry);
}
Expand Down
3 changes: 3 additions & 0 deletions include/bort/IR/OpInst.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ class OpInst final : public Instruction {
void setSrc2(ValueRef value) {
m_Operands[Src2Idx] = std::move(value);
}
void setOp(TokenKind op) {
m_Op = op;
}

static constexpr int Src1Idx{ 1 };
static constexpr int Src2Idx{ 2 };
Expand Down
5 changes: 5 additions & 0 deletions include/bort/IR/Value.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ class Value {
return m_MDList->get<T>();
}

template <MetadataClass T>
void removeMDNode() {
m_MDList->remove<T>();
}

template <MetadataClass T>
auto getMDNode() const -> const T* {
return m_MDList->get<T>();
Expand Down
18 changes: 17 additions & 1 deletion include/bort/Lex/Tokens.def
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,24 @@ PUNCT(Plus, "+")
PUNCT(Minus, "-")
PUNCT(Star, "*")
PUNCT(Div, "/")
PUNCT(Mod, "%")
PUNCT(Pipe, "|")
PUNCT(Xor, "^")
PUNCT(LShift, "<<")
PUNCT(RShift, ">>")
PUNCT(Not, "!")
PUNCT(Tilde, "~")
PUNCT(AmpAmp, "&&")
PUNCT(PipePipe, "||")
PUNCT(PlusAssign, "+=")
PUNCT(MinusAssign, "-=")
PUNCT(TimesAssign, "*=")
PUNCT(StarAssign, "*=")
PUNCT(DivAssign, "/=")
PUNCT(AmpAssign, "&=")
PUNCT(XorAssign, "^=")
PUNCT(PipeAssign, "|=")
PUNCT(LShiftAssign, "<<=")
PUNCT(RShiftAssign, ">>=")
PUNCT(Less, "<")
PUNCT(Greater, ">")
PUNCT(LessEqual, "<=")
Expand All @@ -54,7 +67,10 @@ KEYWORD(char)
KEYWORD(const)
KEYWORD(if)
KEYWORD(else)
KEYWORD(break)
KEYWORD(continue)
KEYWORD(while)
KEYWORD(for)
KEYWORD(return)
KEYWORD(sizeof)

Expand Down
45 changes: 28 additions & 17 deletions include/bort/Parse/Parser.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once
#include "bort/AST/ASTNode.hpp"
#include "bort/AST/BreakStmt.hpp"
#include "bort/AST/ContinueStmt.hpp"
#include "bort/AST/ExpressionNode.hpp"
#include "bort/AST/FunctionCallExpr.hpp"
#include "bort/AST/FunctionDecl.hpp"
Expand Down Expand Up @@ -46,42 +48,40 @@ class Parser {
/// parenExpr \n
/// -> '(' expression ')' \n
/// @todo type-casts -> '(' declspec ')'
auto parseParenExpr() -> Unique<ast::ExpressionNode>;
auto parseParenExpr() -> Ref<ast::ExpressionNode>;
/// identifier \n
/// -> identifier - variable \n
/// -> identifier '(' expr, ... ')' - function call \n
/// -> identifier indexationExpr \n
/// -> identifier ('++' | '--')
/// -> varExpr \n
/// -> functionCallExpr \n
/// -> identifier indexationExpr
auto parseIdentifierExpr() -> Unique<ast::ExpressionNode>;
/// value expression \n
/// -> number \n
/// -> parenExpr \n
/// -> sizeofExpr \n
/// -> unaryOpExpr \n
/// -> lvalue
auto parseValueExpression() -> Unique<ast::ExpressionNode>;
auto parseValueExpression() -> Ref<ast::ExpressionNode>;
/// sizeofExpr -> 'sizeof' (parenExpr | '(' declspec ')' )
auto parseSizeofExpr() -> Unique<ast::ExpressionNode>;
/// lvalue \n
/// -> identifier
auto tryParseLValue() -> std::optional<Unique<ast::ExpressionNode>>;
/// varExpr -> identifier
auto parseVarExpr() -> Unique<ast::ExpressionNode>;
/// unaryOpExpr -> unaryOp valueExpression
auto parseUnaryOpExpr() -> Unique<ast::ExpressionNode>;
/// expression
/// -> valueExpression (binOp valueExpression ...)
auto parseExpression() -> Unique<ast::ExpressionNode>;
/// -> valueExpression binOpRhs
auto parseExpression() -> Ref<ast::ExpressionNode>;
/// binOpRhs
/// -> bipOp valueExpression (binOpRhs ...)
auto parseBinOpRhs(Unique<ast::ExpressionNode> lhs,
auto parseBinOpRhs(Ref<ast::ExpressionNode> lhs,
int32_t prevPrecedence = 0)
-> Unique<ast::ExpressionNode>;
-> Ref<ast::ExpressionNode>;
/// declspec -> ( 'int' | 'void' | 'char' ) ('*'...)
/// @todo type qualifiers
auto parseDeclspec() -> TypeRef;
/// declaration -> declspec (varDecl | functionDecl)
/// declaration -> declspec (varDecl ';' | functionDecl)
auto parseDeclarationStatement() -> Ref<ast::Statement>;
/// varDecl -> declspec identifier ';'
/// @todo declspec (identifier ('=' expr)?, ...) ';'
/// varDecl -> declspec identifier initializerExpr?
/// @todo declspec (identifier ('=' expr)?, ...)
auto parseVarDecl(TypeRef type,
const Token& nameTok) -> Ref<ast::VarDecl>;
/// initializerList -> '{' number, ... '}' | stringLiteral
Expand All @@ -93,21 +93,31 @@ class Parser {
auto parseFunctionCallExpr(const Token& nameTok)
-> Unique<ast::FunctionCallExpr>;
/// indexationExpr -> nameTok '[' expr ']'
/// desugared into pointer arithmetic
auto parseIndexationExpr(const Token& nameTok)
-> Unique<ast::ExpressionNode>;
/// statement \n
/// -> expression ';' \n
/// -> declarationStatement ';' \n
/// -> block \n
/// -> ifStatement \n
/// -> whileStatement \n
/// -> returnStatement \n
/// -> breakStatement \n
/// -> continueStatement
auto parseStatement() -> Ref<ast::Statement>;
/// breakStatement -> 'break' ';'
auto parseBreakStatement() -> Ref<ast::BreakStmt>;
/// continueStatement -> 'continue' ';'
auto parseContinueStatement() -> Ref<ast::ContinueStmt>;
/// block
/// -> '{' statement... '}'
auto parseBlock() -> Unique<ast::Block>;
/// ifStatement -> 'if' parenExpr block (else block)?
auto parseIfStatement() -> Ref<ast::IfStmt>;
/// whileStatement -> 'while' parenExpr block
auto parseWhileStatement() -> Ref<ast::WhileStmt>;
/// forStatement -> 'for' '(' varDecl ';' expr? ';' expr? ')' block
auto parseForStatement() -> Ref<ast::Block>;
/// returnStatement -> 'return' (expr)? ';'
auto parseReturnStatement() -> Ref<ast::ReturnStmt>;

Expand Down Expand Up @@ -141,6 +151,7 @@ class Parser {
Ref<ast::ASTRoot> m_ASTRoot;
bool m_ASTInvalid{ false };
bool m_DiagnosticSilenced{ false };
bool m_InsideLoop{ false };
};

} // namespace bort
Loading