Skip to content

Commit

Permalink
generating code for simple if-else block
Browse files Browse the repository at this point in the history
  • Loading branch information
rigel-star committed Feb 1, 2024
1 parent a395661 commit 264ae08
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 56 deletions.
100 changes: 86 additions & 14 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,66 +25,124 @@ SOFTWARE.
extern crate lazy_static;
use std::{cell::RefCell, rc::Rc};

use lazy_static::lazy_static;

use crate::{enums::*, register::{self, RegisterManager}, symtable};

lazy_static! {
// All available non-extended registers of ARM64
static ref REGISTERS: Vec<&'static str> = vec!["w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15", "w16"];
lazy_static::lazy_static! {
static ref CMP_CONDS_LIST: Vec<&'static str> = vec!["neq", "eq", "ge", "le", "lt", "gt"];
}

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct ASTNode {
pub operation: ASTNodeKind, // operation to be performed on this AST node
pub left: Option<Box<ASTNode>>,
pub right: Option<Box<ASTNode>>,
pub value: LitType
pub mid: Option<Box<ASTNode>>,
pub value: LitType,
}

impl ASTNode {
pub fn new(op: ASTNodeKind, left: ASTNode, right: ASTNode, value: LitType) -> Self {
Self { operation: op, left: Some(Box::new(left)), right: Some(Box::new(right)), value }
Self { operation: op, left: Some(Box::new(left)), right: Some(Box::new(right)), mid: None, value }
}

pub fn make_leaf(op: ASTNodeKind, value: LitType) -> Self {
Self { operation: op, left: None, right: None, value }
Self { operation: op, left: None, right: None, mid: None, value }
}

pub fn make_with_mid(op: ASTNodeKind, left: ASTNode, right: ASTNode, mid: ASTNode, value: LitType) -> Self {
Self { operation: op, left: Some(Box::new(left)), right: Some(Box::new(right)), mid: Some(Box::new(mid)), value }
}
}

pub struct ASTTraverser {
reg_manager: Rc<RefCell<register::RegisterManager>>,
sym_table: Rc<RefCell<symtable::Symtable>>,
label_id_count: usize,
}

impl ASTTraverser {
#[allow(clippy::new_without_default)]
pub fn new(reg_manager: Rc<RefCell<RegisterManager>>, sym_table: Rc<RefCell<symtable::Symtable>>) -> Self {
Self { reg_manager, sym_table }
Self { reg_manager, sym_table, label_id_count: 0 }
}

pub fn traverse(&mut self, ast: &ASTNode) -> usize {
self.gen_from_ast(ast, 0xFFFFFFFF)
self.gen_ast(ast, 0xFFFFFFFF, ast.operation)
}

fn gen_from_ast(&mut self, ast: &ASTNode, _reg: usize) -> usize {
fn gen_ast(&mut self, ast: &ASTNode, _reg: usize, parent_ast_kind: ASTNodeKind) -> usize {
if ast.operation == ASTNodeKind::AST_IF {
return self.gen_ifstmt_ast(ast);
} else if ast.operation == ASTNodeKind::AST_GLUE {
if let Some(left) = &ast.left {
self.gen_ast(left, 0xFFFFFFFF, ast.operation);
self.reg_manager.borrow_mut().deallocate_all();
}
if let Some(right) = &ast.right {
self.gen_ast(right, 0xFFFFFFFF, ast.operation);
self.reg_manager.borrow_mut().deallocate_all();
}
}

let mut leftreg: usize = 0;
let mut rightreg: usize = 0;
if ast.left.is_some() {
leftreg = self.gen_from_ast(ast.left.as_ref().unwrap(), 0xFFFFFFFF);
leftreg = self.gen_ast(ast.left.as_ref().unwrap(), 0xFFFFFFFF, ast.operation);
}
if ast.right.is_some() {
rightreg = self.gen_from_ast(ast.right.as_ref().unwrap(), leftreg);
rightreg = self.gen_ast(ast.right.as_ref().unwrap(), leftreg, ast.operation);
}
match ast.operation {
ASTNodeKind::AST_ADD => self.gen_add(leftreg, rightreg),
ASTNodeKind::AST_SUBTRACT => self.gen_sub(leftreg, rightreg),
ASTNodeKind::AST_INTLIT => self.gen_load_intlit_into_reg(&ast.value),
ASTNodeKind::AST_IDENT => self.gen_load_gid_into_reg(&ast.value),
ASTNodeKind::AST_ASSIGN => rightreg,
ASTNodeKind::AST_GTHAN |
ASTNodeKind::AST_LTHAN |
ASTNodeKind::AST_LTEQ |
ASTNodeKind::AST_GTEQ |
ASTNodeKind::AST_NEQ |
ASTNodeKind::AST_EQEQ => {
if parent_ast_kind == ASTNodeKind::AST_IF {
self.gen_cmp_and_jmp(ast.operation, leftreg, rightreg, _reg)
} else {
0xFFFFFFFF
}
},
_ => panic!("unknown AST operator '{:?}'", ast.operation),
}
}

fn gen_ifstmt_ast(&mut self, ast: &ASTNode) -> usize {
let label_if_false: usize = self.get_next_label(); // label id to jump to if condition turns out to be false
let mut label_end: usize = 0xFFFFFFFF; // this label is put after the end of entire if-else block
if ast.right.is_some() { label_end = self.get_next_label(); }
self.gen_ast(ast.left.as_ref().unwrap(), label_if_false, ast.operation);
self.reg_manager.borrow_mut().deallocate_all();
self.gen_ast(ast.mid.as_ref().unwrap(), 0xFFFFFFFF, ast.operation);
self.reg_manager.borrow_mut().deallocate_all();
// if there is an 'else' block
if ast.right.is_some() { self.gen_jump(label_end); }
// false label
self.gen_label(label_if_false);
if let Some(right_ast) = &ast.right {
self.gen_ast(right_ast, 0xFFFFFFFF, ast.operation);
self.reg_manager.borrow_mut().deallocate_all();
self.gen_label(label_end);
}
0xFFFFFFFF
}

fn gen_cmp_and_jmp(&self, operation: ASTNodeKind, r1: usize, r2: usize, label: usize) -> usize {
let r1name: String = self.reg_manager.borrow().name(r1);
let r2name: String = self.reg_manager.borrow().name(r2);
println!("cmp {}, {}", r1name, r2name);
println!("b{} _L{}", CMP_CONDS_LIST[operation as usize - ASTNodeKind::AST_EQEQ as usize], label);
self.reg_manager.borrow_mut().deallocate_all();
0xFFFFFFFF
}

fn gen_add(&mut self, r1: usize, r2: usize) -> usize {
println!("add {}, {}, {}\n", self.reg_manager.borrow().name(r1), self.reg_manager.borrow().name(r1), self.reg_manager.borrow().name(r2));
self.reg_manager.borrow_mut().deallocate(r2);
Expand Down Expand Up @@ -122,4 +180,18 @@ impl ASTTraverser {
println!("ldr {}, ={}\nldr {}, [{}]\n", reg_name, sym, value_containing_reg_name, reg_name);
value_containing_reg
}

fn get_next_label(&mut self) -> usize {
let label: usize = self.label_id_count;
self.label_id_count += 1;
label
}

fn gen_jump(&self, label_id: usize) {
println!("b _L{}", label_id);
}

fn gen_label(&mut self, label: usize) {
println!("_L{}:", label);
}
}
15 changes: 8 additions & 7 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,13 @@ pub mod enums;
pub mod register;

fn main() {
let mut tokener: tokenizer::Tokenizer = tokenizer::Tokenizer::new("int a; a = 5; int b; b = a;");
let mut tokener: tokenizer::Tokenizer = tokenizer::Tokenizer::new("if (4 > 5) local int c; else { local int a; }");
let tokens: Vec<tokenizer::Token> = tokener.start_scan();
let mut p: parser::Parser = parser::Parser::new(
&tokens,
Rc::new(RefCell::new(register::RegisterManager::new())),
Rc::new(RefCell::new(symtable::Symtable::new()))
);
p.parse_stmts();
let reg_manager: Rc<RefCell<register::RegisterManager>> = Rc::new(RefCell::new(register::RegisterManager::new()));
let sym_table: Rc<RefCell<symtable::Symtable>> = Rc::new(RefCell::new(symtable::Symtable::new()));
let mut p: parser::Parser = parser::Parser::new(&tokens, Rc::clone(&sym_table));
let mut traverser: ast::ASTTraverser = ast::ASTTraverser::new(Rc::clone(&reg_manager), Rc::clone(&sym_table));
if let Some(s) = p.start() {
traverser.traverse(&s);
}
}
63 changes: 28 additions & 35 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,41 +78,34 @@ impl<'a> Parser<'a> {
#[allow(unused_assignments)]
let mut tree: Option<ASTNode> = None;
let mut left: Option<ASTNode> = None;
loop {
match self.current_token.kind {
TokenKind::KW_GLOBAL => {
// ignore globals as they are already parsed
self.jump_past(TokenKind::T_SEMICOLON);
tree = None;
break;
},
TokenKind::KW_LOCAL => {
self.parse_local_variable_decl_stmt();
tree = None;
break;
},
TokenKind::T_IDENTIFIER => {
tree = self.parse_assignment_stmt();
break;
},
TokenKind::KW_IF => {
tree = self.parse_if_stmt();
break;
},
TokenKind::T_LBRACE => {
self.jump_past(TokenKind::T_RBRACE);
tree = left.clone();
break;
},
TokenKind::T_EOF => tree = None,
_ => panic!("Syntax error: {:?}", self.current_token)
};
if let Some(_tree) = &tree {
if left.is_none() {
left = tree;
} else {
left = Some(ASTNode::new(ASTNodeKind::AST_GLUE, left.unwrap(), tree.unwrap(), LitType::Integer(0)));
}
match self.current_token.kind {
TokenKind::KW_GLOBAL => {
// ignore globals as they are already parsed
self.jump_past(TokenKind::T_SEMICOLON);
tree = None;
},
TokenKind::KW_LOCAL => {
self.parse_local_variable_decl_stmt();
tree = Some(ASTNode::make_leaf(ASTNodeKind::AST_INTLIT, LitType::Integer(12)));
},
TokenKind::T_IDENTIFIER => {
tree = self.parse_assignment_stmt();
},
TokenKind::KW_IF => {
tree = self.parse_if_stmt();
},
TokenKind::T_LBRACE => {
self.jump_past(TokenKind::T_RBRACE);
tree = left.clone();
},
TokenKind::T_EOF => tree = None,
_ => panic!("Syntax error: {:?}", self.current_token)
};
if let Some(_tree) = &tree {
if left.is_none() {
left = tree.clone();
} else {
left = Some(ASTNode::new(ASTNodeKind::AST_GLUE, left.unwrap(), tree.clone().unwrap(), LitType::Integer(0)));
}
}
tree
Expand Down

0 comments on commit 264ae08

Please sign in to comment.