Skip to content

Commit

Permalink
'loop' statement is implemented
Browse files Browse the repository at this point in the history
ALong with 'loop' statement, I have also implemented the 'break' statement. Loop is essentially a infinite loop which never stops. I generated unconditional jumps for it. Break statement simply jumps to the end of the loop body.
  • Loading branch information
rigel-star committed Oct 18, 2024
1 parent ca56ed0 commit c5f99df
Show file tree
Hide file tree
Showing 10 changed files with 212 additions and 44 deletions.
21 changes: 18 additions & 3 deletions examples/input1.bic
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
def __socket__() -> integer;
def extern print_int(x: integer) -> void;
def extern print(x: str) -> void;

def main() -> void {
let a: integer = __socket__();
def double_it(x: integer) -> integer {
return x * 2;
}

def main() -> integer {
let a: long = 1;
let msg: str = "'a' is greater than 5. Exiting...";
loop {
if (a > 5) {
print(msg);
break;
}
print_int(double_it(a));
a = a + 1;
}
return a;
}
15 changes: 9 additions & 6 deletions src/ast/ast_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,19 @@ use super::ASTKind;

#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
pub enum ASTOperation {
AST_NONE, // used as a placeholder
AST_ADD = 10, // an AST node with "+" as the root node
AST_SUBTRACT, // an AST node with "-" as the root node
AST_MULTIPLY, // an AST node with "*" as the root node
AST_DIVIDE, // an AST node with "/" as the root node
// below this are relational operators
AST_EQEQ, // equal equal
AST_EQEQ = 0, // equal equal
AST_NEQ, // not equal
AST_LTEQ, // less than or equal to
AST_GTEQ, // greate than equal to
AST_GTHAN, // greater than
AST_LTHAN, // less than

AST_NONE, // used as a placeholder
AST_ADD = 10, // an AST node with "+" as the root node
AST_SUBTRACT, // an AST node with "-" as the root node
AST_MULTIPLY, // an AST node with "*" as the root node
AST_DIVIDE, // an AST node with "/" as the root node
// end of relational operators
AST_INTLIT, // a leaf AST node with literal integer value
AST_IDENT, // a leaf AST node with an identifier name
Expand All @@ -50,6 +51,8 @@ pub enum ASTOperation {
AST_GLUE,
AST_IF,
AST_WHILE,
AST_LOOP,
AST_BREAK,
AST_FUNCTION,
AST_FUNC_CALL,
AST_RETURN, // return statement AST node
Expand Down
2 changes: 2 additions & 0 deletions src/ast/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ pub enum Stmt {
If,
For,
While,
Loop,
Break,
FuncDecl(FuncDeclStmt),
Return(ReturnStmt),
Assignment(AssignStmt),
Expand Down
111 changes: 91 additions & 20 deletions src/code_gen/aarch64/aarch64_codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,23 +95,38 @@ impl<'aarch64> CodeGen for Aarch64CodeGen<'aarch64> {
}
}

fn gen_if_stmt(&mut self, ast: &AST) -> usize {
let label_if_false: usize = self.get_next_label(); // label id to jump to if condition turns out to be false
let label_end: usize = self.get_next_label(); // this label is put after the end of entire if-else block
let cond_result_reg: usize = self.gen_code_from_ast(ast.left.as_ref().unwrap(), label_if_false, ast.operation);
fn gen_if_stmt(&mut self, ast: &AST, reg: usize) -> usize {
// Label for jumping to the 'else' block if the condition is false
let label_if_false: usize = self.get_next_label();

// Label marking the end of the entire if-else block
let label_end: usize = self.get_next_label();

// Evaluate the condition and store the result in a register
let _cond_result_reg: usize = self.gen_code_from_ast(ast.left.as_ref().unwrap(), label_if_false, ast.operation);

// Free registers to allow usage within the if-else body
self.reg_manager.borrow_mut().deallocate_all();
self.gen_code_from_ast(ast.mid.as_ref().unwrap(), cond_result_reg, ast.operation);

// Generate code for the 'if-true' block
self.gen_code_from_ast(ast.mid.as_ref().unwrap(), reg, ast.operation);

// Free registers again to prepare for any subsequent operations
self.reg_manager.borrow_mut().deallocate_all();
// if there is an 'else' block

// Jump to the end of the if-else block to skip the 'else' block if present
if ast.right.is_some() {
self.gen_jump(label_end);
}
// false label

// Label for the start of the 'else' block
self.gen_label(label_if_false);

// Generate code for the 'else' block, if it exists
if let Some(ref right_ast) = ast.right {
self.gen_code_from_ast(right_ast, 0xFFFFFFFF, ast.operation);
self.gen_code_from_ast(right_ast, reg, ast.operation);
self.reg_manager.borrow_mut().deallocate_all();
self.gen_label(label_end);
self.gen_label(label_end); // Mark the end of the if-else block
}
0xFFFFFFFF
}
Expand All @@ -120,10 +135,19 @@ impl<'aarch64> CodeGen for Aarch64CodeGen<'aarch64> {
let r1name: String = self.reg_manager.borrow().name(r1);
let r2name: String = self.reg_manager.borrow().name(r2);
println!("cmp {}, {}", r1name, r2name);
let compare_operator: &str = match operation {
ASTOperation::AST_LTHAN => "bge",
ASTOperation::AST_GTHAN => "ble",
ASTOperation::AST_EQEQ => "bne",
ASTOperation::AST_NEQ => "beq",
ASTOperation::AST_GTEQ => "blt",
ASTOperation::AST_LTEQ => "bgt",
_ => panic!("Not a valid ASTOperation for cmp and set")
};
println!(
"cset {}, {}",
r2name,
CMP_CONDS_LIST[operation as usize - ASTOperation::AST_EQEQ as usize]
compare_operator
);
println!("and {}, {}, 255", r2name, r2name);
r2
Expand All @@ -133,9 +157,18 @@ impl<'aarch64> CodeGen for Aarch64CodeGen<'aarch64> {
let r1name: String = self.reg_manager.borrow().name(r1);
let r2name: String = self.reg_manager.borrow().name(r2);
println!("cmp {}, {}", r1name, r2name);
let compare_operator: &str = match operation {
ASTOperation::AST_LTHAN => "bhs",
ASTOperation::AST_GTHAN => "bls",
ASTOperation::AST_EQEQ => "bne",
ASTOperation::AST_NEQ => "beq",
ASTOperation::AST_GTEQ => "blo",
ASTOperation::AST_LTEQ => "bhi",
_ => panic!("Not a valid ASTOperation for cmp and jmp")
};
println!(
"b{} _L{}",
CMP_CONDS_LIST[operation as usize - ASTOperation::AST_EQEQ as usize],
"{} _L{}",
compare_operator,
label
);
self.reg_manager.borrow_mut().deallocate_all();
Expand Down Expand Up @@ -167,10 +200,12 @@ impl<'aarch64> CodeGen for Aarch64CodeGen<'aarch64> {
}
println!(".global _{}\n_{}:", func_name, func_name);
println!("sub sp, sp, {}", func_info.stack_size);
println!("stp x29, x30, [sp, #16]");
if let Some(ref body) = ast.left {
self.gen_code_from_ast(body, 0xFFFFFFFF, ast.operation);
}
// function postamble
println!("ldp x29, x30, [sp, #16]");
println!("add sp, sp, {}\nret", func_info.stack_size);
0xFFFFFFFF
}
Expand All @@ -181,10 +216,29 @@ impl<'aarch64> CodeGen for Aarch64CodeGen<'aarch64> {
self.gen_label(label_start); // start of loop body
self.gen_code_from_ast(ast.left.as_ref().unwrap(), label_end, ast.operation);
self.reg_manager.borrow_mut().deallocate_all();
self.gen_code_from_ast(ast.right.as_ref().unwrap(), 0xFFFFFFFF, ast.operation);
self.gen_code_from_ast(ast.right.as_ref().unwrap(), label_end, ast.operation);
self.reg_manager.borrow_mut().deallocate_all();
self.gen_jump(label_start);
self.gen_label(label_end);
0xFFFFFFFF
}

fn gen_loop_stmt(&mut self, ast: &AST) {
// loop start label
let label_start: usize = self.get_next_label();

// loop end label
let label_end: usize = self.get_next_label();

self.gen_label(label_start);
self.gen_code_from_ast(ast.left.as_ref().unwrap(), label_end, ast.operation);
self.reg_manager.borrow_mut().deallocate_all();
self.gen_jump(label_start);
self.gen_label(label_end);
}

fn gen_break_stmt(&mut self, break_label: usize) -> usize {
println!("b _L{}", break_label);
0xFFFFFFFF
}

Expand Down Expand Up @@ -230,7 +284,7 @@ impl<'aarch64> CodeGen for Aarch64CodeGen<'aarch64> {
println!("str {}, [{}] // store into {}", reg_name, addr_reg_name, symbol.name);
addr_reg
} else {
println!("str {}, [sp, {}] // store into {}", reg_name, symbol.local_offset, symbol.name);
println!("str {}, [sp, #{}] // store into {}", reg_name, symbol.local_offset, symbol.name);
0xFFFFFFFF
}
}
Expand Down Expand Up @@ -293,12 +347,12 @@ impl<'aarch64> CodeGen for Aarch64CodeGen<'aarch64> {
fn gen_return_stmt(&mut self, result_reg: usize, _func_id: usize) -> usize {
// NOTE: Generate code depending on the function's type. i.e. use w0 for i32, x0 for i64 etc.
// let func_ret_type: LitTypeVariant = self.sym_table.get_symbol(func_id).lit_type;
if result_reg != 0xFFFFFFFF {
println!(
"mov x0, {}",
self.reg_manager.borrow().name(result_reg)
);
}
// if result_reg != 0xFFFFFFFF {
// println!(
// "mov x0, {}",
// self.reg_manager.borrow().name(result_reg)
// );
// }
0xFFFFFFFF
}

Expand Down Expand Up @@ -448,6 +502,23 @@ impl<'aarch64> CodeGen for Aarch64CodeGen<'aarch64> {
self.function_id = 0xFFFFFFFF;
alloced_reg
}

fn gen_var_assignment_stmt(&mut self, assign_stmt: &crate::ast::AssignStmt, expr_ast: &Expr) {
// self.gen_load_id_into_reg(assign_stmt.symtbl_pos);
let expr_reg = self.gen_expr(expr_ast, ASTOperation::AST_ASSIGN, 0xFFFFFFFF, ASTOperation::AST_NONE);
self.gen_store_reg_value_into_id(expr_reg, assign_stmt.symtbl_pos);
// let symbol: Symbol = if let Some(ctx_rc) = &self.ctx {
// let ctx_borrow = ctx_rc.borrow_mut();
// if let Some(symbol) = ctx_borrow.sym_table.get_symbol(assign_stmt.symtbl_pos) {
// symbol.clone()
// } else {
// panic!("not possible to reach here");
// }
// } else {
// panic!("no context provided");
// };

}
}

impl<'aarch64> Aarch64CodeGen<'aarch64> {
Expand Down
52 changes: 44 additions & 8 deletions src/code_gen/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ SOFTWARE.
use std::cell::RefMut;

use crate::ast::ASTKind;
use crate::ast::AssignStmt;
use crate::ast::BinExpr;
use crate::ast::Expr;
use crate::ast::FuncCallExpr;
Expand Down Expand Up @@ -108,18 +109,24 @@ pub trait CodeGen {
parent_ast_kind: ASTOperation)
-> usize where Self: Sized {
if ast_node.operation == ASTOperation::AST_IF {
self.gen_if_stmt(ast_node)
} else if ast_node.operation == ASTOperation::AST_WHILE {
self.gen_if_stmt(ast_node, reg)
}
else if ast_node.operation == ASTOperation::AST_WHILE {
self.gen_while_stmt(ast_node)
} else if ast_node.operation == ASTOperation::AST_FUNCTION {
}
else if ast_node.operation == ASTOperation::AST_FUNCTION {
self.gen_function_stmt(ast_node)
} else if ast_node.operation == ASTOperation::AST_GLUE {
}
else if ast_node.operation == ASTOperation::AST_BREAK {
self.gen_break_stmt(reg)
}
else if ast_node.operation == ASTOperation::AST_GLUE {
if let Some(left) = ast_node.left.as_ref() {
self.gen_code_from_ast(left, 0xFFFFFFFF, ast_node.operation);
self.gen_code_from_ast(left, reg, ast_node.operation);
self.reg_manager().deallocate_all();
}
if let Some(right) = ast_node.right.as_ref() {
self.gen_code_from_ast(right, 0xFFFFFFFF, ast_node.operation);
self.gen_code_from_ast(right, reg, ast_node.operation);
self.reg_manager().deallocate_all();
}
return 0xFFFFFFFF;
Expand Down Expand Up @@ -166,8 +173,31 @@ pub trait CodeGen {
0xFFFFFFFF
}
else if ast_node.operation == ASTOperation::AST_NONE || ast_node.operation == ASTOperation::AST_VAR_DECL {
return 0xFFFFFFFF
return 0xFFFFFFFF;
}
else if ast_node.operation == ASTOperation::AST_ASSIGN {
let possible_assign_stmt: Stmt = ast_node.kind.clone().unwrap_stmt();
return match possible_assign_stmt {
Stmt::Assignment(assign) => {
let assign_expr = &ast_node.right.as_ref().unwrap().kind;
if let ASTKind::ExprAST(__expr) = assign_expr {
self.gen_var_assignment_stmt(&assign, __expr);
}
0xFFFFFFFF
},
_ => 0xFFFFFFFF
};
}
else if ast_node.operation == ASTOperation::AST_LOOP {
let possible_loop_stmt: Stmt = ast_node.kind.clone().unwrap_stmt();
return match possible_loop_stmt {
Stmt::Loop => {
self.gen_loop_stmt(ast_node);
0xFFFFFFFF
},
_ => 0xFFFFFFFF
}
}
else {
let expr_ast: Expr = ast_node.kind.clone().unwrap_expr();
let reg_used_for_expr: usize = self.gen_expr(&expr_ast, ast_node.operation, reg, parent_ast_kind);
Expand Down Expand Up @@ -268,7 +298,7 @@ pub trait CodeGen {
///
/// The function always returns `0xFFFFFFFF` to signify no register allocation during
/// code generation.
fn gen_if_stmt(&mut self, ast: &AST) -> usize;
fn gen_if_stmt(&mut self, ast: &AST, reg: usize) -> usize;

fn gen_jump(&self, label_id: usize);

Expand Down Expand Up @@ -315,5 +345,11 @@ pub trait CodeGen {

fn gen_local_var_decl_stmt(&mut self, var_decl_stmt: &VarDeclStmt, expr_ast: &Expr);

fn gen_var_assignment_stmt(&mut self, assign_stmt: &AssignStmt, expr_ast: &Expr);

fn gen_loop_stmt(&mut self, ast: &AST);

fn gen_break_stmt(&mut self, break_label: usize) -> usize;

fn reg_manager(&self) -> RefMut<RegManager>;
}
1 change: 1 addition & 0 deletions src/code_gen/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ impl RegManager {
for (_, reg_status) in self.registers.iter_mut() {
*reg_status = 1;
}
self.deallocate_all_param_regs();
}

pub fn deallocate_all_param_regs(&mut self) {
Expand Down
Loading

0 comments on commit c5f99df

Please sign in to comment.