lab 6
This commit is contained in:
@@ -63,13 +63,109 @@ impl fmt::Display for BinOp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_typed_expr(expr: UntypedExpr, symbols: &mut SymbolsTable) -> error::Result<TypedExpr> {
|
pub fn to_typed_expr(
|
||||||
|
expr: UntypedExpr,
|
||||||
|
optimize: bool,
|
||||||
|
symbols: &mut SymbolsTable,
|
||||||
|
) -> error::Result<TypedExpr> {
|
||||||
let expr = convert_to_typed_expr(expr, symbols)?;
|
let expr = convert_to_typed_expr(expr, symbols)?;
|
||||||
let expr = coerce_types(expr, symbols)?;
|
let expr = coerce_types(expr, symbols)?;
|
||||||
|
let expr = if optimize { optimize_expr(expr) } else { expr };
|
||||||
|
|
||||||
Ok(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(
|
fn convert_to_typed_expr(
|
||||||
expr: UntypedExpr,
|
expr: UntypedExpr,
|
||||||
symbols: &mut SymbolsTable,
|
symbols: &mut SymbolsTable,
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ pub enum Command {
|
|||||||
},
|
},
|
||||||
Gen {
|
Gen {
|
||||||
mode: GenMode,
|
mode: GenMode,
|
||||||
|
#[clap(short, long, default_value_t = false)]
|
||||||
|
optimize: bool,
|
||||||
input: PathBuf,
|
input: PathBuf,
|
||||||
output: PathBuf,
|
output: PathBuf,
|
||||||
output_symbols: PathBuf,
|
output_symbols: PathBuf,
|
||||||
|
|||||||
24
src/main.rs
24
src/main.rs
@@ -6,13 +6,12 @@ mod representation;
|
|||||||
mod symbols;
|
mod symbols;
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
|
use cli::GenMode;
|
||||||
|
use parse::parser::Parser;
|
||||||
use std::{
|
use std::{
|
||||||
io::{self, Write},
|
io::{self, Write},
|
||||||
path::Path,
|
path::Path,
|
||||||
};
|
};
|
||||||
|
|
||||||
use cli::GenMode;
|
|
||||||
use parse::parser::Parser;
|
|
||||||
use symbols::SymbolsTable;
|
use symbols::SymbolsTable;
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
@@ -34,11 +33,12 @@ fn main() -> anyhow::Result<()> {
|
|||||||
}
|
}
|
||||||
cli::Command::Gen {
|
cli::Command::Gen {
|
||||||
mode,
|
mode,
|
||||||
|
optimize,
|
||||||
input,
|
input,
|
||||||
output,
|
output,
|
||||||
output_symbols,
|
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(
|
fn gen_command(
|
||||||
mode: &GenMode,
|
mode: &GenMode,
|
||||||
|
optimize: bool,
|
||||||
input: &Path,
|
input: &Path,
|
||||||
output: &Path,
|
output: &Path,
|
||||||
output_symbols: &Path,
|
output_symbols: &Path,
|
||||||
@@ -58,7 +59,7 @@ fn gen_command(
|
|||||||
let mut parser = Parser::new(tokens);
|
let mut parser = Parser::new(tokens);
|
||||||
parser.parse()
|
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,
|
Ok(expr) => expr,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -71,8 +72,15 @@ fn gen_command(
|
|||||||
|
|
||||||
match mode {
|
match mode {
|
||||||
GenMode::Intermediate => {
|
GenMode::Intermediate => {
|
||||||
let intermediate_exprs =
|
let intermediate_exprs = representation::intermediate::to_intermediate_expr(
|
||||||
representation::intermediate::to_intermediate_expr(typed_expr, &mut symbols);
|
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)?;
|
util::print_intermediate_exprs(&intermediate_exprs, &mut writer)?;
|
||||||
}
|
}
|
||||||
GenMode::Postfix => {
|
GenMode::Postfix => {
|
||||||
@@ -97,7 +105,7 @@ fn sem_command(input: &Path, output_tree: &Path) -> Result<(), anyhow::Error> {
|
|||||||
let mut parser = Parser::new(tokens);
|
let mut parser = Parser::new(tokens);
|
||||||
parser.parse()
|
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 {
|
match res {
|
||||||
Ok(expr) => {
|
Ok(expr) => {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
use crate::ast::typed::Type;
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{typed::TypedExpr, BinOp},
|
ast::{typed::TypedExpr, BinOp},
|
||||||
symbols::{Symbol, SymbolsTable},
|
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(
|
fn to_intermediate_expr_inner(
|
||||||
expr: TypedExpr,
|
expr: TypedExpr,
|
||||||
|
reuse_symbols: bool,
|
||||||
symbols: &mut SymbolsTable,
|
symbols: &mut SymbolsTable,
|
||||||
intermediate_var_counter: &mut usize,
|
temp_var_counter: &mut usize,
|
||||||
exprs: &mut Vec<IntermediateExpr>,
|
exprs: &mut Vec<IntermediateExpr>,
|
||||||
|
temp_float_vars: &mut Vec<Symbol>,
|
||||||
|
temp_int_vars: &mut Vec<Symbol>,
|
||||||
) -> IntermediateValue {
|
) -> IntermediateValue {
|
||||||
let ty = expr.ty(symbols);
|
let ty = expr.ty(symbols);
|
||||||
|
|
||||||
@@ -49,12 +65,41 @@ fn to_intermediate_expr_inner(
|
|||||||
TypedExpr::Float { value, .. } => IntermediateValue::Float { value },
|
TypedExpr::Float { value, .. } => IntermediateValue::Float { value },
|
||||||
TypedExpr::Var { name, .. } => IntermediateValue::Var { name },
|
TypedExpr::Var { name, .. } => IntermediateValue::Var { name },
|
||||||
TypedExpr::BinOp { lhs, op, rhs, .. } => {
|
TypedExpr::BinOp { lhs, op, rhs, .. } => {
|
||||||
let lhs = to_intermediate_expr_inner(*lhs, symbols, intermediate_var_counter, exprs);
|
let lhs = to_intermediate_expr_inner(
|
||||||
let rhs = to_intermediate_expr_inner(*rhs, symbols, intermediate_var_counter, exprs);
|
*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));
|
if let IntermediateValue::Var { name } = lhs {
|
||||||
symbols.resolve_mut(&result).unwrap().ty = Some(ty);
|
free_temp_var(name, ty, temp_int_vars, temp_float_vars, symbols)
|
||||||
*intermediate_var_counter += 1;
|
}
|
||||||
|
|
||||||
|
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 {
|
exprs.push(IntermediateExpr::BinOp {
|
||||||
result,
|
result,
|
||||||
@@ -66,12 +111,28 @@ fn to_intermediate_expr_inner(
|
|||||||
IntermediateValue::Var { name: result }
|
IntermediateValue::Var { name: result }
|
||||||
}
|
}
|
||||||
TypedExpr::IntToFloat { value, .. } => {
|
TypedExpr::IntToFloat { value, .. } => {
|
||||||
let value =
|
let value = to_intermediate_expr_inner(
|
||||||
to_intermediate_expr_inner(*value, symbols, intermediate_var_counter, exprs);
|
*value,
|
||||||
|
reuse_symbols,
|
||||||
|
symbols,
|
||||||
|
temp_var_counter,
|
||||||
|
exprs,
|
||||||
|
temp_float_vars,
|
||||||
|
temp_int_vars,
|
||||||
|
);
|
||||||
|
|
||||||
let result = symbols.add(format!("#T{}", intermediate_var_counter));
|
if let IntermediateValue::Var { name: value } = value {
|
||||||
symbols.resolve_mut(&result).unwrap().ty = Some(ty);
|
free_temp_var(value, Type::Int, temp_int_vars, temp_float_vars, symbols)
|
||||||
*intermediate_var_counter += 1;
|
}
|
||||||
|
|
||||||
|
let result = allocate_temp_var(
|
||||||
|
ty,
|
||||||
|
reuse_symbols,
|
||||||
|
temp_var_counter,
|
||||||
|
temp_float_vars,
|
||||||
|
temp_int_vars,
|
||||||
|
symbols,
|
||||||
|
);
|
||||||
|
|
||||||
exprs.push(IntermediateExpr::IntToFloat { result, value });
|
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<IntermediateExpr> {
|
fn allocate_temp_var(
|
||||||
|
ty: Type,
|
||||||
|
reuse_symbols: bool,
|
||||||
|
temp_var_counter: &mut usize,
|
||||||
|
temp_float_vars: &mut Vec<Symbol>,
|
||||||
|
temp_int_vars: &mut Vec<Symbol>,
|
||||||
|
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<Symbol>,
|
||||||
|
temp_float_vars: &mut Vec<Symbol>,
|
||||||
|
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<IntermediateExpr> {
|
||||||
let mut exprs = Vec::new();
|
let mut exprs = Vec::new();
|
||||||
let mut intermediate_var_counter = 0;
|
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
|
exprs
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<String>) -> Symbol {
|
pub fn add(&mut self, symbol: impl Into<String>) -> Symbol {
|
||||||
let symbol = symbol.into();
|
let symbol = symbol.into();
|
||||||
if let hash_map::Entry::Vacant(e) = self.symbols.entry(symbol.clone()) {
|
if let hash_map::Entry::Vacant(e) = self.symbols.entry(symbol.clone()) {
|
||||||
|
|||||||
31
src/util.rs
31
src/util.rs
@@ -1,11 +1,42 @@
|
|||||||
|
use std::collections::HashSet;
|
||||||
use std::io;
|
use std::io;
|
||||||
|
|
||||||
|
use crate::representation::intermediate::IntermediateValue;
|
||||||
|
use crate::symbols::Symbol;
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{typed::TypedExpr, UntypedExpr},
|
ast::{typed::TypedExpr, UntypedExpr},
|
||||||
representation::intermediate::IntermediateExpr,
|
representation::intermediate::IntermediateExpr,
|
||||||
symbols::SymbolsTable,
|
symbols::SymbolsTable,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub fn collect_used_symbols(expr: &[IntermediateExpr]) -> Vec<Symbol> {
|
||||||
|
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(
|
pub fn print_intermediate_exprs(
|
||||||
exprs: &[IntermediateExpr],
|
exprs: &[IntermediateExpr],
|
||||||
writer: &mut impl io::Write,
|
writer: &mut impl io::Write,
|
||||||
|
|||||||
Reference in New Issue
Block a user