111 lines
3.4 KiB
Rust
111 lines
3.4 KiB
Rust
mod parser {
|
|
use pest_derive::Parser;
|
|
|
|
#[derive(Parser)]
|
|
#[grammar = "../examples/base.pest"]
|
|
#[grammar = "../examples/calc.pest"]
|
|
pub struct Parser;
|
|
}
|
|
|
|
use parser::Rule;
|
|
use pest::{
|
|
iterators::Pairs,
|
|
pratt_parser::{Assoc::*, Op, PrattParser},
|
|
Parser,
|
|
};
|
|
use std::io::{stdin, stdout, Write};
|
|
|
|
fn parse_to_str(pairs: Pairs<Rule>, pratt: &PrattParser<Rule>) -> String {
|
|
pratt
|
|
.map_primary(|primary| match primary.as_rule() {
|
|
Rule::int => primary.as_str().to_owned(),
|
|
Rule::expr => parse_to_str(primary.into_inner(), pratt),
|
|
_ => unreachable!(),
|
|
})
|
|
.map_prefix(|op, rhs| match op.as_rule() {
|
|
Rule::neg => format!("(-{})", rhs),
|
|
_ => unreachable!(),
|
|
})
|
|
.map_postfix(|lhs, op| match op.as_rule() {
|
|
Rule::fac => format!("({}!)", lhs),
|
|
_ => unreachable!(),
|
|
})
|
|
.map_infix(|lhs, op, rhs| match op.as_rule() {
|
|
Rule::add => format!("({}+{})", lhs, rhs),
|
|
Rule::sub => format!("({}-{})", lhs, rhs),
|
|
Rule::mul => format!("({}*{})", lhs, rhs),
|
|
Rule::div => format!("({}/{})", lhs, rhs),
|
|
Rule::pow => format!("({}^{})", lhs, rhs),
|
|
_ => unreachable!(),
|
|
})
|
|
.parse(pairs)
|
|
}
|
|
|
|
fn parse_to_i32(pairs: Pairs<Rule>, pratt: &PrattParser<Rule>) -> i128 {
|
|
pratt
|
|
.map_primary(|primary| match primary.as_rule() {
|
|
Rule::int => primary.as_str().parse().unwrap(),
|
|
Rule::expr => parse_to_i32(primary.into_inner(), pratt),
|
|
_ => unreachable!(),
|
|
})
|
|
.map_prefix(|op, rhs| match op.as_rule() {
|
|
Rule::neg => -rhs,
|
|
_ => unreachable!(),
|
|
})
|
|
.map_postfix(|lhs, op| match op.as_rule() {
|
|
Rule::fac => (1..lhs + 1).product(),
|
|
_ => unreachable!(),
|
|
})
|
|
.map_infix(|lhs, op, rhs| match op.as_rule() {
|
|
Rule::add => lhs + rhs,
|
|
Rule::sub => lhs - rhs,
|
|
Rule::mul => lhs * rhs,
|
|
Rule::div => lhs / rhs,
|
|
Rule::pow => (1..rhs + 1).map(|_| lhs).product(),
|
|
_ => unreachable!(),
|
|
})
|
|
.parse(pairs)
|
|
}
|
|
|
|
fn main() {
|
|
let pratt = PrattParser::new()
|
|
.op(Op::infix(Rule::add, Left) | Op::infix(Rule::sub, Left))
|
|
.op(Op::infix(Rule::mul, Left) | Op::infix(Rule::div, Left))
|
|
.op(Op::infix(Rule::pow, Right))
|
|
.op(Op::postfix(Rule::fac))
|
|
.op(Op::prefix(Rule::neg));
|
|
|
|
let stdin = stdin();
|
|
let mut stdout = stdout();
|
|
|
|
loop {
|
|
let source = {
|
|
print!("> ");
|
|
let _ = stdout.flush();
|
|
let mut input = String::new();
|
|
let _ = stdin.read_line(&mut input);
|
|
input.trim().to_string()
|
|
};
|
|
|
|
let pairs = match parser::Parser::parse(Rule::program, &source) {
|
|
Ok(mut parse_tree) => {
|
|
parse_tree
|
|
.next()
|
|
.unwrap()
|
|
.into_inner() // inner of program
|
|
.next()
|
|
.unwrap()
|
|
.into_inner() // inner of expr
|
|
}
|
|
Err(err) => {
|
|
println!("Failed parsing input: {:}", err);
|
|
continue;
|
|
}
|
|
};
|
|
|
|
print!("{} => ", source);
|
|
print!("{} => ", parse_to_str(pairs.clone(), &pratt));
|
|
println!("{}", parse_to_i32(pairs.clone(), &pratt));
|
|
}
|
|
}
|