1
0
This commit is contained in:
2024-11-08 06:47:11 +03:00
parent 1f6b90e1e1
commit a0c1648b17
7 changed files with 439 additions and 155 deletions

View File

@@ -27,6 +27,20 @@ pub enum Command {
input: PathBuf, input: PathBuf,
output_tree: 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 { impl Args {
@@ -60,6 +74,12 @@ fn validate_inner(args: ArgsInner) -> Result<ArgsInner, clap::Error> {
} => validate_lex(input, output_tokens, output_symbols)?, } => validate_lex(input, output_tokens, output_symbols)?,
Command::Syn { input, output_tree } => validate_syn(input, output_tree)?, Command::Syn { input, output_tree } => validate_syn(input, output_tree)?,
Command::Sem { input, output_tree } => validate_sem(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) Ok(args)
@@ -129,3 +149,33 @@ fn validate_sem(input: &PathBuf, output_tree: &PathBuf) -> Result<(), clap::Erro
Ok(()) 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(())
}

View File

@@ -2,107 +2,19 @@ mod ast;
mod cli; mod cli;
mod error; mod error;
mod parse; mod parse;
mod representation;
mod symbols; 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 parse::parser::Parser;
use symbols::SymbolsTable; 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, "<id,{},{}>", 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, "<id,{}", id)?;
if let Some(typename) = typename {
write!(writer, ",{}", typename)?;
}
writeln!(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<()> { fn main() -> anyhow::Result<()> {
let args = cli::Args::parse(); let args = cli::Args::parse();
@@ -112,66 +24,137 @@ fn main() -> anyhow::Result<()> {
output_tokens, output_tokens,
output_symbols, output_symbols,
} => { } => {
let input = std::fs::read_to_string(input)?; lex_command(input, output_tokens, output_symbols)?;
let mut symbols = SymbolsTable::default();
let tokens =
parse::lexer::make_tokenizer(&input, &mut symbols).collect::<Result<Vec<_>, _>>();
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);
}
}
} }
cli::Command::Syn { input, output_tree } => { cli::Command::Syn { input, output_tree } => {
let input = std::fs::read_to_string(input)?; syn_command(input, output_tree)?;
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),
}
} }
cli::Command::Sem { input, output_tree } => { cli::Command::Sem { input, output_tree } => {
let input = std::fs::read_to_string(input)?; sem_command(input, output_tree)?;
let mut symbols = SymbolsTable::default(); }
let res = { cli::Command::Gen {
let tokens = parse::lexer::make_tokenizer(&input, &mut symbols); mode,
let mut parser = Parser::new(tokens); input,
parser.parse() output,
} output_symbols,
.and_then(|expr| ast::to_typed_expr(expr, &mut symbols)); } => {
gen_command(mode, input, output, output_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),
}
} }
} }
Ok(()) 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::<Result<Vec<_>, _>>();
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(())
}

View File

@@ -82,8 +82,8 @@ impl<'s, T: Iterator<Item = (usize, char)>> Lexer<'s, T> {
if let Some(id) = self.symbols.get(&name) { if let Some(id) = self.symbols.get(&name) {
Ok((start, Token::Name(id), end)) Ok((start, Token::Name(id), end))
} else { } else {
self.symbols.add(name.clone()); let id = self.symbols.add(name.clone());
let id = self.symbols.get(&name).unwrap(); // let id = self.symbols.get(&name).unwrap();
Ok((start, Token::Name(id), end)) Ok((start, Token::Name(id), end))
} }
} }

View File

@@ -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, "<id,{}>", 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<IntermediateExpr>,
) -> 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<IntermediateExpr> {
let mut exprs = Vec::new();
let mut intermediate_var_counter = 0;
to_intermediate_expr_inner(expr, symbols, &mut intermediate_var_counter, &mut exprs);
exprs
}

View File

@@ -0,0 +1 @@
pub mod intermediate;

View File

@@ -19,12 +19,14 @@ pub struct SymbolData {
impl Display for SymbolData { impl Display for SymbolData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 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 { 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<String>) { 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()) {
e.insert(SymbolData { e.insert(SymbolData {
@@ -57,7 +59,11 @@ impl SymbolsTable {
ty: None, ty: None,
}); });
self.next_id += 1; self.next_id += 1;
return Symbol(self.next_id - 1);
} }
self.get(&symbol).unwrap()
} }
pub fn get(&self, symbol: &str) -> Option<Symbol> { pub fn get(&self, symbol: &str) -> Option<Symbol> {

154
src/util.rs Normal file
View File

@@ -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 <id,{}>, {}", result, value)?;
}
IntermediateExpr::BinOp {
result,
lhs,
op,
rhs,
} => {
writeln!(
writer,
"{} <id,{}>, {}, {}",
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, "<id,{}> ", 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, "<id,{},{}>", 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, "<id,{}", id)?;
if let Some(typename) = typename {
write!(writer, ",{}", typename)?;
}
writeln!(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)
}