diff --git a/src/cli.rs b/src/cli.rs index 3838520..edbef5f 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -27,6 +27,20 @@ pub enum Command { input: PathBuf, output_tree: PathBuf, }, + Gen { + mode: GenMode, + input: PathBuf, + output: PathBuf, + output_symbols: PathBuf, + }, +} + +#[derive(Copy, Clone, PartialEq, Eq, clap::ValueEnum)] +pub enum GenMode { + #[clap(name = "intermediate", alias = "i")] + Intermediate, + #[clap(name = "postfix", alias = "p")] + Postfix, } impl Args { @@ -60,6 +74,12 @@ fn validate_inner(args: ArgsInner) -> Result { } => validate_lex(input, output_tokens, output_symbols)?, Command::Syn { input, output_tree } => validate_syn(input, output_tree)?, Command::Sem { input, output_tree } => validate_sem(input, output_tree)?, + Command::Gen { + mode, + input, + output, + output_symbols, + } => validate_gen(mode, input, output, output_symbols)?, }; Ok(args) @@ -129,3 +149,33 @@ fn validate_sem(input: &PathBuf, output_tree: &PathBuf) -> Result<(), clap::Erro Ok(()) } + +fn validate_gen( + _mode: &GenMode, + input: &PathBuf, + output: &PathBuf, + output_symbols: &PathBuf, +) -> Result<(), clap::Error> { + if !input.is_file() { + return Err(clap::Error::raw( + clap::error::ErrorKind::InvalidValue, + format!("Input file '{}' does not exist", input.display()), + )); + } + + if input == output { + return Err(clap::Error::raw( + clap::error::ErrorKind::InvalidValue, + "Input and output files cannot be the same", + )); + }; + + if input == output_symbols { + return Err(clap::Error::raw( + clap::error::ErrorKind::InvalidValue, + "Input and output files cannot be the same", + )); + }; + + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index 7c4bd2b..a3ef37f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,107 +2,19 @@ mod ast; mod cli; mod error; mod parse; +mod representation; mod symbols; +mod util; -use std::io::{self, Write}; +use std::{ + io::{self, Write}, + path::Path, +}; -use ast::{typed::TypedExpr, UntypedExpr}; +use cli::GenMode; use parse::parser::Parser; use symbols::SymbolsTable; -fn write_typed_expr( - expr: &TypedExpr, - symbols: &SymbolsTable, - writer: &mut impl Write, - prefix: &str, - is_last: bool, -) -> io::Result<()> { - let branch = if is_last { "└──" } else { "├──" }; - - write!(writer, "{}{}", prefix, branch)?; - - match expr { - TypedExpr::Int { value, .. } => writeln!(writer, "<{}>", value), - TypedExpr::Float { value, .. } => writeln!(writer, "<{}>", value), - TypedExpr::Var { name, .. } => { - let ty = symbols.resolve(*name).unwrap().ty.unwrap(); - writeln!(writer, "", name, ty) - } - TypedExpr::BinOp { lhs, op, rhs, .. } => { - writeln!(writer, "<{}>", op)?; - - let new_prefix = if is_last { - format!("{} ", prefix) - } else { - format!("{}│ ", prefix) - }; - - write_typed_expr(lhs, symbols, writer, &new_prefix, false)?; - write_typed_expr(rhs, symbols, writer, &new_prefix, true) - } - TypedExpr::IntToFloat { value, .. } => { - writeln!(writer, "i2f")?; - - let new_prefix = if is_last { - format!("{} ", prefix) - } else { - format!("{}│ ", prefix) - }; - - write_typed_expr(value, symbols, writer, &new_prefix, true) - } - } -} - -fn print_typed_expr( - expr: &TypedExpr, - symbols: &SymbolsTable, - writer: &mut impl Write, -) -> io::Result<()> { - write_typed_expr(expr, symbols, writer, "", true) -} - -fn write_untyped_expr( - expr: &UntypedExpr, - writer: &mut impl Write, - prefix: &str, - is_last: bool, -) -> io::Result<()> { - let branch = if is_last { "└──" } else { "├──" }; - - write!(writer, "{}{}", prefix, branch)?; - - match expr { - UntypedExpr::Int { value, .. } => writeln!(writer, "<{}>", value), - UntypedExpr::Float { value, .. } => writeln!(writer, "<{}>", value), - UntypedExpr::Var { - name: id, typename, .. - } => { - write!(writer, "") - } - UntypedExpr::BinOp { lhs, op, rhs, .. } => { - writeln!(writer, "<{}>", op)?; - - let new_prefix = if is_last { - format!("{} ", prefix) - } else { - format!("{}│ ", prefix) - }; - - write_untyped_expr(lhs, writer, &new_prefix, false)?; - write_untyped_expr(rhs, writer, &new_prefix, true) - } - } -} - -fn print_untyped_expr(expr: &UntypedExpr, writer: &mut impl Write) -> io::Result<()> { - write_untyped_expr(expr, writer, "", true) -} - fn main() -> anyhow::Result<()> { let args = cli::Args::parse(); @@ -112,66 +24,137 @@ fn main() -> anyhow::Result<()> { output_tokens, output_symbols, } => { - let input = std::fs::read_to_string(input)?; - let mut symbols = SymbolsTable::default(); - let tokens = - parse::lexer::make_tokenizer(&input, &mut symbols).collect::, _>>(); - - match tokens { - Ok(tokens) => { - let mut writer_tokens = - io::BufWriter::new(std::fs::File::create(output_tokens)?); - - for (_, token, _) in tokens { - writeln!(writer_tokens, "{token:>6} - {}", token.as_str())?; - } - - let mut writer_symbols = - io::BufWriter::new(std::fs::File::create(output_symbols)?); - for (name, data) in &symbols { - writeln!(writer_symbols, "{name} -> {}", data)?; - } - } - Err(e) => { - eprintln!("error: {}", e); - } - } + lex_command(input, output_tokens, output_symbols)?; } cli::Command::Syn { input, output_tree } => { - let input = std::fs::read_to_string(input)?; - let mut symbols = SymbolsTable::default(); - let tokens = parse::lexer::make_tokenizer(&input, &mut symbols); - - let mut parser = Parser::new(tokens); - let res = parser.parse(); - - match res { - Ok(expr) => { - let mut writer_tree = io::BufWriter::new(std::fs::File::create(output_tree)?); - print_untyped_expr(&expr, &mut writer_tree)?; - } - Err(e) => eprintln!("error: {}", e), - } + syn_command(input, output_tree)?; } cli::Command::Sem { input, output_tree } => { - let input = std::fs::read_to_string(input)?; - let mut symbols = SymbolsTable::default(); - let res = { - let tokens = parse::lexer::make_tokenizer(&input, &mut symbols); - let mut parser = Parser::new(tokens); - parser.parse() - } - .and_then(|expr| ast::to_typed_expr(expr, &mut symbols)); - - match res { - Ok(expr) => { - let mut writer_tree = io::BufWriter::new(std::fs::File::create(output_tree)?); - print_typed_expr(&expr, &symbols, &mut writer_tree)?; - } - Err(e) => eprintln!("error: {}", e), - } + sem_command(input, output_tree)?; + } + cli::Command::Gen { + mode, + input, + output, + output_symbols, + } => { + gen_command(mode, input, output, output_symbols)?; } } Ok(()) } + +fn gen_command( + mode: &GenMode, + input: &Path, + output: &Path, + output_symbols: &Path, +) -> Result<(), anyhow::Error> { + let input = std::fs::read_to_string(input)?; + let mut symbols = SymbolsTable::default(); + let typed_expr = match { + let tokens = parse::lexer::make_tokenizer(&input, &mut symbols); + let mut parser = Parser::new(tokens); + parser.parse() + } + .and_then(|expr| ast::to_typed_expr(expr, &mut symbols)) + { + Ok(expr) => expr, + Err(e) => { + eprintln!("error: {}", e); + return Ok(()); + } + }; + + let mut writer = io::BufWriter::new(std::fs::File::create(output)?); + + match mode { + GenMode::Intermediate => { + let intermediate_exprs = + representation::intermediate::to_intermediate_expr(typed_expr, &mut symbols); + util::print_intermediate_exprs(&intermediate_exprs, &mut writer)?; + } + GenMode::Postfix => { + util::print_postfix_exprs(&typed_expr, &mut writer)?; + } + } + + let mut writer_symbols = io::BufWriter::new(std::fs::File::create(output_symbols)?); + for (name, data) in &symbols { + writeln!(writer_symbols, "{name} -> {}", data)?; + } + + Ok(()) +} + +fn sem_command(input: &Path, output_tree: &Path) -> Result<(), anyhow::Error> { + let input = std::fs::read_to_string(input)?; + let mut symbols = SymbolsTable::default(); + + let res = { + let tokens = parse::lexer::make_tokenizer(&input, &mut symbols); + let mut parser = Parser::new(tokens); + parser.parse() + } + .and_then(|expr| ast::to_typed_expr(expr, &mut symbols)); + + match res { + Ok(expr) => { + let mut writer_tree = io::BufWriter::new(std::fs::File::create(output_tree)?); + util::print_typed_expr(&expr, &symbols, &mut writer_tree)?; + } + Err(e) => eprintln!("error: {}", e), + }; + + Ok(()) +} + +fn syn_command(input: &Path, output_tree: &Path) -> Result<(), anyhow::Error> { + let input = std::fs::read_to_string(input)?; + let mut symbols = SymbolsTable::default(); + + let tokens = parse::lexer::make_tokenizer(&input, &mut symbols); + let mut parser = Parser::new(tokens); + let res = parser.parse(); + + match res { + Ok(expr) => { + let mut writer_tree = io::BufWriter::new(std::fs::File::create(output_tree)?); + util::print_untyped_expr(&expr, &mut writer_tree)?; + } + Err(e) => eprintln!("error: {}", e), + }; + + Ok(()) +} + +fn lex_command( + input: &Path, + output_tokens: &Path, + output_symbols: &Path, +) -> Result<(), anyhow::Error> { + let input = std::fs::read_to_string(input)?; + let mut symbols = SymbolsTable::default(); + let tokens = parse::lexer::make_tokenizer(&input, &mut symbols).collect::, _>>(); + + match tokens { + Ok(tokens) => { + let mut writer_tokens = io::BufWriter::new(std::fs::File::create(output_tokens)?); + + for (_, token, _) in tokens { + writeln!(writer_tokens, "{token:>6} - {}", token.as_str())?; + } + + let mut writer_symbols = io::BufWriter::new(std::fs::File::create(output_symbols)?); + for (name, data) in &symbols { + writeln!(writer_symbols, "{name} -> {}", data)?; + } + } + Err(e) => { + eprintln!("error: {}", e); + } + }; + + Ok(()) +} diff --git a/src/parse/lexer.rs b/src/parse/lexer.rs index 24aa5ab..9e08e8c 100644 --- a/src/parse/lexer.rs +++ b/src/parse/lexer.rs @@ -82,8 +82,8 @@ impl<'s, T: Iterator> Lexer<'s, T> { if let Some(id) = self.symbols.get(&name) { Ok((start, Token::Name(id), end)) } else { - self.symbols.add(name.clone()); - let id = self.symbols.get(&name).unwrap(); + let id = self.symbols.add(name.clone()); + // let id = self.symbols.get(&name).unwrap(); Ok((start, Token::Name(id), end)) } } diff --git a/src/representation/intermediate.rs b/src/representation/intermediate.rs new file mode 100644 index 0000000..b79476e --- /dev/null +++ b/src/representation/intermediate.rs @@ -0,0 +1,90 @@ +use std::fmt; + +use crate::{ + ast::{typed::TypedExpr, BinOp}, + symbols::{Symbol, SymbolsTable}, +}; + +#[derive(Debug)] +pub enum IntermediateValue { + Int { value: i64 }, + Float { value: f64 }, + Var { name: Symbol }, +} + +impl fmt::Display for IntermediateValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + IntermediateValue::Int { value } => write!(f, "{}", value), + IntermediateValue::Float { value } => write!(f, "{}", value), + IntermediateValue::Var { name } => write!(f, "", name), + } + } +} + +#[derive(Debug)] +pub enum IntermediateExpr { + IntToFloat { + result: Symbol, + value: IntermediateValue, + }, + BinOp { + result: Symbol, + lhs: IntermediateValue, + op: BinOp, + rhs: IntermediateValue, + }, +} + +fn to_intermediate_expr_inner( + expr: TypedExpr, + symbols: &mut SymbolsTable, + intermediate_var_counter: &mut usize, + exprs: &mut Vec, +) -> IntermediateValue { + let ty = expr.ty(symbols); + + match expr { + TypedExpr::Int { value, .. } => IntermediateValue::Int { value }, + 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 result = symbols.add(format!("#T{}", intermediate_var_counter)); + symbols.resolve_mut(result).unwrap().ty = Some(ty); + *intermediate_var_counter += 1; + + exprs.push(IntermediateExpr::BinOp { + result, + lhs, + op, + rhs, + }); + + IntermediateValue::Var { name: result } + } + TypedExpr::IntToFloat { value, .. } => { + let value = + to_intermediate_expr_inner(*value, symbols, intermediate_var_counter, exprs); + + let result = symbols.add(format!("#T{}", intermediate_var_counter)); + symbols.resolve_mut(result).unwrap().ty = Some(ty); + *intermediate_var_counter += 1; + + exprs.push(IntermediateExpr::IntToFloat { result, value }); + + IntermediateValue::Var { name: result } + } + } +} + +pub fn to_intermediate_expr(expr: TypedExpr, symbols: &mut SymbolsTable) -> Vec { + let mut exprs = Vec::new(); + let mut intermediate_var_counter = 0; + + to_intermediate_expr_inner(expr, symbols, &mut intermediate_var_counter, &mut exprs); + + exprs +} diff --git a/src/representation/mod.rs b/src/representation/mod.rs new file mode 100644 index 0000000..51da266 --- /dev/null +++ b/src/representation/mod.rs @@ -0,0 +1 @@ +pub mod intermediate; diff --git a/src/symbols/mod.rs b/src/symbols/mod.rs index 0af391d..7850928 100644 --- a/src/symbols/mod.rs +++ b/src/symbols/mod.rs @@ -19,12 +19,14 @@ pub struct SymbolData { impl Display for SymbolData { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.id)?; + let mut builder = f.debug_struct("symbol"); + builder.field("id", &self.id.0); + if let Some(ty) = self.ty { - write!(f, ":{}", ty)?; + builder.field("type", &ty); } - Ok(()) + builder.finish() } } @@ -48,7 +50,7 @@ impl SymbolsTable { } } - pub fn add(&mut self, symbol: impl Into) { + 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()) { e.insert(SymbolData { @@ -57,7 +59,11 @@ impl SymbolsTable { ty: None, }); self.next_id += 1; + + return Symbol(self.next_id - 1); } + + self.get(&symbol).unwrap() } pub fn get(&self, symbol: &str) -> Option { diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..7fd8f75 --- /dev/null +++ b/src/util.rs @@ -0,0 +1,154 @@ +use std::io; + +use crate::{ + ast::{typed::TypedExpr, BinOp, UntypedExpr}, + representation::intermediate::IntermediateExpr, + symbols::SymbolsTable, +}; + +pub fn print_intermediate_exprs( + exprs: &[IntermediateExpr], + writer: &mut impl io::Write, +) -> io::Result<()> { + for expr in exprs { + match expr { + IntermediateExpr::IntToFloat { result, value } => { + writeln!(writer, "i2f , {}", result, value)?; + } + IntermediateExpr::BinOp { + result, + lhs, + op, + rhs, + } => { + writeln!( + writer, + "{} , {}, {}", + match op { + BinOp::Add => "add", + BinOp::Sub => "sub", + BinOp::Mul => "mul", + BinOp::Div => "div", + }, + result, + lhs, + rhs + )?; + } + } + } + + Ok(()) +} + +pub fn print_postfix_exprs(expr: &TypedExpr, writer: &mut impl io::Write) -> io::Result<()> { + match expr { + TypedExpr::Int { value, .. } => write!(writer, "{} ", value)?, + TypedExpr::Float { value, .. } => write!(writer, "{} ", value)?, + TypedExpr::Var { name, .. } => write!(writer, " ", name)?, + TypedExpr::BinOp { lhs, op, rhs, .. } => { + print_postfix_exprs(lhs, writer)?; + print_postfix_exprs(rhs, writer)?; + write!(writer, "{} ", op)?; + } + TypedExpr::IntToFloat { value, .. } => { + print_postfix_exprs(value, writer)?; + write!(writer, "i2f ")?; + } + } + + Ok(()) +} + +fn write_typed_expr( + expr: &TypedExpr, + symbols: &SymbolsTable, + writer: &mut impl io::Write, + prefix: &str, + is_last: bool, +) -> io::Result<()> { + let branch = if is_last { "└──" } else { "├──" }; + + write!(writer, "{}{}", prefix, branch)?; + + match expr { + TypedExpr::Int { value, .. } => writeln!(writer, "<{}>", value), + TypedExpr::Float { value, .. } => writeln!(writer, "<{}>", value), + TypedExpr::Var { name, .. } => { + let ty = symbols.resolve(*name).unwrap().ty.unwrap(); + writeln!(writer, "", name, ty) + } + TypedExpr::BinOp { lhs, op, rhs, .. } => { + writeln!(writer, "<{}>", op)?; + + let new_prefix = if is_last { + format!("{} ", prefix) + } else { + format!("{}│ ", prefix) + }; + + write_typed_expr(lhs, symbols, writer, &new_prefix, false)?; + write_typed_expr(rhs, symbols, writer, &new_prefix, true) + } + TypedExpr::IntToFloat { value, .. } => { + writeln!(writer, "i2f")?; + + let new_prefix = if is_last { + format!("{} ", prefix) + } else { + format!("{}│ ", prefix) + }; + + write_typed_expr(value, symbols, writer, &new_prefix, true) + } + } +} + +pub fn print_typed_expr( + expr: &TypedExpr, + symbols: &SymbolsTable, + writer: &mut impl io::Write, +) -> io::Result<()> { + write_typed_expr(expr, symbols, writer, "", true) +} + +fn write_untyped_expr( + expr: &UntypedExpr, + writer: &mut impl io::Write, + prefix: &str, + is_last: bool, +) -> io::Result<()> { + let branch = if is_last { "└──" } else { "├──" }; + + write!(writer, "{}{}", prefix, branch)?; + + match expr { + UntypedExpr::Int { value, .. } => writeln!(writer, "<{}>", value), + UntypedExpr::Float { value, .. } => writeln!(writer, "<{}>", value), + UntypedExpr::Var { + name: id, typename, .. + } => { + write!(writer, "") + } + UntypedExpr::BinOp { lhs, op, rhs, .. } => { + writeln!(writer, "<{}>", op)?; + + let new_prefix = if is_last { + format!("{} ", prefix) + } else { + format!("{}│ ", prefix) + }; + + write_untyped_expr(lhs, writer, &new_prefix, false)?; + write_untyped_expr(rhs, writer, &new_prefix, true) + } + } +} + +pub fn print_untyped_expr(expr: &UntypedExpr, writer: &mut impl io::Write) -> io::Result<()> { + write_untyped_expr(expr, writer, "", true) +}