From 264ae08b841edd93dba86a593160e765a2d26fa0 Mon Sep 17 00:00:00 2001 From: Ramesh Poudel Date: Thu, 1 Feb 2024 18:00:48 +0545 Subject: [PATCH] generating code for simple if-else block --- src/ast.rs | 100 +++++++++++++++++++++++++++++++++++++++++++------- src/main.rs | 15 ++++---- src/parser.rs | 63 ++++++++++++++----------------- 3 files changed, 122 insertions(+), 56 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 714ef15..fca684a 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -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>, pub right: Option>, - pub value: LitType + pub mid: Option>, + 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>, sym_table: Rc>, + label_id_count: usize, } impl ASTTraverser { #[allow(clippy::new_without_default)] pub fn new(reg_manager: Rc>, sym_table: Rc>) -> 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); @@ -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); + } } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index a893e7b..443d614 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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 = 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> = Rc::new(RefCell::new(register::RegisterManager::new())); + let sym_table: Rc> = 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(®_manager), Rc::clone(&sym_table)); + if let Some(s) = p.start() { + traverser.traverse(&s); + } } \ No newline at end of file diff --git a/src/parser.rs b/src/parser.rs index 5111106..1d2fae7 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -78,41 +78,34 @@ impl<'a> Parser<'a> { #[allow(unused_assignments)] let mut tree: Option = None; let mut left: Option = 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