diff options
author | Greg Brown <gmb60@cam.ac.uk> | 2021-04-20 13:22:49 +0100 |
---|---|---|
committer | Greg Brown <gmb60@cam.ac.uk> | 2021-04-20 13:22:49 +0100 |
commit | bb3c8d1455f7a102a0c0abffd757ccace94f77d5 (patch) | |
tree | 5c2793598c781c648c4d9cd103414ff47d88adc1 | |
parent | 15f5491028b11bd821bd141183e8b5bf8c1c46af (diff) |
Add LALRPOP arithmetic parser.
-rw-r--r-- | chomp-bench/benches/arith.rs | 8 | ||||
-rw-r--r-- | chomp-bench/benches/json.rs | 4 | ||||
-rw-r--r-- | chomp-bench/src/arith/lalr.lalrpop | 33 | ||||
-rw-r--r-- | chomp-bench/src/arith/mod.rs | 24 |
4 files changed, 63 insertions, 6 deletions
diff --git a/chomp-bench/benches/arith.rs b/chomp-bench/benches/arith.rs index 489a847..f5ca735 100644 --- a/chomp-bench/benches/arith.rs +++ b/chomp-bench/benches/arith.rs @@ -28,7 +28,12 @@ fn parse_handwritten(input: &str) -> i64 { parse_expr(&mut IterWrapper::new(input.chars())).unwrap() } +fn parse_lalrpop(parser: &lalr::ExpressionParser, input: &str) -> i64 { + parser.parse(input).unwrap() +} + fn bench_parse(c: &mut Criterion) { + let lalr_parser = lalr::ExpressionParser::new(); let plot_config = PlotConfiguration::default().summary_scale(AxisScale::Logarithmic); let mut group = c.benchmark_group("Arith"); group.plot_config(plot_config); @@ -40,6 +45,9 @@ fn bench_parse(c: &mut Criterion) { group.bench_with_input(BenchmarkId::new("Handwritten", i), *input, |b, i| { b.iter(|| parse_handwritten(i)) }); + group.bench_with_input(BenchmarkId::new("LALRPOP", i), *input, |b, i| { + b.iter(|| parse_lalrpop(&lalr_parser, i)) + }); } } diff --git a/chomp-bench/benches/json.rs b/chomp-bench/benches/json.rs index abe1c28..c6c73ef 100644 --- a/chomp-bench/benches/json.rs +++ b/chomp-bench/benches/json.rs @@ -1,8 +1,8 @@ use chewed::{IterWrapper, Parser}; use chomp_bench::json::*; use criterion::{ - criterion_group, criterion_main, AxisScale, BenchmarkId, Criterion, - PlotConfiguration, Throughput, + criterion_group, criterion_main, AxisScale, BenchmarkId, Criterion, PlotConfiguration, + Throughput, }; const INPUTS: &[&str] = &[ diff --git a/chomp-bench/src/arith/lalr.lalrpop b/chomp-bench/src/arith/lalr.lalrpop new file mode 100644 index 0000000..fe21d01 --- /dev/null +++ b/chomp-bench/src/arith/lalr.lalrpop @@ -0,0 +1,33 @@ +use std::str::FromStr; + +grammar; + +pub Expression: i64 = { + <p : Product> <v : (<AddOp> <Product>)*> => { + v.into_iter().fold(p, |acc, (op, p)| if op { acc + p } else { acc - p }) + } +} + +AddOp: bool = { + "+" => true, + "-" => false, +} + +Product: i64 = { + <t : Term> <v : (<MulOp> <Term>)*> => { + v.into_iter().fold(t, |acc, (op, t)| if op { acc * t } else { acc / t }) + } +} + +MulOp: bool = { + "*" => true, + "/" => false, +} + +Term: i64 = { + Number, + "-" <Number> => -<>, + "(" <Expression> ")", +} + +Number: i64 = r"[0-9]+" => i64::from_str(<>).unwrap(); diff --git a/chomp-bench/src/arith/mod.rs b/chomp-bench/src/arith/mod.rs index 37432d5..38556fe 100644 --- a/chomp-bench/src/arith/mod.rs +++ b/chomp-bench/src/arith/mod.rs @@ -1,39 +1,51 @@ use chewed::{ParseError, TakeError}; +use lalrpop_util::lalrpop_mod; pub mod nibble; +lalrpop_mod!(pub lalr, "/arith/lalr.rs"); pub fn take_number<P: chewed::Parser + ?Sized>(input: &mut P) -> Result<i64, TakeError> { let mut out = None; loop { - match input.next() { + match input.peek() { Some('0') => { + input.consume_str("0")?; out = Some(out.unwrap_or_default() * 10); } Some('1') => { + input.consume_str("1")?; out = Some(out.unwrap_or_default() * 10 + 1); } Some('2') => { + input.consume_str("2")?; out = Some(out.unwrap_or_default() * 10 + 2); } Some('3') => { + input.consume_str("3")?; out = Some(out.unwrap_or_default() * 10 + 3); } Some('4') => { + input.consume_str("4")?; out = Some(out.unwrap_or_default() * 10 + 4); } Some('5') => { + input.consume_str("5")?; out = Some(out.unwrap_or_default() * 10 + 5); } Some('6') => { + input.consume_str("6")?; out = Some(out.unwrap_or_default() * 10 + 6); } Some('7') => { + input.consume_str("7")?; out = Some(out.unwrap_or_default() * 10 + 7); } Some('8') => { + input.consume_str("8")?; out = Some(out.unwrap_or_default() * 10 + 8); } Some('9') => { + input.consume_str("9")?; out = Some(out.unwrap_or_default() * 10 + 9); } Some(c) => { @@ -80,13 +92,15 @@ pub fn take_product<P: chewed::Parser + ?Sized>(input: &mut P) -> Result<i64, Ta let mut out = take_term(input)?; while let Some(c) = input.peek() { if c == '*' { + input.consume_str("*")?; input.skip_while(|c| c == ' '); out *= take_term(input)?; } else if c == '/' { + input.consume_str("/")?; input.skip_while(|c| c == ' '); - out -= take_term(input)?; + out /= take_term(input)?; } else { - return Err(TakeError::BadBranch(input.pos(), c, &['*', '/'])); + break } } Ok(out) @@ -96,13 +110,15 @@ pub fn take_expr<P: chewed::Parser + ?Sized>(input: &mut P) -> Result<i64, TakeE let mut out = take_product(input)?; while let Some(c) = input.peek() { if c == '+' { + input.consume_str("+")?; input.skip_while(|c| c == ' '); out += take_product(input)?; } else if c == '-' { + input.consume_str("-")?; input.skip_while(|c| c == ' '); out -= take_product(input)?; } else { - return Err(TakeError::BadBranch(input.pos(), c, &['+', '-'])); + break } } Ok(out) |