From 322a8faec7c51de33d4af9681f6bbaead6a77400 Mon Sep 17 00:00:00 2001 From: lionarius Date: Sun, 10 Nov 2024 10:33:24 +0300 Subject: [PATCH] lab 6 --- src/ast/mod.rs | 98 +++++++++++++++++++- src/cli.rs | 2 + src/main.rs | 24 +++-- src/representation/intermediate.rs | 139 ++++++++++++++++++++++++++--- src/symbols/mod.rs | 4 + src/util.rs | 31 +++++++ 6 files changed, 276 insertions(+), 22 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 661e5eb..45d341d 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -63,13 +63,109 @@ impl fmt::Display for BinOp { } } -pub fn to_typed_expr(expr: UntypedExpr, symbols: &mut SymbolsTable) -> error::Result { +pub fn to_typed_expr( + expr: UntypedExpr, + optimize: bool, + symbols: &mut SymbolsTable, +) -> error::Result { let expr = convert_to_typed_expr(expr, symbols)?; let expr = coerce_types(expr, symbols)?; + let expr = if optimize { optimize_expr(expr) } else { expr }; Ok(expr) } +fn optimize_expr(expr: TypedExpr) -> TypedExpr { + let expr = match expr { + TypedExpr::BinOp { lhs, rhs, op, span } => { + let lhs = optimize_expr(*lhs); + let rhs = optimize_expr(*rhs); + + match (lhs, rhs) { + (TypedExpr::Int { value: lhs, .. }, TypedExpr::Int { value: rhs, .. }) => { + TypedExpr::Int { + span, + value: match op { + BinOp::Add => lhs + rhs, + BinOp::Sub => lhs - rhs, + BinOp::Mul => lhs * rhs, + BinOp::Div => lhs / rhs, + }, + } + } + (TypedExpr::Float { value: lhs, .. }, TypedExpr::Float { value: rhs, .. }) => { + TypedExpr::Float { + span, + value: match op { + BinOp::Add => lhs + rhs, + BinOp::Sub => lhs - rhs, + BinOp::Mul => lhs * rhs, + BinOp::Div => lhs / rhs, + }, + } + } + (lhs, TypedExpr::Int { value: 0, .. }) + | (TypedExpr::Float { value: 0.0, .. }, lhs) + if matches!(op, BinOp::Add | BinOp::Sub) => + { + lhs + } + (lhs, TypedExpr::Int { value: 1, .. }) + | (lhs, TypedExpr::Float { value: 1.0, .. }) + if matches!(op, BinOp::Mul | BinOp::Div) => + { + lhs + } + (TypedExpr::Int { value: 0, .. }, rhs) + | (TypedExpr::Float { value: 0.0, .. }, rhs) + if matches!(op, BinOp::Add) => + { + rhs + } + (TypedExpr::Int { value: 1, .. }, rhs) + | (TypedExpr::Float { value: 1.0, .. }, rhs) + if matches!(op, BinOp::Mul) => + { + rhs + } + (TypedExpr::Int { value: 0, .. }, _) | (_, TypedExpr::Int { value: 0, .. }) + if matches!(op, BinOp::Mul) => + { + TypedExpr::Int { span, value: 0 } + } + (TypedExpr::Float { value: 0.0, .. }, _) + | (_, TypedExpr::Float { value: 0.0, .. }) + if matches!(op, BinOp::Mul) => + { + TypedExpr::Float { span, value: 0.0 } + } + (lhs, rhs) => TypedExpr::BinOp { + span, + lhs: Box::new(lhs), + op, + rhs: Box::new(rhs), + }, + } + } + TypedExpr::IntToFloat { value } => { + let value = optimize_expr(*value); + if let TypedExpr::Int { value, span } = value { + TypedExpr::Float { + span, + value: value as f64, + } + } else { + TypedExpr::IntToFloat { + value: Box::new(value), + } + } + } + expr => expr, + }; + + expr +} + fn convert_to_typed_expr( expr: UntypedExpr, symbols: &mut SymbolsTable, diff --git a/src/cli.rs b/src/cli.rs index 1b587a4..226c8f7 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -29,6 +29,8 @@ pub enum Command { }, Gen { mode: GenMode, + #[clap(short, long, default_value_t = false)] + optimize: bool, input: PathBuf, output: PathBuf, output_symbols: PathBuf, diff --git a/src/main.rs b/src/main.rs index 61f87f2..e2fa4fa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,13 +6,12 @@ mod representation; mod symbols; mod util; +use cli::GenMode; +use parse::parser::Parser; use std::{ io::{self, Write}, path::Path, }; - -use cli::GenMode; -use parse::parser::Parser; use symbols::SymbolsTable; fn main() -> anyhow::Result<()> { @@ -34,11 +33,12 @@ fn main() -> anyhow::Result<()> { } cli::Command::Gen { mode, + optimize, input, output, output_symbols, } => { - gen_command(mode, input, output, output_symbols)?; + gen_command(mode, *optimize, input, output, output_symbols)?; } } @@ -47,6 +47,7 @@ fn main() -> anyhow::Result<()> { fn gen_command( mode: &GenMode, + optimize: bool, input: &Path, output: &Path, output_symbols: &Path, @@ -58,7 +59,7 @@ fn gen_command( let mut parser = Parser::new(tokens); parser.parse() } - .and_then(|expr| ast::to_typed_expr(expr, &mut symbols)) + .and_then(|expr| ast::to_typed_expr(expr, optimize, &mut symbols)) { Ok(expr) => expr, Err(e) => { @@ -71,8 +72,15 @@ fn gen_command( match mode { GenMode::Intermediate => { - let intermediate_exprs = - representation::intermediate::to_intermediate_expr(typed_expr, &mut symbols); + let intermediate_exprs = representation::intermediate::to_intermediate_expr( + typed_expr, + optimize, + &mut symbols, + ); + + let used_symbols = util::collect_used_symbols(&intermediate_exprs); + symbols.retain(&used_symbols); + util::print_intermediate_exprs(&intermediate_exprs, &mut writer)?; } GenMode::Postfix => { @@ -97,7 +105,7 @@ fn sem_command(input: &Path, output_tree: &Path) -> Result<(), anyhow::Error> { let mut parser = Parser::new(tokens); parser.parse() } - .and_then(|expr| ast::to_typed_expr(expr, &mut symbols)); + .and_then(|expr| ast::to_typed_expr(expr, false, &mut symbols)); match res { Ok(expr) => { diff --git a/src/representation/intermediate.rs b/src/representation/intermediate.rs index c733985..58d8c50 100644 --- a/src/representation/intermediate.rs +++ b/src/representation/intermediate.rs @@ -1,5 +1,6 @@ use std::fmt; +use crate::ast::typed::Type; use crate::{ ast::{typed::TypedExpr, BinOp}, symbols::{Symbol, SymbolsTable}, @@ -36,11 +37,26 @@ pub enum IntermediateExpr { }, } +fn add_temp_var(temp_var_counter: &mut usize, ty: Type, symbols: &mut SymbolsTable) -> Symbol { + let result = symbols.add(format!("#T{}", temp_var_counter)); + { + let data = symbols.resolve_mut(&result).unwrap(); + data.ty = Some(ty); + data.temporary = true; + } + *temp_var_counter += 1; + + result +} + fn to_intermediate_expr_inner( expr: TypedExpr, + reuse_symbols: bool, symbols: &mut SymbolsTable, - intermediate_var_counter: &mut usize, + temp_var_counter: &mut usize, exprs: &mut Vec, + temp_float_vars: &mut Vec, + temp_int_vars: &mut Vec, ) -> IntermediateValue { let ty = expr.ty(symbols); @@ -49,12 +65,41 @@ fn to_intermediate_expr_inner( TypedExpr::Float { value, .. } => IntermediateValue::Float { value }, TypedExpr::Var { name, .. } => IntermediateValue::Var { name }, TypedExpr::BinOp { lhs, op, rhs, .. } => { - let lhs = to_intermediate_expr_inner(*lhs, symbols, intermediate_var_counter, exprs); - let rhs = to_intermediate_expr_inner(*rhs, symbols, intermediate_var_counter, exprs); + let lhs = to_intermediate_expr_inner( + *lhs, + reuse_symbols, + symbols, + temp_var_counter, + exprs, + temp_float_vars, + temp_int_vars, + ); + let rhs = to_intermediate_expr_inner( + *rhs, + reuse_symbols, + symbols, + temp_var_counter, + exprs, + temp_float_vars, + temp_int_vars, + ); - let result = symbols.add(format!("#T{}", intermediate_var_counter)); - symbols.resolve_mut(&result).unwrap().ty = Some(ty); - *intermediate_var_counter += 1; + if let IntermediateValue::Var { name } = lhs { + free_temp_var(name, ty, temp_int_vars, temp_float_vars, symbols) + } + + if let IntermediateValue::Var { name } = rhs { + free_temp_var(name, ty, temp_int_vars, temp_float_vars, symbols) + } + + let result = allocate_temp_var( + ty, + reuse_symbols, + temp_var_counter, + temp_float_vars, + temp_int_vars, + symbols, + ); exprs.push(IntermediateExpr::BinOp { result, @@ -66,12 +111,28 @@ fn to_intermediate_expr_inner( IntermediateValue::Var { name: result } } TypedExpr::IntToFloat { value, .. } => { - let value = - to_intermediate_expr_inner(*value, symbols, intermediate_var_counter, exprs); + let value = to_intermediate_expr_inner( + *value, + reuse_symbols, + symbols, + temp_var_counter, + exprs, + temp_float_vars, + temp_int_vars, + ); - let result = symbols.add(format!("#T{}", intermediate_var_counter)); - symbols.resolve_mut(&result).unwrap().ty = Some(ty); - *intermediate_var_counter += 1; + if let IntermediateValue::Var { name: value } = value { + free_temp_var(value, Type::Int, temp_int_vars, temp_float_vars, symbols) + } + + let result = allocate_temp_var( + ty, + reuse_symbols, + temp_var_counter, + temp_float_vars, + temp_int_vars, + symbols, + ); exprs.push(IntermediateExpr::IntToFloat { result, value }); @@ -80,11 +141,63 @@ fn to_intermediate_expr_inner( } } -pub fn to_intermediate_expr(expr: TypedExpr, symbols: &mut SymbolsTable) -> Vec { +fn allocate_temp_var( + ty: Type, + reuse_symbols: bool, + temp_var_counter: &mut usize, + temp_float_vars: &mut Vec, + temp_int_vars: &mut Vec, + symbols: &mut SymbolsTable, +) -> Symbol { + if reuse_symbols { + match ty { + Type::Int if !temp_int_vars.is_empty() => temp_int_vars.pop().unwrap(), + Type::Float if !temp_float_vars.is_empty() => temp_float_vars.pop().unwrap(), + _ => add_temp_var(temp_var_counter, ty, symbols), + } + } else { + add_temp_var(temp_var_counter, ty, symbols) + } +} + +fn free_temp_var( + name: Symbol, + ty: Type, + temp_int_vars: &mut Vec, + temp_float_vars: &mut Vec, + symbols: &mut SymbolsTable, +) { + let temporary = symbols.temporary(&name).unwrap(); + if !temporary { + return; + } + + if ty == Type::Int { + temp_int_vars.push(name); + } else { + temp_float_vars.push(name); + } +} + +pub fn to_intermediate_expr( + expr: TypedExpr, + reuse_symbols: bool, + symbols: &mut SymbolsTable, +) -> Vec { let mut exprs = Vec::new(); let mut intermediate_var_counter = 0; + let mut temp_float_vars = Vec::new(); + let mut temp_int_vars = Vec::new(); - to_intermediate_expr_inner(expr, symbols, &mut intermediate_var_counter, &mut exprs); + to_intermediate_expr_inner( + expr, + reuse_symbols, + symbols, + &mut intermediate_var_counter, + &mut exprs, + &mut temp_float_vars, + &mut temp_int_vars, + ); exprs } diff --git a/src/symbols/mod.rs b/src/symbols/mod.rs index 3e0edc9..0baa837 100644 --- a/src/symbols/mod.rs +++ b/src/symbols/mod.rs @@ -55,6 +55,10 @@ impl SymbolsTable { } } + pub fn retain(&mut self, symbols: &[Symbol]) { + self.symbols.retain(|_, data| symbols.contains(&data.id)); + } + pub fn add(&mut self, symbol: impl Into) -> Symbol { let symbol = symbol.into(); if let hash_map::Entry::Vacant(e) = self.symbols.entry(symbol.clone()) { diff --git a/src/util.rs b/src/util.rs index f5819d6..b9659dd 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,11 +1,42 @@ +use std::collections::HashSet; use std::io; +use crate::representation::intermediate::IntermediateValue; +use crate::symbols::Symbol; use crate::{ ast::{typed::TypedExpr, UntypedExpr}, representation::intermediate::IntermediateExpr, symbols::SymbolsTable, }; +pub fn collect_used_symbols(expr: &[IntermediateExpr]) -> Vec { + let mut used_symbols = HashSet::new(); + + for expr in expr { + match expr { + IntermediateExpr::IntToFloat { result, value } => { + used_symbols.insert(*result); + if let IntermediateValue::Var { name } = value { + used_symbols.insert(*name); + } + } + IntermediateExpr::BinOp { + result, lhs, rhs, .. + } => { + used_symbols.insert(*result); + if let IntermediateValue::Var { name } = lhs { + used_symbols.insert(*name); + } + if let IntermediateValue::Var { name } = rhs { + used_symbols.insert(*name); + } + } + } + } + + used_symbols.into_iter().collect() +} + pub fn print_intermediate_exprs( exprs: &[IntermediateExpr], writer: &mut impl io::Write,