Skip to content

Commit

Permalink
feat: add support for loops (while, do-while, for) (#57)
Browse files Browse the repository at this point in the history
* the parser battle begins

* parser battle has some sunshine

* done with parser

* for loop battle showdown

* a taste of victory

* the battle is over

* final clean up

* update docs
  • Loading branch information
Sh0g0-1758 authored Feb 19, 2025
1 parent 927db87 commit 9087598
Show file tree
Hide file tree
Showing 10 changed files with 1,077 additions and 336 deletions.
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

0 comments on commit 9087598

Please sign in to comment.