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

feat: add support for loops (while, do-while, for) #57

Merged
merged 9 commits into from
Feb 19, 2025
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
30 changes: 22 additions & 8 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
cmake_minimum_required(VERSION 3.14)
project(Scarlet LANGUAGES CXX)

if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose build type: Debug Release" FORCE)
endif()

if(CMAKE_BUILD_TYPE STREQUAL "Debug")
message(STATUS "Building in debug mode")
elseif(CMAKE_BUILD_TYPE STREQUAL "Release")
message(STATUS "Building in release mode")
else()
message(FATAL_ERROR "Invalid build type: ${CMAKE_BUILD_TYPE}\nValid build types are: Debug, Release")
endif()

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

Expand All @@ -26,7 +38,8 @@ function(set_basic_compile_options target)
-fno-strict-aliasing
-fwrapv
-fpie
-O3
$<$<CONFIG:Debug>:-g -O0 -DDEBUG>
$<$<CONFIG:Release>:-O3>
)
endfunction()

Expand All @@ -51,10 +64,11 @@ endif()

add_executable(scarlet ${SOURCES})
target_compile_options(scarlet PRIVATE
-O3
-Wall
-Wextra
-Werror
$<$<CONFIG:Debug>:-g -O0 -DDEBUG>
$<$<CONFIG:Release>:-O3>
)

add_dependencies(
Expand All @@ -79,17 +93,17 @@ target_compile_options(scarlet PRIVATE -O3)
add_custom_target(test-scarlet
DEPENDS scarlet
COMMAND echo "Running lexer test"
COMMAND ${CMAKE_SOURCE_DIR}/test_compiler ./scarlet --chapter 7 --stage lex
COMMAND ${CMAKE_SOURCE_DIR}/test_compiler ./scarlet --chapter 8 --stage lex
COMMAND echo "Running parser test"
COMMAND ${CMAKE_SOURCE_DIR}/test_compiler ./scarlet --chapter 7 --stage parse
COMMAND ${CMAKE_SOURCE_DIR}/test_compiler ./scarlet --chapter 8 --stage parse
COMMAND echo "Running semantic analysis test"
COMMAND ${CMAKE_SOURCE_DIR}/test_compiler ./scarlet --chapter 7 --stage validate
COMMAND ${CMAKE_SOURCE_DIR}/test_compiler ./scarlet --chapter 8 --stage validate
COMMAND echo "Running scar test"
COMMAND ${CMAKE_SOURCE_DIR}/test_compiler ./scarlet --chapter 7 --stage tacky
COMMAND ${CMAKE_SOURCE_DIR}/test_compiler ./scarlet --chapter 8 --stage tacky
COMMAND echo "Running Codegen test"
COMMAND ${CMAKE_SOURCE_DIR}/test_compiler ./scarlet --chapter 7 --stage codegen
COMMAND ${CMAKE_SOURCE_DIR}/test_compiler ./scarlet --chapter 8 --stage codegen
COMMAND echo "Running bitwise, compound, increment/decrement and goto test"
COMMAND ${CMAKE_SOURCE_DIR}/test_compiler ./scarlet --chapter 7 --extra-credit
COMMAND echo "Running test asm"
COMMAND ${CMAKE_SOURCE_DIR}/test_compiler ./scarlet --chapter 7
COMMAND ${CMAKE_SOURCE_DIR}/test_compiler ./scarlet --chapter 8
)
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ Scarlet currently supports the following architectures:
- [x] Add support for compound operators (+=,-=,*=,/=,<<=,>>=,%=)
- [x] Add support for goto statement
- [x] Add support for compound statements
- [ ] Add support for Loops
- [x] Add support for Loops (for, while, do-while)
- [ ] Add support for switch-case
- [ ] Add support for Functions
- [ ] Add support for static keyword and global scope
- [ ] Add support for Long Integers
Expand Down
126 changes: 120 additions & 6 deletions ast/ast.hh
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ Grammar:
<block_item> ::= <statement> | <declaration>
<block> ::= "{" { <block_item> } "}"
<declaration> ::= "int" <identifier> [ "=" <exp> ] ";"
<statement> ::= "return" <exp> ";" | <exp> ";" | ";" | "if" "(" <exp> ")" <statement> [ "else" <statement> ] | "goto" <identifier> ";" | <identifier> ":" | <block>
<for-init> ::= <declaration> | [ <exp> ]
<statement> ::= "return" <exp> ";" | <exp> ";" | ";" | "if" "(" <exp> ")" <statement> [ "else" <statement> ] | "goto" <identifier> ";" | <identifier> ":" | <block> | "break" ";" | "continue" ";" | "while" "(" <exp> ")" <statement> | "for" "(" <for-init> ";" [ <exp> ] ";" [ <exp> ] ")" <statement> | "do" <statement> "while" "(" <exp> ")" ";"
<exp> ::= <factor> | <exp> <binop> <exp> | <exp> "?" <exp> ":" <exp>
<factor> ::= <int> | <identifier> | <unop> <factor> | "(" <exp> ")"
<unop> ::= "~" | "-" | "!" | "--" | "++"
Expand Down Expand Up @@ -184,22 +185,29 @@ class AST_Block_Node;
// since each if statement can either exist on its own or have an else statement
enum class statementType {
UNKNOWN,
NULLSTMT,
RETURN,
EXP,
IF,
IFELSE,
_IF_END,
_IFELSE_END,
GOTO,
LABEL,
BLOCK
BLOCK,
BREAK,
CONTINUE,
WHILE,
FOR,
DO_WHILE
};

class AST_Statement_Node {
private:
std::shared_ptr<AST_exp_Node> exps;
statementType type;
std::shared_ptr<AST_Block_Node> block;
// Labels serve different purpose for different statements
std::pair<std::shared_ptr<AST_identifier_Node>,
std::shared_ptr<AST_identifier_Node>>
labels;

public:
std::string get_AST_name() { return "Statement"; }
Expand All @@ -211,12 +219,70 @@ public:
this->exps = std::move(exp);
}

std::pair<std::shared_ptr<AST_identifier_Node>,
std::shared_ptr<AST_identifier_Node>>
get_labels() {
return labels;
}
void set_labels(std::pair<std::shared_ptr<AST_identifier_Node>,
std::shared_ptr<AST_identifier_Node>>
labels) {
this->labels = std::move(labels);
}
};

class AST_block_statement_node : public AST_Statement_Node {
private:
std::shared_ptr<AST_Block_Node> block;

public:
std::string get_AST_name() { return "BlockStatement"; }
std::shared_ptr<AST_Block_Node> get_block() { return block; }
void set_block(std::shared_ptr<AST_Block_Node> block) {
this->block = std::move(block);
}
};

class AST_if_else_statement_Node : public AST_Statement_Node {
private:
std::shared_ptr<AST_Statement_Node> stmt1;
std::shared_ptr<AST_Statement_Node> stmt2;

public:
std::string get_AST_name() {
if (this->get_type() == statementType::IF) {
return "IfStatement";
} else {
return "IfElseStatement";
}
}
std::shared_ptr<AST_Statement_Node> get_stmt1() { return stmt1; }
void set_stmt1(std::shared_ptr<AST_Statement_Node> stmt1) {
this->stmt1 = std::move(stmt1);
}
std::shared_ptr<AST_Statement_Node> get_stmt2() { return stmt2; }
void set_stmt2(std::shared_ptr<AST_Statement_Node> stmt2) {
this->stmt2 = std::move(stmt2);
}
};

class AST_while_statement_Node : public AST_Statement_Node {
private:
std::shared_ptr<AST_Statement_Node> stmt;
std::string start_label;

public:
std::string get_AST_name() { return "WhileStatement"; }
std::shared_ptr<AST_Statement_Node> get_stmt() { return stmt; }
void set_stmt(std::shared_ptr<AST_Statement_Node> stmt) {
this->stmt = std::move(stmt);
}
std::string get_start_label() { return start_label; }
void set_start_label(std::string &&start_label) {
this->start_label = std::move(start_label);
}
};

enum class DeclarationType { INT };

class AST_Declaration_Node {
Expand Down Expand Up @@ -244,6 +310,54 @@ public:
}
};

class AST_For_Init_Node {
private:
std::shared_ptr<AST_Declaration_Node> declaration;
std::shared_ptr<AST_exp_Node> exp;

public:
std::string get_AST_name() { return "ForInit"; }
std::shared_ptr<AST_Declaration_Node> get_declaration() {
return declaration;
}
void set_declaration(std::shared_ptr<AST_Declaration_Node> declaration) {
this->declaration = std::move(declaration);
}
std::shared_ptr<AST_exp_Node> get_exp() { return exp; }
void set_exp(std::shared_ptr<AST_exp_Node> exp) {
this->exp = std::move(exp);
}
};

class AST_For_Statement_Node : public AST_Statement_Node {
private:
std::shared_ptr<AST_For_Init_Node> for_init;
std::shared_ptr<AST_exp_Node> exp2;
std::shared_ptr<AST_Statement_Node> stmt;
std::string start_label;

public:
std::string get_AST_name() { return "ForStatement"; }
std::shared_ptr<AST_For_Init_Node> get_for_init() { return for_init; }
void set_for_init(std::shared_ptr<AST_For_Init_Node> for_init) {
this->for_init = std::move(for_init);
}
std::shared_ptr<AST_exp_Node> get_exp2() { return exp2; }
void set_exp2(std::shared_ptr<AST_exp_Node> exp2) {
this->exp2 = std::move(exp2);
}

std::shared_ptr<AST_Statement_Node> get_stmt() { return stmt; }
void set_stmt(std::shared_ptr<AST_Statement_Node> stmt) {
this->stmt = std::move(stmt);
}

std::string get_start_label() { return start_label; }
void set_start_label(std::string &&start_label) {
this->start_label = std::move(start_label);
}
};

enum class BlockItemType { UNKNOWN, STATEMENT, DECLARATION };

// Right now, we determine whether a block item is a statement or a declaration
Expand Down Expand Up @@ -277,7 +391,7 @@ private:

public:
std::string get_AST_name() { return "Block"; }
std::vector<std::shared_ptr<AST_Block_Item_Node>> get_blockItems() {
std::vector<std::shared_ptr<AST_Block_Item_Node>> &get_blockItems() {
return blockItems;
}
void add_blockItem(std::shared_ptr<AST_Block_Item_Node> statement) {
Expand Down
Loading