summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Brown <gmb60@cam.ac.uk>2021-04-20 13:22:49 +0100
committerGreg Brown <gmb60@cam.ac.uk>2021-04-20 13:22:49 +0100
commitbb3c8d1455f7a102a0c0abffd757ccace94f77d5 (patch)
tree5c2793598c781c648c4d9cd103414ff47d88adc1
parent15f5491028b11bd821bd141183e8b5bf8c1c46af (diff)
Add LALRPOP arithmetic parser.
-rw-r--r--chomp-bench/benches/arith.rs8
-rw-r--r--chomp-bench/benches/json.rs4
-rw-r--r--chomp-bench/src/arith/lalr.lalrpop33
-rw-r--r--chomp-bench/src/arith/mod.rs24
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)