diff --git a/examples/input1.bic b/examples/input1.bic index 325cf79..b39b04c 100644 --- a/examples/input1.bic +++ b/examples/input1.bic @@ -1 +1 @@ -let a: integer = 88834; \ No newline at end of file +let b = 34; \ No newline at end of file diff --git a/src/code_gen/aarch64/aarch64_codegen.rs b/src/code_gen/aarch64/aarch64_codegen.rs index 0f2517b..7ef6e44 100644 --- a/src/code_gen/aarch64/aarch64_codegen.rs +++ b/src/code_gen/aarch64/aarch64_codegen.rs @@ -22,6 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +use core::panic; use std::cell::RefMut; use std::cell::RefCell; use std::rc::Rc; @@ -69,6 +70,13 @@ impl<'aarch64> CodeGen for Aarch64CodeGen<'aarch64> { if symbol.lit_type == LitTypeVariant::None || symbol.sym_type == SymbolType::Function || symbol.class != StorageClass::GLOBAL { continue; } + if symbol.lit_type == LitTypeVariant::Str && symbol.sym_type == SymbolType::Constant { + let str_const_name_and_val: Vec<&str> = symbol.name.split("---").collect::>(); + let str_const_name: String = String::from(str_const_name_and_val[0]); + println!(".data\n.global {str_const_name}"); + println!("{str_const_name}:\n\t.asciz \"{}\"", str_const_name_and_val[1]); + continue; + } println!(".data\n.global {}", symbol.name); if symbol.sym_type == SymbolType::Variable { Aarch64CodeGen::dump_global_with_alignment(symbol); @@ -427,6 +435,17 @@ impl<'aarch64> Aarch64CodeGen<'aarch64> { match symbol.lit_type { LitTypeVariant::I32 => println!("{}: .align 4\n\t.word 0", symbol.name), LitTypeVariant::U8 => println!("{}:\t.byte 0", symbol.name), + LitTypeVariant::Str => { + let label_id = if let Some(lit_val) = &symbol.default_value { + match lit_val { + LitType::I32(__id) => *__id, + _ => panic!("Not a valid label id for string literal '{}'", symbol.default_value.as_ref().unwrap()) + } + } else { + panic!("No label id provided for string literal"); + }; + println!("{}:\t.quad ._L{:?}", symbol.name, label_id); + } _ => panic!("Symbol's size is not supported right now: '{:?}'", symbol), } } diff --git a/src/code_gen/codegen.rs b/src/code_gen/codegen.rs index 683a504..9230565 100644 --- a/src/code_gen/codegen.rs +++ b/src/code_gen/codegen.rs @@ -118,7 +118,26 @@ pub trait CodeGen { self.reg_manager().deallocate_all(); } return 0xFFFFFFFF; - } else if ast_node.operation == ASTOperation::AST_VAR_DECL { + } + else if ast_node.operation == ASTOperation::AST_RETURN { + let possible_ret_stmt: Stmt = ast_node.kind.clone().unwrap_stmt(); + let return_expr: &AST = ast_node.left.as_ref().unwrap(); + let result_reg: usize = self.gen_expr(&return_expr.kind.clone().unwrap_expr(), ast_node.operation, reg, parent_ast_kind); + return match possible_ret_stmt { + Stmt::Return(ret) => self.gen_return_stmt(result_reg, ret.func_id), + _ => 0xFFFFFFFF + }; + } + else if ast_node.operation == ASTOperation::AST_NONE || ast_node.operation == ASTOperation::AST_VAR_DECL { + return 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); + return reg_used_for_expr; + } + /* + else if ast_node.operation == ASTOperation::AST_VAR_DECL { let possible_var_decl_stmt: Stmt = ast_node.kind.clone().unwrap_stmt(); return match possible_var_decl_stmt { Stmt::VarDecl(var_decl) => { @@ -137,23 +156,7 @@ pub trait CodeGen { _ => 0xFFFFFFFF // invalid AST kind with AST_LVIDENT operation }; } - else if ast_node.operation == ASTOperation::AST_RETURN { - let possible_ret_stmt: Stmt = ast_node.kind.clone().unwrap_stmt(); - let return_expr: &AST = ast_node.left.as_ref().unwrap(); - let result_reg: usize = self.gen_expr(&return_expr.kind.clone().unwrap_expr(), ast_node.operation, reg, parent_ast_kind); - return match possible_ret_stmt { - Stmt::Return(ret) => self.gen_return_stmt(result_reg, ret.func_id), - _ => 0xFFFFFFFF - }; - } - else if ast_node.operation == ASTOperation::AST_NONE { - return 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); - return reg_used_for_expr; - } + */ } fn gen_expr( diff --git a/src/context/compiler_ctx.rs b/src/context/compiler_ctx.rs index 6352acc..08c4e70 100644 --- a/src/context/compiler_ctx.rs +++ b/src/context/compiler_ctx.rs @@ -36,7 +36,7 @@ pub struct CompilerCtx<'ctx> { pub label_id: usize, /// Source file that is currently being processed. - pub current_file: Option<&'ctx SourceFile> + pub current_file: Option<&'ctx SourceFile>, } impl<'ctx> CompilerCtx<'ctx> { @@ -45,11 +45,11 @@ impl<'ctx> CompilerCtx<'ctx> { sym_table: symt, func_table, label_id: 0, - current_file: None + current_file: None, } } pub fn incr_label_count(&mut self) { self.label_id += 1; } -} \ No newline at end of file +} diff --git a/src/error.rs b/src/error.rs index 1a86e43..5698d1d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -53,7 +53,8 @@ pub enum BTypeErr { TypesMismatch { expected: String, found: String }, AssignmentTypeMismatch { var_type: String, assigned_type: String }, ReturnTypeMismatch { expected: String, found: String }, - IncompatibleTypes { first_type: String, second_type: String, operator: String } + IncompatibleTypes { first_type: String, second_type: String, operator: String }, + InitializerNotAConstant { lexeme: String } } #[derive(PartialEq, Clone, Debug)] @@ -91,7 +92,8 @@ impl BErr { BTypeErr::TypesMismatch { expected, found } => format!("Type mismatch: expected {}, found {}", expected, found), BTypeErr::AssignmentTypeMismatch { var_type, assigned_type } => format!("Cannot assign a value of type '{}' to a variable of type '{}'", assigned_type, var_type), BTypeErr::ReturnTypeMismatch { expected, found } => format!("Return type mismatch: expected {}, found {}", expected, found), - BTypeErr::IncompatibleTypes { first_type, second_type, operator } => format!("Incompatible types '{}' and '{}' for operator '{}'", first_type, second_type, operator) + BTypeErr::IncompatibleTypes { first_type, second_type, operator } => format!("Incompatible types '{}' and '{}' for operator '{}'", first_type, second_type, operator), + BTypeErr::InitializerNotAConstant { lexeme } => format!("Initializer is not a constant '{}'", lexeme) }, _ => "".to_string() }; diff --git a/src/parser/parser_impl.rs b/src/parser/parser_impl.rs index 9fd2c79..f57d82a 100644 --- a/src/parser/parser_impl.rs +++ b/src/parser/parser_impl.rs @@ -37,7 +37,6 @@ use crate::ast::SubscriptExpr; use crate::ast::VarDeclStmt; use crate::ast::AST; use crate::context::CompilerCtx; -use crate::error; use crate::error::*; use crate::symbol::*; use crate::tokenizer::*; @@ -67,7 +66,7 @@ enum ParserScope { struct ParserContext { function_id: usize, scope: ParserScope, - is_erronous_parse: bool + is_erronous_parse: bool, } impl ParserContext { @@ -106,7 +105,7 @@ pub struct Parser<'parser> { ctx: Option>>>, /// Context of this parser. - __pctx: ParserContext + __pctx: ParserContext, } impl<'parser> Parser<'parser> { @@ -122,11 +121,11 @@ impl<'parser> Parser<'parser> { next_global_sym_pos: 0, next_local_sym_pos: NSYMBOLS - 1, ctx: None, - __pctx: ParserContext { - function_id: INVALID_FUNC_ID, - scope: ParserScope::GLOBAL, - is_erronous_parse: false - } + __pctx: ParserContext { + function_id: INVALID_FUNC_ID, + scope: ParserScope::GLOBAL, + is_erronous_parse: false, + }, } } @@ -191,7 +190,10 @@ impl<'parser> Parser<'parser> { TokenKind::T_LBRACE => self.parse_compound_stmt(), TokenKind::KW_DEF => self.parse_function_stmt(), TokenKind::KW_RETURN => self.parse_return_stmt(), - TokenKind::T_EOF => Err(Box::new(BErr::unexpected_token(self.get_current_file_name(), self.current_token.clone()))), + TokenKind::T_EOF => Err(Box::new(BErr::unexpected_token( + self.get_current_file_name(), + self.current_token.clone(), + ))), _ => { let result: ParseResult2 = self.parse_equality(); self.token_match(TokenKind::T_SEMICOLON); @@ -231,7 +233,10 @@ impl<'parser> Parser<'parser> { if let Some(node) = left { Ok(node) } else { - Err(Box::new(BErr::unexpected_token(self.get_current_file_name(), self.current_token.clone()))) + Err(Box::new(BErr::unexpected_token( + self.get_current_file_name(), + self.current_token.clone(), + ))) } } @@ -247,7 +252,10 @@ impl<'parser> Parser<'parser> { let curr_tok_kind: TokenKind = self.current_token.kind; let func_return_type: LitTypeVariant = LitTypeVariant::from_token_kind(curr_tok_kind); if func_return_type == LitTypeVariant::None { - return Err(Box::new(BErr::unexpected_token(self.get_current_file_name(), self.current_token.clone()))); + return Err(Box::new(BErr::unexpected_token( + self.get_current_file_name(), + self.current_token.clone(), + ))); } self.skip_to_next_token(); // skip return type // create a new function symbol with the storage class of global @@ -259,7 +267,10 @@ impl<'parser> Parser<'parser> { )); // in case the function symbol addition process fails if function_id.is_none() { - return Err(Box::new(BErr::symbol_already_defined(self.get_current_file_name(), self.current_token.clone()))); + return Err(Box::new(BErr::symbol_already_defined( + self.get_current_file_name(), + self.current_token.clone(), + ))); } self.current_function_id = function_id.unwrap(); // create function body @@ -307,7 +318,10 @@ impl<'parser> Parser<'parser> { let mut func_symbol: Option = None; // check whether parser's parsing a function or not if self.current_function_id == INVALID_FUNC_ID { - return Err(Box::new(BErr::unexpected_token(self.get_current_file_name(), self.current_token.clone()))); + return Err(Box::new(BErr::unexpected_token( + self.get_current_file_name(), + self.current_token.clone(), + ))); } else { let mut sym: Option = None; if let Some(ctx_rc) = &mut self.ctx { @@ -321,7 +335,10 @@ impl<'parser> Parser<'parser> { ); } if sym.is_none() { - return Err(Box::new(BErr::undefined_symbol(self.get_current_file_name(), self.current_token.clone()))); + return Err(Box::new(BErr::undefined_symbol( + self.get_current_file_name(), + self.current_token.clone(), + ))); } func_symbol = sym; // check if the function's return type is void @@ -331,7 +348,10 @@ impl<'parser> Parser<'parser> { if void_ret_type { // if function has void as the return type, panic if any expression follows the keyword 'return' if self.current_token.kind != TokenKind::T_SEMICOLON { - return Err(Box::new(BErr::unexpected_token(self.get_current_file_name(), self.current_token.clone()))); + return Err(Box::new(BErr::unexpected_token( + self.get_current_file_name(), + self.current_token.clone(), + ))); } // skip semicolon self.token_match(TokenKind::T_SEMICOLON); @@ -347,20 +367,14 @@ impl<'parser> Parser<'parser> { let return_expr_type: LitTypeVariant = return_expr.result_type; if return_expr_type != func_symbol.as_ref().unwrap().lit_type { let expected_type: LitTypeVariant = func_symbol.as_ref().unwrap().lit_type; - return Err( - Box::new( - BErr::new( - BErrType::TypeError( - BTypeErr::ReturnTypeMismatch { - expected: expected_type.to_string(), - found: return_expr_type.to_string() - } - ), - self.get_current_file_name(), - self.current_token.clone() - ) - ) - ); + return Err(Box::new(BErr::new( + BErrType::TypeError(BTypeErr::ReturnTypeMismatch { + expected: expected_type.to_string(), + found: return_expr_type.to_string(), + }), + self.get_current_file_name(), + self.current_token.clone(), + ))); } _ = self.token_match(TokenKind::T_SEMICOLON); // expect semicolon to end a return statement Ok(AST::new( @@ -512,6 +526,7 @@ impl<'parser> Parser<'parser> { _ = self.token_match(TokenKind::T_EQUAL); // match and ignore '=' sign assignment_parse_res = Some(self.parse_equality()); } + let mut default_value: Option = None; // if there is some error during expression parsing if let Some(Err(parse_error)) = assignment_parse_res { return Err(parse_error); @@ -520,21 +535,19 @@ impl<'parser> Parser<'parser> { let assign_value_type: LitTypeVariant = self.determine_type(assignment_parse_res.as_ref().unwrap()); if var_type != LitTypeVariant::None && var_type != assign_value_type { - return Err( - Box::new( - BErr::new( - BErrType::TypeError( - BTypeErr::AssignmentTypeMismatch { - var_type: var_type.to_string(), - assigned_type: assign_value_type.to_string() - } - ), - self.get_current_file_name(), - self.current_token.clone() - ) - ) - ); + return Err(Box::new(BErr::new( + BErrType::TypeError(BTypeErr::AssignmentTypeMismatch { + var_type: var_type.to_string(), + assigned_type: assign_value_type.to_string(), + }), + self.get_current_file_name(), + self.current_token.clone(), + ))); } else { + if var_type == LitTypeVariant::Str { + let str_const_label: usize = self.ctx.as_ref().unwrap().borrow_mut().label_id - 1; + default_value = Some(LitType::I32(str_const_label as i32)); + } var_type = assign_value_type; } } @@ -546,10 +559,11 @@ impl<'parser> Parser<'parser> { SymbolType::Variable, var_class, ); + sym.default_value = default_value; // test assignability let mut return_result: ParseResult2 = Err(Box::new(BErr::none())); // this indicates variable is declared without assignment - // This has to fixed later. + // This has to fixed later. let symbol_add_pos: usize = if inside_func { self.add_symbol_local(sym.clone()).unwrap() } else { @@ -647,7 +661,10 @@ impl<'parser> Parser<'parser> { self.find_symbol(&id_token.lexeme); if symbol_search_result.is_none() { self.skip_past(TokenKind::T_SEMICOLON); - return Err(Box::new(BErr::undefined_symbol(self.get_current_file_name(), id_token))); + return Err(Box::new(BErr::undefined_symbol( + self.get_current_file_name(), + id_token, + ))); } let id_index_symt: usize = symbol_search_result.unwrap().0; let symbol: Symbol = if let Some(ctx_rc) = &mut self.ctx { @@ -658,14 +675,19 @@ impl<'parser> Parser<'parser> { .unwrap() .clone() } else { - return Err( - Box::new(BErr::new(BErrType::UndefinedSymbol, self.get_current_file_name(), self.current_token.clone())) - ); + return Err(Box::new(BErr::new( + BErrType::UndefinedSymbol, + self.get_current_file_name(), + self.current_token.clone(), + ))); }; // we are in global scope but trying to assign to a local variable if self.is_scope_global() && symbol.class == StorageClass::LOCAL { self.skip_past(TokenKind::T_SEMICOLON); - return Err(Box::new(BErr::undefined_symbol(self.get_current_file_name(), id_token))); + return Err(Box::new(BErr::undefined_symbol( + self.get_current_file_name(), + id_token, + ))); } // Check if we are assigning to a type other than SymbolType::Variable. If yes, panic! if symbol.sym_type != SymbolType::Variable { @@ -696,8 +718,7 @@ impl<'parser> Parser<'parser> { } fn validate_assign_compatibility(symbol: &Symbol, node: &mut AST) -> Option { - let compat_node: Option = - types::modify_ast_node_type(node, symbol.lit_type); + let compat_node: Option = types::modify_ast_node_type(node, symbol.lit_type); compat_node.as_ref()?; compat_node } @@ -743,21 +764,18 @@ impl<'parser> Parser<'parser> { self.skip_to_next_token(); // skip the operator let ast_op: ASTOperation = ASTOperation::from_token_kind(current_token_kind); let right: AST = self.parse_equality()?; - let compat_res: (bool, LitTypeVariant) = are_compatible_for_operation(&left, &right, ast_op); + let compat_res: (bool, LitTypeVariant) = + are_compatible_for_operation(&left, &right, ast_op); if !compat_res.0 { - return Err( - Box::new( - BErr::new( - BErrType::TypeError(BTypeErr::IncompatibleTypes { - first_type: left.result_type.to_string(), - second_type: right.result_type.to_string(), - operator: format!("{:?}", ast_op) - }), - self.get_current_file_name(), - self.current_token.clone() - ) - ) - ); + return Err(Box::new(BErr::new( + BErrType::TypeError(BTypeErr::IncompatibleTypes { + first_type: left.result_type.to_string(), + second_type: right.result_type.to_string(), + operator: format!("{:?}", ast_op), + }), + self.get_current_file_name(), + self.current_token.clone(), + ))); } let result_type: LitTypeVariant = compat_res.1; let left_expr: Expr = left.kind.unwrap_expr(); @@ -776,7 +794,13 @@ impl<'parser> Parser<'parser> { fn get_current_file_name(&mut self) -> String { if let Some(ctx_rc) = &mut self.ctx { - return ctx_rc.borrow_mut().current_file.as_ref().unwrap().name.clone() + return ctx_rc + .borrow_mut() + .current_file + .as_ref() + .unwrap() + .name + .clone(); } else { panic!("no file is selected"); }; @@ -817,7 +841,6 @@ impl<'parser> Parser<'parser> { StorageClass::GLOBAL, ); self.add_symbol_global(str_const_symbol); - println!("_L{}: .ascii \"{}\"", str_label, current_token.lexeme); Ok(AST::create_leaf( ASTKind::ExprAST(Expr::LitVal(LitValExpr { value: LitType::Str(current_token.lexeme.clone()), @@ -828,20 +851,31 @@ impl<'parser> Parser<'parser> { )) } TokenKind::T_IDENTIFIER => { + if !self.is_scope_global() { + return Err(Box::new(BErr::new(BErrType::TypeError(BTypeErr::InitializerNotAConstant { + lexeme: current_token.lexeme.clone() + }), current_file.clone(), current_token.clone()))); + } let sym_find_res: Option = if self.is_scope_func() { Some(self.find_symbol(¤t_token.lexeme).unwrap().0) } else { self.find_symbol_global(¤t_token.lexeme) }; if sym_find_res.is_none() { - return Err(Box::new(BErr::undefined_symbol(current_file.clone(), current_token.clone()))); + return Err(Box::new(BErr::undefined_symbol( + current_file.clone(), + current_token.clone(), + ))); } let id_index: usize = sym_find_res.unwrap(); let symbol: Symbol = if let Some(ctx_rc) = &mut self.ctx { let ctx_borrow = ctx_rc.borrow_mut(); ctx_borrow.sym_table.get_symbol(id_index).unwrap().clone() } else { - return Err(Box::new(BErr::undefined_symbol(current_file.clone(), current_token.clone()))) + return Err(Box::new(BErr::undefined_symbol( + current_file.clone(), + current_token.clone(), + ))); }; let curr_tok_kind: TokenKind = self.current_token.kind; if curr_tok_kind == TokenKind::T_LPAREN { @@ -866,9 +900,10 @@ impl<'parser> Parser<'parser> { self.token_match(TokenKind::T_RPAREN); Ok(group_expr.unwrap()) } - _ => { - Err(Box::new(BErr::unexpected_token(current_file.clone(), current_token.clone()))) - } + _ => Err(Box::new(BErr::unexpected_token( + current_file.clone(), + current_token.clone(), + ))), } } @@ -898,7 +933,10 @@ impl<'parser> Parser<'parser> { } let array_access_expr: AST = array_access_expr_result.ok().unwrap(); if indexed_symbol.sym_type != SymbolType::Array { - return Err(Box::new(BErr::nonsubsriptable_ident(current_file.clone(), sym_token.clone()))); + return Err(Box::new(BErr::nonsubsriptable_ident( + current_file.clone(), + sym_token.clone(), + ))); } _ = self.token_match(TokenKind::T_RBRACKET); Ok(AST::create_leaf( @@ -921,7 +959,10 @@ impl<'parser> Parser<'parser> { let current_file = self.get_current_file_name(); _ = self.token_match(TokenKind::T_LPAREN); if called_symbol.sym_type != SymbolType::Function { - return Err(Box::new(BErr::noncallable_ident(current_file.clone(), sym_token.clone()))); + return Err(Box::new(BErr::noncallable_ident( + current_file.clone(), + sym_token.clone(), + ))); } _ = self.token_match(TokenKind::T_RPAREN); // Allocating extra 16 bytes to store x29(Frame Pointer), and x30(Link Register). @@ -940,7 +981,7 @@ impl<'parser> Parser<'parser> { fn add_symbol_global(&mut self, sym: Symbol) -> Option { let insert_pos: Option = { if let Some(ctx_rc) = &mut self.ctx { - let mut ctx_borrow: std::cell::RefMut> = ctx_rc.borrow_mut(); + let mut ctx_borrow = ctx_rc.borrow_mut(); ctx_borrow.sym_table.insert(self.next_global_sym_pos, sym) } else { panic!("Can't add a new symbol globally"); @@ -953,7 +994,7 @@ impl<'parser> Parser<'parser> { fn add_symbol_local(&mut self, sym: Symbol) -> Option { let insert_pos: Option = { if let Some(ctx_rc) = &mut self.ctx { - let mut ctx_borrow: std::cell::RefMut> = ctx_rc.borrow_mut(); + let mut ctx_borrow = ctx_rc.borrow_mut(); ctx_borrow.sym_table.insert(self.next_local_sym_pos, sym) } else { panic!("Can't add a new symbol locally"); @@ -1044,4 +1085,4 @@ impl<'parser> Parser<'parser> { // REWRITE ALL THE TEST CASES #[cfg(test)] -mod tests {} \ No newline at end of file +mod tests {} diff --git a/src/symbol/sym.rs b/src/symbol/sym.rs index 7ba7a3a..ee4abfc 100644 --- a/src/symbol/sym.rs +++ b/src/symbol/sym.rs @@ -22,7 +22,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -use crate::types::LitTypeVariant; +use crate::types::{LitType, LitTypeVariant}; // The types of symbol names inside the symbol table #[derive(Debug, Clone, PartialEq, Eq, Copy)] @@ -48,6 +48,10 @@ pub struct Symbol { pub size: usize, // number of elements in the symbol pub class: StorageClass, pub local_offset: i32, // for locals, offset from the stack base pointer + + /// Default value this symbol has. This is only set when + /// the identifier is a global one. + pub default_value: Option } impl Symbol { @@ -59,6 +63,7 @@ impl Symbol { size: 1, class, local_offset: 0, + default_value: None } } @@ -71,6 +76,7 @@ impl Symbol { size: 0, // oooooh, scary class: StorageClass::GLOBAL, local_offset: 0, + default_value: None } } } \ No newline at end of file