feat(ir,backend,frontend): Support for and revise ir array param generate

This commit is contained in:
2026-06-07 22:26:23 +08:00
parent 55636e07af
commit b7c2924e8b
11 changed files with 508 additions and 67 deletions
+46 -1
View File
@@ -2,7 +2,7 @@ use petgraph::dot::{Config, Dot};
use petgraph::graph::{Graph, NodeIndex}; use petgraph::graph::{Graph, NodeIndex};
use crate::ast::types::{ use crate::ast::types::{
ArrayDimension, BlockStmt, BreakStmt, CompileUnit, ContinueStmt, Expr, ExprValue, FuncDeclStmt, GlobalDeclStmt, IfStmt, Param, ReturnStmt, Statement, VarDeclStmt, VarDeclStmtValue, WhileStmt ArrayDimension, BlockStmt, BreakStmt, CompileUnit, ContinueStmt, Expr, ExprValue, ForInit, ForStmt, FuncDeclStmt, GlobalDeclStmt, IfStmt, Param, ReturnStmt, Statement, VarDeclStmt, VarDeclStmtValue, WhileStmt
}; };
pub type AstGraph = Graph<String, String>; pub type AstGraph = Graph<String, String>;
@@ -77,6 +77,9 @@ impl AstGraphBuilder {
for dimension in &value.dimensions { for dimension in &value.dimensions {
self.add_array_dimension(node, dimension); self.add_array_dimension(node, dimension);
} }
if let Some(expr) = &value.value {
self.add_expr(node, expr);
}
node node
} }
@@ -134,6 +137,7 @@ impl AstGraphBuilder {
}, },
Statement::If(if_stmt) => self.add_if_stmt(parent, if_stmt), Statement::If(if_stmt) => self.add_if_stmt(parent, if_stmt),
Statement::While(while_stmt) => self.add_while_stmt(parent, while_stmt), Statement::While(while_stmt) => self.add_while_stmt(parent, while_stmt),
Statement::For(for_stmt) => self.add_for_stmt(parent, for_stmt),
Statement::Break(break_stmt) => self.add_break_stmt(parent, break_stmt), Statement::Break(break_stmt) => self.add_break_stmt(parent, break_stmt),
Statement::Continue(continue_stmt) => self.add_continue_stmt(parent, continue_stmt), Statement::Continue(continue_stmt) => self.add_continue_stmt(parent, continue_stmt),
} }
@@ -160,6 +164,42 @@ impl AstGraphBuilder {
self.add_block_stmt(node, &while_stmt.body); self.add_block_stmt(node, &while_stmt.body);
node node
} }
fn add_for_stmt(&mut self, parent: NodeIndex, for_stmt: &ForStmt) -> NodeIndex {
let node = self.child(parent, for_stmt.to_string());
match &for_stmt.init {
Some(ForInit::Expr(expr)) => {
let init = self.child(node, "Init");
self.add_expr(init, expr);
}
Some(ForInit::VarDecl(var_decl)) => {
let init = self.child(node, "Init");
self.add_var_decl(init, var_decl);
}
None => {
self.child(node, "NoInit");
}
}
match &for_stmt.condition {
Some(expr) => {
let condition = self.child(node, "Condition");
self.add_expr(condition, expr);
}
None => {
self.child(node, "NoCondition");
}
}
match &for_stmt.update {
Some(expr) => {
let update = self.child(node, "Update");
self.add_expr(update, expr);
}
None => {
self.child(node, "NoUpdate");
}
}
self.add_block_stmt(node, &for_stmt.body);
node
}
fn add_break_stmt(&mut self, parent: NodeIndex, break_stmt: &BreakStmt) -> NodeIndex { fn add_break_stmt(&mut self, parent: NodeIndex, break_stmt: &BreakStmt) -> NodeIndex {
self.child(parent, break_stmt.to_string()) self.child(parent, break_stmt.to_string())
} }
@@ -200,6 +240,11 @@ impl AstGraphBuilder {
self.add_expr(node, operand); self.add_expr(node, operand);
node node
} }
ExprValue::IncDec { operand, .. } => {
let node = self.child(parent, expr.value.to_string());
self.add_expr(node, operand);
node
}
} }
} }
} }
+170 -38
View File
@@ -1,6 +1,6 @@
use crate::{ use crate::{
ast::types::{ ast::types::{
ArrayDimension, BinaryOp, BlockStmt, BreakStmt, CompileUnit, ContinueStmt, Expr, ExprValue, FuncDeclStmt, GlobalDeclStmt, IfElseBranch, IfStmt, Param, ReturnStmt, Statement, UnaryOp, VarDeclStmt, VarDeclStmtValue, WhileStmt ArrayDimension, BinaryOp, BlockStmt, BreakStmt, CompileUnit, ContinueStmt, Expr, ExprValue, ForInit, ForStmt, FuncDeclStmt, GlobalDeclStmt, IfElseBranch, IfStmt, IncDecOp, Param, ReturnStmt, Statement, UnaryOp, VarDeclStmt, VarDeclStmtValue, WhileStmt
}, },
diagnostic::{Diagnositics, span::Span}, diagnostic::{Diagnositics, span::Span},
lexer::{ lexer::{
@@ -46,6 +46,9 @@ impl Parser {
fn peek(&self) -> &Token { fn peek(&self) -> &Token {
self.tokens.get(self.pos).unwrap_or(&self.eof_token) self.tokens.get(self.pos).unwrap_or(&self.eof_token)
} }
fn peek_n(&self, n: usize) -> &Token {
self.tokens.get(self.pos + n).unwrap_or(&self.eof_token)
}
fn next(&mut self) -> Token { fn next(&mut self) -> Token {
let token = self.peek().clone(); let token = self.peek().clone();
if !matches!(token.value, TokenValue::Eof) { if !matches!(token.value, TokenValue::Eof) {
@@ -294,6 +297,10 @@ impl Parser {
// } // }
// } // }
fn parse_var_decl_stmt(&mut self, parse_type: ParseType) -> Result<VarDeclStmt, ParseProcessError> { fn parse_var_decl_stmt(&mut self, parse_type: ParseType) -> Result<VarDeclStmt, ParseProcessError> {
self.parse_var_decl_stmt_inner(parse_type, true)
}
fn parse_var_decl_stmt_inner(&mut self, parse_type: ParseType, consume_semicolon: bool) -> Result<VarDeclStmt, ParseProcessError> {
assert!(!self.is_eof()); assert!(!self.is_eof());
let mut values = vec![]; let mut values = vec![];
let (var_type, name, type_span, name_span) = match self.parse_type_and_name(parse_type) { let (var_type, name, type_span, name_span) = match self.parse_type_and_name(parse_type) {
@@ -307,7 +314,13 @@ impl Parser {
} }
}; };
let dimensions = self.parse_array_dimensions(false)?; let dimensions = self.parse_array_dimensions(false)?;
values.push(VarDeclStmtValue { name, name_span, dimensions }); let value = if self.peek().value == TokenValue::Equal {
self.advance(1);
Some(self.parse_expr()?)
} else {
None
};
values.push(VarDeclStmtValue { name, name_span, dimensions, value });
let mut last_name = true; // indicate whether the last parsed token is a variable name let mut last_name = true; // indicate whether the last parsed token is a variable name
while !self.is_eof() { while !self.is_eof() {
if matches!(self.peek().value, TokenValue::Semicolon) { // statement end if matches!(self.peek().value, TokenValue::Semicolon) { // statement end
@@ -327,7 +340,13 @@ impl Parser {
if let Some(ident) = self.peek().value.as_ident() { if let Some(ident) = self.peek().value.as_ident() {
let span = self.next().span; let span = self.next().span;
let dimensions = self.parse_array_dimensions(false)?; let dimensions = self.parse_array_dimensions(false)?;
values.push(VarDeclStmtValue { name: ident, name_span: span, dimensions }); let value = if self.peek().value == TokenValue::Equal {
self.advance(1);
Some(self.parse_expr()?)
} else {
None
};
values.push(VarDeclStmtValue { name: ident, name_span: span, dimensions, value });
last_name = true; last_name = true;
} else { } else {
let token = self.next().clone(); let token = self.next().clone();
@@ -338,7 +357,9 @@ impl Parser {
return Err(ParseProcessError::ErrorInMatch); return Err(ParseProcessError::ErrorInMatch);
} }
} }
self.must_match_token(&TokenValue::Semicolon, "`;`")?; if consume_semicolon {
self.must_match_token(&TokenValue::Semicolon, "`;`")?;
}
Ok(VarDeclStmt { values, type_span, data_type: var_type.into() }) Ok(VarDeclStmt { values, type_span, data_type: var_type.into() })
} }
@@ -457,6 +478,11 @@ impl Parser {
Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch), Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
Err(_) => {}, Err(_) => {},
} }
match self.parse_for_stmt() {
Ok(for_stmt) => return Ok(Statement::For(for_stmt)),
Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
Err(_) => {},
}
match self.parse_break_stmt() { match self.parse_break_stmt() {
Ok(break_stmt) => return Ok(Statement::Break(break_stmt)), Ok(break_stmt) => return Ok(Statement::Break(break_stmt)),
Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch), Err(ParseProcessError::ErrorInMatch) => return Err(ParseProcessError::ErrorInMatch),
@@ -593,6 +619,48 @@ impl Parser {
}) })
} }
fn parse_for_stmt(&mut self) -> Result<ForStmt, ParseProcessError> {
assert!(!self.is_eof());
if self.peek().value != TokenValue::For {
return Err(ParseProcessError::TryNext);
}
self.advance(1);
self.must_match_token(&TokenValue::LParen, "`(`")?;
let init = if self.peek().value == TokenValue::Semicolon {
None
} else if matches!(self.peek().value, TokenValue::TypeIdent(_)) {
Some(ForInit::VarDecl(self.parse_var_decl_stmt_inner(ParseType::MustParse, false)?))
} else {
Some(ForInit::Expr(self.parse_expr()?))
};
self.must_match_token(&TokenValue::Semicolon, "`;`")?;
let condition = if self.peek().value == TokenValue::Semicolon {
None
} else {
Some(self.parse_expr()?)
};
self.must_match_token(&TokenValue::Semicolon, "`;`")?;
let update = if self.peek().value == TokenValue::RParen {
None
} else {
Some(self.parse_expr()?)
};
self.must_match_token(&TokenValue::RParen, "`)`")?;
let body;
if self.peek().value != TokenValue::LBrace {
let stmt = self.parse_stmt()?;
body = BlockStmt { statements: vec![stmt] };
} else {
body = self.parse_block_stmt(ParseType::MustParse)?;
}
Ok(ForStmt {
init,
condition,
update,
body,
})
}
fn parse_break_stmt(&mut self) -> Result<BreakStmt, ParseProcessError> { fn parse_break_stmt(&mut self) -> Result<BreakStmt, ParseProcessError> {
assert!(!self.is_eof()); assert!(!self.is_eof());
let start_span = self.peek().span; let start_span = self.peek().span;
@@ -747,41 +815,63 @@ impl Parser {
} }
fn parse_primary(&mut self) -> Result<Expr, ParseProcessError> { fn parse_primary(&mut self) -> Result<Expr, ParseProcessError> {
let mut expr = self.parse_primary_atom()?; let mut expr = self.parse_primary_atom()?;
while self.peek().value == TokenValue::LBracket { loop {
let start_span = expr.span; if self.peek().value == TokenValue::LBracket {
self.advance(1); let start_span = expr.span;
let index = if self.is_eof() { self.advance(1);
self.diagnostics.add_from_frontend_error(ParseError::ExpectButEof("array index expression"), start_span); let index = if self.is_eof() {
return Err(ParseProcessError::ErrorInMatch); self.diagnostics.add_from_frontend_error(ParseError::ExpectButEof("array index expression"), start_span);
} else { return Err(ParseProcessError::ErrorInMatch);
self.parse_expr()? } else {
}; self.parse_expr()?
let end_span = match &self.peek().value { };
TokenValue::RBracket => { let end_span = match &self.peek().value {
let span = self.peek().span; TokenValue::RBracket => {
self.advance(1); let span = self.peek().span;
span self.advance(1);
} span
TokenValue::Eof => { }
self.diagnostics.add_from_frontend_error(ParseError::ExpectButEof("`]`"), index.span); TokenValue::Eof => {
return Err(ParseProcessError::ErrorInMatch); self.diagnostics.add_from_frontend_error(ParseError::ExpectButEof("`]`"), index.span);
} return Err(ParseProcessError::ErrorInMatch);
_ => { }
let token = self.next(); _ => {
self.diagnostics.add_from_frontend_error( let token = self.next();
ParseError::UnexpectedToken(token.value, "`]`"), self.diagnostics.add_from_frontend_error(
token.span, ParseError::UnexpectedToken(token.value, "`]`"),
); token.span,
return Err(ParseProcessError::ErrorInMatch); );
} return Err(ParseProcessError::ErrorInMatch);
}; }
expr = Expr { };
value: ExprValue::ArrayAccess { expr = Expr {
array: Box::new(expr), value: ExprValue::ArrayAccess {
index: Box::new(index), array: Box::new(expr),
}, index: Box::new(index),
span: Span::from_two(start_span, end_span), },
span: Span::from_two(start_span, end_span),
};
continue;
}
let op = match (&self.peek().value, &self.peek_n(1).value) {
(TokenValue::Plus, TokenValue::Plus) => Some(IncDecOp::Inc),
(TokenValue::Minus, TokenValue::Minus) => Some(IncDecOp::Dec),
_ => None,
}; };
if let Some(op) = op {
let end_span = self.peek_n(1).span;
self.advance(2);
expr = Expr {
span: Span::from_two(expr.span, end_span),
value: ExprValue::IncDec {
op,
operand: Box::new(expr),
is_prefix: false,
},
};
continue;
}
break;
} }
Ok(expr) Ok(expr)
} }
@@ -790,6 +880,27 @@ impl Parser {
let token = self.peek().clone(); let token = self.peek().clone();
match token.value { match token.value {
TokenValue::Plus => { TokenValue::Plus => {
if self.peek_n(1).value == TokenValue::Plus {
self.advance(2);
let expr = if self.is_eof() {
self.diagnostics.add_from_frontend_error(
ParseError::ExpectButEof("expression"),
token.span,
);
return Err(ParseProcessError::ErrorInMatch);
} else {
self.parse_unary()?
};
let span = Span::from_two(token.span, expr.span);
return Ok(Expr {
value: ExprValue::IncDec {
op: IncDecOp::Inc,
operand: Box::new(expr),
is_prefix: true,
},
span,
});
}
self.advance(1); self.advance(1);
let expr = if self.is_eof() { let expr = if self.is_eof() {
self.diagnostics.add_from_frontend_error( self.diagnostics.add_from_frontend_error(
@@ -810,6 +921,27 @@ impl Parser {
}) })
} }
TokenValue::Minus => { TokenValue::Minus => {
if self.peek_n(1).value == TokenValue::Minus {
self.advance(2);
let rhs = if self.is_eof() {
self.diagnostics.add_from_frontend_error(
ParseError::ExpectButEof("expression"),
token.span,
);
return Err(ParseProcessError::ErrorInMatch);
} else {
self.parse_unary()?
};
let span = Span::from_two(token.span, rhs.span);
return Ok(Expr {
value: ExprValue::IncDec {
op: IncDecOp::Dec,
operand: Box::new(rhs),
is_prefix: true,
},
span,
});
}
self.advance(1); self.advance(1);
let rhs = if self.is_eof() { let rhs = if self.is_eof() {
self.diagnostics.add_from_frontend_error( self.diagnostics.add_from_frontend_error(
+38
View File
@@ -18,6 +18,7 @@ pub struct VarDeclStmtValue {
pub name: String, pub name: String,
pub name_span: Span, pub name_span: Span,
pub dimensions: Vec<ArrayDimension>, pub dimensions: Vec<ArrayDimension>,
pub value: Option<Expr>,
} }
pub struct ArrayDimension { pub struct ArrayDimension {
@@ -44,6 +45,7 @@ pub enum Statement {
VarDecl(VarDeclStmt), VarDecl(VarDeclStmt),
If(IfStmt), If(IfStmt),
While(WhileStmt), While(WhileStmt),
For(ForStmt),
Break(BreakStmt), Break(BreakStmt),
Continue(ContinueStmt), Continue(ContinueStmt),
} }
@@ -77,6 +79,16 @@ pub struct WhileStmt {
pub body: BlockStmt, pub body: BlockStmt,
// pub span: Span, // pub span: Span,
} }
pub struct ForStmt {
pub init: Option<ForInit>,
pub condition: Option<Expr>,
pub update: Option<Expr>,
pub body: BlockStmt,
}
pub enum ForInit {
Expr(Expr),
VarDecl(VarDeclStmt),
}
pub struct BreakStmt { pub struct BreakStmt {
pub span: Span, pub span: Span,
} }
@@ -107,6 +119,11 @@ pub enum ExprValue {
op: UnaryOp, op: UnaryOp,
operand: Box<Expr>, operand: Box<Expr>,
}, },
IncDec {
op: IncDecOp,
operand: Box<Expr>,
is_prefix: bool,
},
FuncCall(String, Vec<Expr>), FuncCall(String, Vec<Expr>),
Assign { Assign {
lvalue: Box<Expr>, lvalue: Box<Expr>,
@@ -124,6 +141,11 @@ pub enum BinaryOp {
pub enum UnaryOp { pub enum UnaryOp {
Add, Sub, Not, Add, Sub, Not,
} }
#[derive(Clone, Copy)]
pub enum IncDecOp {
Inc,
Dec,
}
impl BinaryOp { impl BinaryOp {
pub fn from_token_value(token_value: &TokenValue) -> Option<Self> { pub fn from_token_value(token_value: &TokenValue) -> Option<Self> {
match token_value { match token_value {
@@ -227,6 +249,7 @@ impl fmt::Display for Statement {
Statement::VarDecl(_) => write!(f, "VarDeclStmt"), Statement::VarDecl(_) => write!(f, "VarDeclStmt"),
Statement::If(_) => write!(f, "IfStmt"), Statement::If(_) => write!(f, "IfStmt"),
Statement::While(_) => write!(f, "WhileStmt"), Statement::While(_) => write!(f, "WhileStmt"),
Statement::For(_) => write!(f, "ForStmt"),
Statement::Break(_) => write!(f, "BreakStmt"), Statement::Break(_) => write!(f, "BreakStmt"),
Statement::Continue(_) => write!(f, "ContinueStmt"), Statement::Continue(_) => write!(f, "ContinueStmt"),
} }
@@ -249,6 +272,12 @@ impl fmt::Display for WhileStmt {
} }
} }
impl fmt::Display for ForStmt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ForStmt")
}
}
impl fmt::Display for BreakStmt { impl fmt::Display for BreakStmt {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "BreakStmt") write!(f, "BreakStmt")
@@ -277,6 +306,7 @@ impl fmt::Display for ExprValue {
ExprValue::FuncCall(name, _) => write!(f, "FuncCall({})", name), ExprValue::FuncCall(name, _) => write!(f, "FuncCall({})", name),
ExprValue::Assign { .. } => write!(f, "Assign"), ExprValue::Assign { .. } => write!(f, "Assign"),
ExprValue::UnaryOp { op, .. } => write!(f, "UnaryOp({})", op), ExprValue::UnaryOp { op, .. } => write!(f, "UnaryOp({})", op),
ExprValue::IncDec { op, is_prefix, .. } => write!(f, "{}{}", if *is_prefix { "Prefix" } else { "Postfix" }, op),
} }
} }
} }
@@ -317,6 +347,14 @@ impl fmt::Display for UnaryOp {
write!(f, "{}", op) write!(f, "{}", op)
} }
} }
impl fmt::Display for IncDecOp {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
IncDecOp::Inc => write!(f, "Inc"),
IncDecOp::Dec => write!(f, "Dec"),
}
}
}
impl fmt::Display for Type { impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
+18 -1
View File
@@ -78,6 +78,23 @@ fn emit_store_stack(src: Register, offset: i32, reg_allocator: &mut RegisterAllo
fn load_variable(variable: Variable, reg_allocator: &mut RegisterAllocator, var_index_to_stack_offset: &BTreeMap<usize, usize>, instrs: &mut Vec<ARMInstr>) -> RegisterAlloc { fn load_variable(variable: Variable, reg_allocator: &mut RegisterAllocator, var_index_to_stack_offset: &BTreeMap<usize, usize>, instrs: &mut Vec<ARMInstr>) -> RegisterAlloc {
if variable.data_type.is_array() { if variable.data_type.is_array() {
let var_alloc = reg_allocator.alloc(variable.clone()).expect("Ran out of registers"); let var_alloc = reg_allocator.alloc(variable.clone()).expect("Ran out of registers");
if variable.data_type.is_array_param() {
match variable.var_type {
VariableType::ParamTemp(param_index) => {
if param_index < ARG_REGS.len() {
instrs.push(MoveInstr::new_uncond(var_alloc.reg, RegisterOrImm::Reg(ARG_REGS[param_index])));
} else {
let stack_arg_offset = 8 + ((param_index - ARG_REGS.len()) * 4);
instrs.push(LoadInstr::new(var_alloc.reg, REG_FP, Some(RegisterOrImm::Imm(stack_arg_offset as i32))));
}
}
_ => {
let stack_offset = var_index_to_stack_offset.get(&variable.index).expect("Variable not declared");
emit_load_stack(var_alloc.reg, *stack_offset as i32, reg_allocator, instrs);
}
}
return var_alloc;
}
match variable.var_type { match variable.var_type {
VariableType::Global => { VariableType::Global => {
instrs.push(LoadPseudoInstr::new(var_alloc.reg, format!("global_var_{}", variable.index))); instrs.push(LoadPseudoInstr::new(var_alloc.reg, format!("global_var_{}", variable.index)));
@@ -213,7 +230,7 @@ impl Generator {
IRInstr::Store(addr, value) => self.emit_store(addr, value, &var_index_to_stack_offset), IRInstr::Store(addr, value) => self.emit_store(addr, value, &var_index_to_stack_offset),
IRInstr::Declare(variable) => { IRInstr::Declare(variable) => {
assert!(!encounter_entry, "Variable declarations must come before entry instruction"); assert!(!encounter_entry, "Variable declarations must come before entry instruction");
let size = variable.data_type.size_in_bytes(); let size = if variable.data_type.is_array_param() { 4 } else { variable.data_type.size_in_bytes() };
stack_size_needed = (stack_size_needed + size).next_multiple_of(ARM_STACK_ALIGNMENT); stack_size_needed = (stack_size_needed + size).next_multiple_of(ARM_STACK_ALIGNMENT);
var_index_to_stack_offset.insert(variable.index, stack_size_needed); var_index_to_stack_offset.insert(variable.index, stack_size_needed);
}, },
+121 -7
View File
@@ -1,6 +1,6 @@
use std::{collections::BTreeMap, vec}; use std::{collections::BTreeMap, vec};
use crate::{ir::types::{CmpOp, Function, IRInstr, IRType, MoveRValue, UnaryOp, Variable, VariableOrIntLit, VariableType}, sema::{analyzer::Analyzer as SemaAnalyzer, hir::{HirBlockStmt, HirBreakStmt, HirCompileUnit, HirContinueStmt, HirExpr, HirExprValue, HirFuncDeclStmt, HirGlobalDeclStmt, HirIfElseBranch, HirIfStmt, HirReturnStmt, HirStatement, HirVarDeclStmt, HirWhileStmt}, symbol::{FunctionId, SymbolId}}}; use crate::{ir::types::{BinaryOp as IRBinaryOp, CmpOp, Function, IRInstr, IRType, MoveRValue, UnaryOp, Variable, VariableOrIntLit, VariableType}, sema::{analyzer::Analyzer as SemaAnalyzer, hir::{HirBlockStmt, HirBreakStmt, HirCompileUnit, HirContinueStmt, HirExpr, HirExprValue, HirForInit, HirForStmt, HirFuncDeclStmt, HirGlobalDeclStmt, HirIfElseBranch, HirIfStmt, HirReturnStmt, HirStatement, HirVarDeclStmt, HirWhileStmt}, symbol::{FunctionId, SymbolId}}};
use crate::ast::types::BinaryOp as AstBinaryOp; use crate::ast::types::BinaryOp as AstBinaryOp;
use crate::ast::types::UnaryOp as AstUnaryOp; use crate::ast::types::UnaryOp as AstUnaryOp;
pub struct Generator<'a> { pub struct Generator<'a> {
@@ -64,11 +64,24 @@ impl<'a> Generator<'a> {
fn generate_var_decl(&mut self, var_decl: HirVarDeclStmt, is_global: bool) -> Vec<IRInstr> { fn generate_var_decl(&mut self, var_decl: HirVarDeclStmt, is_global: bool) -> Vec<IRInstr> {
let mut instrs = vec![]; let mut instrs = vec![];
let var_type = if is_global { VariableType::Global } else { VariableType::Local };
for value in var_decl.values { for value in var_decl.values {
let var_type = if is_global { VariableType::Global } else { VariableType::Local };
let var = self.var_manager.declare_symbol(value.symbol, var_type, self.sema.get_symbol_type(value.symbol).into()); let var = self.var_manager.declare_symbol(value.symbol, var_type, self.sema.get_symbol_type(value.symbol).into());
if is_global { if is_global {
instrs.push(IRInstr::Declare(var)); instrs.push(IRInstr::Declare(var));
} else if let Some(init) = value.value {
self.current_exit_label.push(None);
let (init_instrs, init_var) = match self.generate_expr(init) {
Some(res) => res,
None => {
self.current_exit_label.pop();
continue;
}
};
self.current_exit_label.pop();
let target = self.var_manager.get_symbol(value.symbol).unwrap();
instrs.extend(init_instrs);
instrs.push(IRInstr::Move(target, MoveRValue::Var(init_var.unwrap())));
} }
} }
@@ -125,6 +138,7 @@ impl<'a> Generator<'a> {
Return(return_stmt) => self.generate_return_stmt(return_stmt), Return(return_stmt) => self.generate_return_stmt(return_stmt),
If(if_stmt) => self.generate_if_stmt(if_stmt), If(if_stmt) => self.generate_if_stmt(if_stmt),
While(while_stmt) => self.generate_while_stmt(while_stmt), While(while_stmt) => self.generate_while_stmt(while_stmt),
For(for_stmt) => self.generate_for_stmt(for_stmt),
Break(break_stmt) => self.generate_break_stmt(break_stmt), Break(break_stmt) => self.generate_break_stmt(break_stmt),
Continue(continue_stmt) => self.generate_continue_stmt(continue_stmt), Continue(continue_stmt) => self.generate_continue_stmt(continue_stmt),
Block(block_stmt) => { Block(block_stmt) => {
@@ -193,6 +207,69 @@ impl<'a> Generator<'a> {
instrs.push(IRInstr::Label(exit_label)); instrs.push(IRInstr::Label(exit_label));
instrs instrs
} }
fn generate_for_stmt(&mut self, for_stmt: HirForStmt) -> Vec<IRInstr> {
let mut instrs = vec![];
let cond_label = self.request_label();
let body_label = self.request_label();
let update_label = self.request_label();
let exit_label = self.request_label();
if let Some(init) = for_stmt.init {
match init {
HirForInit::Expr(init) => {
self.current_exit_label.push(None);
let (init_instrs, _) = match self.generate_expr(init) {
Some(res) => res,
None => {
self.current_exit_label.pop();
return vec![];
}
};
self.current_exit_label.pop();
instrs.extend(init_instrs);
}
HirForInit::VarDecl(var_decl) => {
instrs.extend(self.generate_var_decl(var_decl, false));
}
}
}
instrs.push(IRInstr::Label(cond_label));
if let Some(condition) = for_stmt.condition {
self.current_exit_label.push(Some((body_label, exit_label)));
let (cond_instrs, _) = match self.generate_expr(condition) {
Some(res) => res,
None => {
self.current_exit_label.pop();
return vec![];
}
};
self.current_exit_label.pop();
instrs.extend(cond_instrs);
}
instrs.push(IRInstr::Label(body_label));
self.while_exit_label.push((update_label, exit_label));
instrs.extend(self.generate_block_stmt(for_stmt.body));
self.while_exit_label.pop();
instrs.push(IRInstr::Label(update_label));
if let Some(update) = for_stmt.update {
self.current_exit_label.push(None);
let (update_instrs, _) = match self.generate_expr(update) {
Some(res) => res,
None => {
self.current_exit_label.pop();
return vec![];
}
};
self.current_exit_label.pop();
instrs.extend(update_instrs);
}
instrs.push(IRInstr::Goto(cond_label));
instrs.push(IRInstr::Label(exit_label));
instrs
}
fn generate_if_stmt(&mut self, if_stmt: HirIfStmt) -> Vec<IRInstr> { fn generate_if_stmt(&mut self, if_stmt: HirIfStmt) -> Vec<IRInstr> {
let mut instrs = vec![]; let mut instrs = vec![];
let then_label = self.request_label(); let then_label = self.request_label();
@@ -274,9 +351,13 @@ impl<'a> Generator<'a> {
HirExprValue::Var(symbol) => { HirExprValue::Var(symbol) => {
let var = self.var_manager.get_symbol(symbol).unwrap(); let var = self.var_manager.get_symbol(symbol).unwrap();
if var.data_type.is_array() { if var.data_type.is_array() {
let ptr_ty = var.data_type.decay_to_ptr().unwrap(); if var.data_type.is_array_param() {
let dest = self.var_manager.declare_temp(ptr_ty); (vec![], Some(var))
(vec![IRInstr::Move(dest.clone(), MoveRValue::Var(var))], Some(dest)) } else {
let ptr_ty = var.data_type.decay_to_ptr().unwrap();
let dest = self.var_manager.declare_temp(ptr_ty);
(vec![IRInstr::Move(dest.clone(), MoveRValue::Var(var))], Some(dest))
}
} else { } else {
(vec![], Some(var)) (vec![], Some(var))
} }
@@ -372,6 +453,35 @@ impl<'a> Generator<'a> {
}; };
(instrs, Some(dest_var)) (instrs, Some(dest_var))
}, },
HirExprValue::IncDec { op, operand, is_prefix } => {
let result_ty: IRType = expr.ty.clone().into();
let (mut instrs, target, is_addr) = self.generate_lvalue(*operand)?;
let old_var = self.var_manager.declare_temp(result_ty.clone());
if is_addr {
instrs.push(IRInstr::Load(old_var.clone(), target.clone()));
} else {
instrs.push(IRInstr::Move(old_var.clone(), MoveRValue::Var(target.clone())));
}
let one = self.var_manager.declare_temp(result_ty.clone());
instrs.push(IRInstr::Move(one.clone(), MoveRValue::ConstInt(1)));
let new_var = self.var_manager.declare_temp(result_ty.clone());
let ir_op = match op {
crate::ast::types::IncDecOp::Inc => IRBinaryOp::Add,
crate::ast::types::IncDecOp::Dec => IRBinaryOp::Sub,
};
instrs.push(IRInstr::Binary(new_var.clone(), old_var.clone(), ir_op, one));
if is_addr {
instrs.push(IRInstr::Store(target, new_var.clone()));
} else {
instrs.push(IRInstr::Move(target, MoveRValue::Var(new_var.clone())));
}
if is_prefix {
(instrs, Some(new_var))
} else {
(instrs, Some(old_var))
}
},
HirExprValue::BinaryOp { lhs, op, rhs } => { HirExprValue::BinaryOp { lhs, op, rhs } => {
// +--------+-------------------------+-------------------------+-------------------------+ // +--------+-------------------------+-------------------------+-------------------------+
// | parent | (true_exit, false_exit) | (true_exit, false_exit) | (true_exit, false_exit) | // | parent | (true_exit, false_exit) | (true_exit, false_exit) | (true_exit, false_exit) |
@@ -564,8 +674,12 @@ impl<'a> Generator<'a> {
HirExprValue::Var(symbol) => { HirExprValue::Var(symbol) => {
let var = self.var_manager.get_symbol(symbol).unwrap(); let var = self.var_manager.get_symbol(symbol).unwrap();
if var.data_type.is_array() { if var.data_type.is_array() {
let ptr = self.var_manager.declare_temp(var.data_type.decay_to_ptr().unwrap()); if var.data_type.is_array_param() {
(vec![IRInstr::Move(ptr.clone(), MoveRValue::Var(var))], ptr) (vec![], var)
} else {
let ptr = self.var_manager.declare_temp(var.data_type.decay_to_ptr().unwrap());
(vec![IRInstr::Move(ptr.clone(), MoveRValue::Var(var))], ptr)
}
} else { } else {
(vec![], var) (vec![], var)
} }
+17 -1
View File
@@ -86,6 +86,10 @@ impl IRType {
matches!(self, IRType::Array(_, _)) matches!(self, IRType::Array(_, _))
} }
pub fn is_array_param(&self) -> bool {
matches!(self, IRType::Array(_, dims) if dims.first().is_some_and(|dim| *dim == 0))
}
pub fn decay_to_ptr(&self) -> Option<IRType> { pub fn decay_to_ptr(&self) -> Option<IRType> {
match self { match self {
IRType::Array(elem, dims) => { IRType::Array(elem, dims) => {
@@ -236,6 +240,18 @@ impl Variable {
_ => format!("{} {}", self.data_type, self), _ => format!("{} {}", self.data_type, self),
} }
} }
pub fn to_typed_string_with_type(&self, ty: &IRType) -> String {
match ty {
IRType::Array(_, _) => {
let (base_type, dims) = ty.base_type_and_dims();
let dims_str = dims.iter().map(|dim| format!("[{}]", dim)).collect::<Vec<_>>().join("");
format!("{} {}{}", base_type, self, dims_str)
}
IRType::Ptr(_) => format!("{}* {}", ty.scalar_base_type(), self),
_ => format!("{} {}", ty, self),
}
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Function { pub struct Function {
@@ -247,7 +263,7 @@ pub struct Function {
impl Function { impl Function {
pub fn to_call_string(&self, args: &Vec<Variable>) -> String { pub fn to_call_string(&self, args: &Vec<Variable>) -> String {
assert!(args.len() == self.parameter_types.len()); assert!(args.len() == self.parameter_types.len());
let args_str = args.iter().zip(self.parameter_types.iter()).map(|(arg, param)| format!("{} {}", param, arg)).collect::<Vec<_>>().join(", "); let args_str = args.iter().zip(self.parameter_types.iter()).map(|(arg, param)| arg.to_typed_string_with_type(param)).collect::<Vec<_>>().join(", ");
format!("{} @{}({})", self.return_type, self.name, args_str) format!("{} @{}({})", self.return_type, self.name, args_str)
} }
+3
View File
@@ -345,6 +345,9 @@ fn parse_ident(
if name.eq("while") { if name.eq("while") {
return Ok(TokenValue::While); return Ok(TokenValue::While);
} }
if name.eq("for") {
return Ok(TokenValue::For);
}
if name.eq("break") { if name.eq("break") {
return Ok(TokenValue::Break); return Ok(TokenValue::Break);
} }
+3 -2
View File
@@ -24,7 +24,7 @@ pub enum TokenValue {
LBracket, RBracket, LBracket, RBracket,
Comma, Semicolon, Comma, Semicolon,
If, Else, While, Return, Break, Continue, If, Else, While, For, Return, Break, Continue,
Eof, Eof,
Unrecognized, Unrecognized,
@@ -77,6 +77,7 @@ impl std::fmt::Display for TokenValue {
TokenValue::If => write!(f, "if"), TokenValue::If => write!(f, "if"),
TokenValue::Else => write!(f, "else"), TokenValue::Else => write!(f, "else"),
TokenValue::While => write!(f, "while"), TokenValue::While => write!(f, "while"),
TokenValue::For => write!(f, "for"),
TokenValue::Return => write!(f, "return"), TokenValue::Return => write!(f, "return"),
TokenValue::Break => write!(f, "break"), TokenValue::Break => write!(f, "break"),
TokenValue::Continue => write!(f, "continue"), TokenValue::Continue => write!(f, "continue"),
@@ -100,7 +101,7 @@ pub enum TokenKind {
LBracket, RBracket, LBracket, RBracket,
Comma, Semicolon, Comma, Semicolon,
If, Else, While, Return, Break, Continue, If, Else, While, For, Return, Break, Continue,
Eof, Eof,
Unrecognized, Unrecognized,
+71 -17
View File
@@ -2,7 +2,7 @@ use std::collections::BTreeMap;
use crate::{ use crate::{
ast::types::{ ast::types::{
ArrayDimension, BinaryOp, BlockStmt, BreakStmt, CompileUnit, ContinueStmt, Expr, ExprValue, FuncDeclStmt, ArrayDimension, BinaryOp, BlockStmt, BreakStmt, CompileUnit, ContinueStmt, Expr, ExprValue, ForInit, ForStmt, FuncDeclStmt,
GlobalDeclStmt, IfElseBranch, IfStmt, ReturnStmt, Statement, VarDeclStmt, WhileStmt, GlobalDeclStmt, IfElseBranch, IfStmt, ReturnStmt, Statement, VarDeclStmt, WhileStmt,
}, },
diagnostic::{span::Span, Diagnositics}, diagnostic::{span::Span, Diagnositics},
@@ -10,7 +10,7 @@ use crate::{
err::SemaError, err::SemaError,
hir::{ hir::{
HirBlockStmt, HirBreakStmt, HirCompileUnit, HirContinueStmt, HirExpr, HirExprValue, HirBlockStmt, HirBreakStmt, HirCompileUnit, HirContinueStmt, HirExpr, HirExprValue,
HirFuncDeclStmt, HirGlobalDeclStmt, HirIfElseBranch, HirIfStmt, HirParam, HirForInit, HirForStmt, HirFuncDeclStmt, HirGlobalDeclStmt, HirIfElseBranch, HirIfStmt, HirParam,
HirReturnStmt, HirStatement, HirVarDeclStmt, HirVarDeclStmtValue, HirWhileStmt, HirReturnStmt, HirStatement, HirVarDeclStmt, HirVarDeclStmtValue, HirWhileStmt,
}, },
symbol::{FunctionId, FunctionSig, SymbolId, SymbolKind, SymbolTable}, symbol::{FunctionId, FunctionSig, SymbolId, SymbolKind, SymbolTable},
@@ -39,7 +39,9 @@ impl Analyzer {
}; };
analyzer.declare_builtin_func("putint", vec![SemaType::I32], SemaType::Void); analyzer.declare_builtin_func("putint", vec![SemaType::I32], SemaType::Void);
analyzer.declare_builtin_func("putch", vec![SemaType::I32], SemaType::Void); analyzer.declare_builtin_func("putch", vec![SemaType::I32], SemaType::Void);
analyzer.declare_builtin_func("putarray", vec![SemaType::I32, SemaType::Array(Box::new(SemaType::I32), vec![0])], SemaType::Void);
analyzer.declare_builtin_func("getint", vec![], SemaType::I32); analyzer.declare_builtin_func("getint", vec![], SemaType::I32);
analyzer.declare_builtin_func("getarray", vec![SemaType::Array(Box::new(SemaType::I32), vec![0])], SemaType::I32);
analyzer analyzer
} }
@@ -102,10 +104,24 @@ impl Analyzer {
for value in var_decl.values { for value in var_decl.values {
let data_type = self.build_var_type(base_type.clone(), &value.dimensions, false); let data_type = self.build_var_type(base_type.clone(), &value.dimensions, false);
match self.symbols.declare_variable(&value.name, kind, data_type) { match self.symbols.declare_variable(&value.name, kind, data_type) {
Ok(symbol) => values.push(HirVarDeclStmtValue { Ok(symbol) => {
symbol, let symbol_type = self.symbols.get_symbol(symbol).ty.clone();
name_span: value.name_span, let init = value.value.and_then(|expr| {
}), let span = expr.span;
let init = self.analyze_expr(expr)?;
if init.ty == SemaType::Void {
self.add_error(SemaError::InvalidOperand(SemaType::Void), span);
} else if !self.type_matches(&symbol_type, &init.ty) {
self.add_error(SemaError::TypeMismatch(symbol_type.clone(), init.ty.clone()), span);
}
Some(init)
});
values.push(HirVarDeclStmtValue {
symbol,
name_span: value.name_span,
value: init,
});
}
Err(e) => self.add_error(e, value.name_span), Err(e) => self.add_error(e, value.name_span),
} }
} }
@@ -185,20 +201,11 @@ impl Analyzer {
self.add_error(SemaError::InvalidArrayDimension, dimension.span); self.add_error(SemaError::InvalidArrayDimension, dimension.span);
} }
} }
None if is_param && i == 0 => {} None if is_param && i == 0 => dims.push(0),
None => self.add_error(SemaError::InvalidArrayDimension, dimension.span), None => self.add_error(SemaError::InvalidArrayDimension, dimension.span),
} }
} }
if is_param { SemaType::Array(Box::new(base_type), dims)
let pointee_type = if dims.is_empty() {
base_type
} else {
SemaType::Array(Box::new(base_type), dims)
};
SemaType::Ptr(Box::new(pointee_type))
} else {
SemaType::Array(Box::new(base_type), dims)
}
} }
fn analyze_block_stmt(&mut self, block_stmt: BlockStmt) -> HirBlockStmt { fn analyze_block_stmt(&mut self, block_stmt: BlockStmt) -> HirBlockStmt {
@@ -216,6 +223,7 @@ impl Analyzer {
Statement::Return(stmt) => Some(HirStatement::Return(self.analyze_return_stmt(stmt))), Statement::Return(stmt) => Some(HirStatement::Return(self.analyze_return_stmt(stmt))),
Statement::If(stmt) => Some(HirStatement::If(self.analyze_if_stmt(stmt))), Statement::If(stmt) => Some(HirStatement::If(self.analyze_if_stmt(stmt))),
Statement::While(stmt) => Some(HirStatement::While(self.analyze_while_stmt(stmt))), Statement::While(stmt) => Some(HirStatement::While(self.analyze_while_stmt(stmt))),
Statement::For(stmt) => Some(HirStatement::For(self.analyze_for_stmt(stmt))),
Statement::Break(stmt) => Some(HirStatement::Break(self.analyze_break_stmt(stmt))), Statement::Break(stmt) => Some(HirStatement::Break(self.analyze_break_stmt(stmt))),
Statement::Continue(stmt) => Some(HirStatement::Continue(self.analyze_continue_stmt(stmt))), Statement::Continue(stmt) => Some(HirStatement::Continue(self.analyze_continue_stmt(stmt))),
Statement::Block(stmt) => { Statement::Block(stmt) => {
@@ -294,6 +302,26 @@ impl Analyzer {
} }
} }
fn analyze_for_stmt(&mut self, for_stmt: ForStmt) -> HirForStmt {
self.symbols.enter_scope();
let init = for_stmt.init.and_then(|init| match init {
ForInit::Expr(expr) => self.analyze_expr(expr).map(HirForInit::Expr),
ForInit::VarDecl(var_decl) => Some(HirForInit::VarDecl(self.analyze_var_decl(var_decl, SymbolKind::Local))),
});
let condition = for_stmt.condition.map(|expr| self.analyze_condition_expr(expr));
let update = for_stmt.update.and_then(|expr| self.analyze_expr(expr));
self.loop_depth += 1;
let body = self.analyze_block_stmt(for_stmt.body);
self.loop_depth -= 1;
self.symbols.exit_scope();
HirForStmt {
init,
condition,
update,
body,
}
}
fn analyze_break_stmt(&mut self, stmt: BreakStmt) -> HirBreakStmt { fn analyze_break_stmt(&mut self, stmt: BreakStmt) -> HirBreakStmt {
if self.loop_depth == 0 { if self.loop_depth == 0 {
self.add_error(SemaError::BreakOutsideLoop, stmt.span); self.add_error(SemaError::BreakOutsideLoop, stmt.span);
@@ -369,6 +397,27 @@ impl Analyzer {
span, span,
}) })
} }
ExprValue::IncDec { op, operand, is_prefix } => {
if !matches!(operand.value, ExprValue::Var(_) | ExprValue::ArrayAccess { .. }) {
self.add_error(SemaError::InvalidAssignmentTarget, operand.span);
return None;
}
let operand_span = operand.span;
let operand = self.analyze_expr(*operand)?;
if !operand.ty.is_scalar() {
self.add_error(SemaError::InvalidOperand(operand.ty.clone()), operand_span);
return None;
}
Some(HirExpr {
ty: operand.ty.clone(),
value: HirExprValue::IncDec {
op,
operand: Box::new(operand),
is_prefix,
},
span,
})
}
ExprValue::BinaryOp { lhs, op, rhs } => self.analyze_binary_expr(*lhs, op, *rhs, span), ExprValue::BinaryOp { lhs, op, rhs } => self.analyze_binary_expr(*lhs, op, *rhs, span),
ExprValue::FuncCall(func_name, args) => self.analyze_func_call_expr(func_name, args, span), ExprValue::FuncCall(func_name, args) => self.analyze_func_call_expr(func_name, args, span),
} }
@@ -524,6 +573,11 @@ impl Analyzer {
if expected == actual { if expected == actual {
return true; return true;
} }
if let (SemaType::Array(expected_elem, expected_dims), SemaType::Array(actual_elem, actual_dims)) = (expected, actual) {
return expected_elem == actual_elem
&& expected_dims.len() == actual_dims.len()
&& expected_dims.iter().zip(actual_dims.iter()).all(|(expected_dim, actual_dim)| *expected_dim == 0 || expected_dim == actual_dim);
}
matches!((expected, actual), (SemaType::Ptr(expected_elem), SemaType::Array(_, _)) if actual.indexed_type().is_some_and(|ty| &ty == expected_elem.as_ref())) matches!((expected, actual), (SemaType::Ptr(expected_elem), SemaType::Array(_, _)) if actual.indexed_type().is_some_and(|ty| &ty == expected_elem.as_ref()))
} }
} }
+19
View File
@@ -18,6 +18,7 @@ pub struct HirVarDeclStmt {
pub struct HirVarDeclStmtValue { pub struct HirVarDeclStmtValue {
pub symbol: SymbolId, pub symbol: SymbolId,
pub name_span: Span, pub name_span: Span,
pub value: Option<HirExpr>,
} }
pub struct HirFuncDeclStmt { pub struct HirFuncDeclStmt {
@@ -46,6 +47,7 @@ pub enum HirStatement {
VarDecl(HirVarDeclStmt), VarDecl(HirVarDeclStmt),
If(HirIfStmt), If(HirIfStmt),
While(HirWhileStmt), While(HirWhileStmt),
For(HirForStmt),
Break(HirBreakStmt), Break(HirBreakStmt),
Continue(HirContinueStmt), Continue(HirContinueStmt),
} }
@@ -67,6 +69,18 @@ pub struct HirWhileStmt {
pub body: HirBlockStmt, pub body: HirBlockStmt,
} }
pub struct HirForStmt {
pub init: Option<HirForInit>,
pub condition: Option<HirExpr>,
pub update: Option<HirExpr>,
pub body: HirBlockStmt,
}
pub enum HirForInit {
Expr(HirExpr),
VarDecl(HirVarDeclStmt),
}
pub struct HirBreakStmt { pub struct HirBreakStmt {
pub span: Span, pub span: Span,
} }
@@ -102,6 +116,11 @@ pub enum HirExprValue {
op: UnaryOp, op: UnaryOp,
operand: Box<HirExpr>, operand: Box<HirExpr>,
}, },
IncDec {
op: crate::ast::types::IncDecOp,
operand: Box<HirExpr>,
is_prefix: bool,
},
FuncCall(FunctionId, Vec<HirExpr>), FuncCall(FunctionId, Vec<HirExpr>),
Assign { Assign {
lvalue: Box<HirExpr>, lvalue: Box<HirExpr>,
+2
View File
@@ -35,6 +35,8 @@ impl SemaType {
SemaType::Array(elem, dims) => { SemaType::Array(elem, dims) => {
if dims.len() == 1 { if dims.len() == 1 {
Some((**elem).clone()) Some((**elem).clone())
} else if dims.first().is_some_and(|dim| *dim == 0) {
Some(SemaType::Array(elem.clone(), dims[1..].to_vec()))
} else { } else {
Some(SemaType::Array(elem.clone(), dims[1..].to_vec())) Some(SemaType::Array(elem.clone(), dims[1..].to_vec()))
} }