Skip to content

Commit

Permalink
climberを使うように変更
Browse files Browse the repository at this point in the history
  • Loading branch information
Toru3 committed Aug 11, 2019
1 parent db9c3d3 commit 226f0a8
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 98 deletions.
29 changes: 19 additions & 10 deletions src/calc.pest
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
atom = _{ int | ident }
int = @{ (ASCII_NONZERO_DIGIT ~ ASCII_DIGIT*) | "0" }
ident = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* }
uniop = @{ "+" | "-" }
add = @{ "+" | "-" }
mul = @{ "*" | "/" | "%" }
pow = @{ "^" }
expr = { term3 ~ (add ~ term3)* }
term3 = { term2 ~ (mul ~ term2)* }
term2 = { term1 ~ (pow ~ term2)* }

uniop = _{ plus | neg }
plus = { "+" }
neg = { "-" }

binop = _{ add | sub | mul | div | rem | pow }
add = { "+" }
sub = { "-" }
mul = { "*" }
div = { "/" }
rem = { "%" }
pow = { "^" }

func = { ident ~ "(" ~ args ~ ")" }
args = _{ expr ~ ("," ~ expr)* | "" }

expr = { term1 ~ (binop ~ term1)* }
term1 = { uniop? ~ term0 }
term0 = { func | "(" ~ expr ~ ")" | atom }
atom = { int | ident }
func = { ident ~ "(" ~ args ~ ")" }
args = { expr ~ ("," ~ expr)* | "" }

WHITESPACE = _{ " " | "\t" | NEWLINE }
123 changes: 35 additions & 88 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,21 +88,10 @@ fn ast_func(func: pest::iterators::Pair<Rule>) -> Ast {
let func_name = iter.next().unwrap();
assert_eq!(func_name.as_rule(), Rule::ident);
let name = func_name.as_str().to_owned();
let args = iter.next().unwrap();
assert_eq!(args.as_rule(), Rule::args);
let args = args.into_inner().map(ast_expr).collect::<Vec<_>>();
let args = iter.map(ast_expr).collect::<Vec<_>>();
Ast::Func { name, args }
}

fn ast_atom(atom: pest::iterators::Pair<Rule>) -> Ast {
let t = atom.into_inner().next().unwrap();
match t.as_rule() {
Rule::int => Ast::Num(t.as_str().parse::<i64>().unwrap()),
Rule::ident => Ast::Ident(t.as_str().to_owned()),
_ => unreachable!(),
}
}

fn ast_term0(term0: pest::iterators::Pair<Rule>) -> Ast {
let t = term0.into_inner().next().unwrap();
match t.as_rule() {
Expand All @@ -111,99 +100,57 @@ fn ast_term0(term0: pest::iterators::Pair<Rule>) -> Ast {
println!("{:?}", t);
ast_expr(t)
}
Rule::atom => ast_atom(t),
Rule::int => Ast::Num(t.as_str().parse::<i64>().unwrap()),
Rule::ident => Ast::Ident(t.as_str().to_owned()),
_ => unreachable!(),
}
}

fn ast_term1(term1: pest::iterators::Pair<Rule>) -> Ast {
let mut iter = term1.into_inner();
let first = iter.next().unwrap();
if first.as_rule() == Rule::uniop {
let op = match first.as_str() {
"+" => UniOp::Plus,
"-" => UniOp::Neg,
_ => unreachable!(),
};
let second = iter.next().unwrap();
let expr = Box::new(ast_term0(second));
Ast::UniOp { op, expr }
} else {
assert_eq!(first.as_rule(), Rule::term0);
if first.as_rule() == Rule::term0 {
ast_term0(first)
}
}

fn ast_term2(term2: pest::iterators::Pair<Rule>) -> Ast {
let mut iter = term2.into_inner();
let first = iter.next().unwrap();
assert_eq!(first.as_rule(), Rule::term1);
let mut ast = ast_term1(first);
if let Some(op) = iter.next() {
assert_eq!(op.as_rule(), Rule::pow);
let op = match op.as_str() {
"^" => BinOp::Pow,
} else {
let op = match first.as_rule() {
Rule::plus => UniOp::Plus,
Rule::neg => UniOp::Neg,
_ => unreachable!(),
};
let right = iter.next().unwrap();
assert_eq!(right.as_rule(), Rule::term2);
let right = Box::new(ast_term2(right));
ast = Ast::BinOp {
Ast::UniOp {
op,
left: Box::new(ast),
right,
};
expr: Box::new(ast_term0(iter.next().unwrap())),
}
}
dbg!(ast)
}

fn ast_term3(term3: pest::iterators::Pair<Rule>) -> Ast {
let mut iter = term3.into_inner();
let first = iter.next().unwrap();
assert_eq!(first.as_rule(), Rule::term2);
let mut ast = ast_term2(first);
while let Some(op) = iter.next() {
assert_eq!(op.as_rule(), Rule::mul);
let op = match op.as_str() {
"*" => BinOp::Mul,
"/" => BinOp::Div,
"%" => BinOp::Rem,
_ => unreachable!(),
};
let right = iter.next().unwrap();
assert_eq!(right.as_rule(), Rule::term2);
let right = Box::new(ast_term2(right));
ast = Ast::BinOp {
op,
left: Box::new(ast),
right,
};
fn binop(left: Ast, op: pest::iterators::Pair<Rule>, right: Ast) -> Ast {
let op = match op.as_rule() {
Rule::add => BinOp::Add,
Rule::sub => BinOp::Sub,
Rule::mul => BinOp::Mul,
Rule::div => BinOp::Div,
Rule::rem => BinOp::Rem,
Rule::pow => BinOp::Pow,
_ => unreachable!(),
};
Ast::BinOp {
op,
left: Box::new(left),
right: Box::new(right),
}
dbg!(ast)
}

fn ast_expr(expr: pest::iterators::Pair<Rule>) -> Ast {
let mut iter = expr.into_inner();
let first = iter.next().unwrap();
assert_eq!(first.as_rule(), Rule::term3);
let mut ast = ast_term3(first);
while let Some(op) = iter.next() {
assert_eq!(op.as_rule(), Rule::add);
let op = match op.as_str() {
"+" => BinOp::Add,
"-" => BinOp::Sub,
_ => unreachable!(),
};
let right = iter.next().unwrap();
assert_eq!(right.as_rule(), Rule::term3);
let right = Box::new(ast_term3(right));
ast = Ast::BinOp {
op,
left: Box::new(ast),
right,
};
}
dbg!(ast)
fn ast_expr(pair: pest::iterators::Pair<Rule>) -> Ast {
use pest::prec_climber::{Assoc, Operator, PrecClimber};
let climber = PrecClimber::new(vec![
Operator::new(Rule::add, Assoc::Left) | Operator::new(Rule::sub, Assoc::Left),
Operator::new(Rule::mul, Assoc::Left)
| Operator::new(Rule::div, Assoc::Left)
| Operator::new(Rule::rem, Assoc::Left),
Operator::new(Rule::pow, Assoc::Right),
]);
climber.climb(pair.into_inner(), ast_term1, binop)
}

fn make_ast(parsed: pest::iterators::Pairs<Rule>) -> Vec<Ast> {
Expand Down

0 comments on commit 226f0a8

Please sign in to comment.