Differences
This shows you the differences between two versions of the page.
lib:parser [2019/01/08 08:37] – created sprowell | lib:parser [2019/01/08 09:42] (current) – sprowell | ||
---|---|---|---|
Line 21: | Line 21: | ||
<code Ada> | <code Ada> | ||
-- The best pseudocode is written in Ada for some reason. | -- The best pseudocode is written in Ada for some reason. | ||
- | while peek is a digit loop | + | while is_digit(peek) loop |
consume; | consume; | ||
end loop; | end loop; | ||
Line 27: | Line 27: | ||
Composites of these primitives are available to simplify things. | Composites of these primitives are available to simplify things. | ||
- | the implementation of the above pseudocode might look like the code below, | + | the implementation of the above pseudocode might look like the code below, |
+ | |||
+ | <code Rust> | ||
+ | fn parse_unsigned_integer< | ||
+ | let mut result = String:: | ||
+ | while let Some(ch) = parser.peek()? | ||
+ | if ch.is_digit(10) { | ||
+ | result.push(ch); | ||
+ | parser.consume(); | ||
+ | } else { | ||
+ | break; | ||
+ | } | ||
+ | } | ||
+ | match result.parse::< | ||
+ | Ok(number) => Ok(number), | ||
+ | Err(err) => Err(parser.error(err.to_string())), | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | This is terrible. | ||
+ | |||
+ | Here the integer parsing is broken out into a separate function so we can use the ''?'' | ||
<code Rust> | <code Rust> | ||
Line 59: | Line 81: | ||
If nothing is entered we get '' | If nothing is entered we get '' | ||
+ | Of course, this probably isn't what we want. Suppose we have a stream of identifiers and numbers, and we want to parse these. | ||
+ | |||
+ | We already know how to parse unsigned integers. | ||
+ | |||
+ | <code Rust> | ||
+ | fn parse_identifier< | ||
+ | let mut result = parser.take_while(|ch| ch.is_alphabetic())?; | ||
+ | result = result + parser.take_while(|ch| ch.is_alphanumeric())? | ||
+ | Ok(result) | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Okay, now let's create a type for our tokens. | ||
+ | |||
+ | <code Rust> | ||
+ | # | ||
+ | enum Thing { | ||
+ | Number(u64), | ||
+ | Id(String), | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Now we can parse the sequence, and create a vector of '' | ||
+ | |||
+ | <code Rust> | ||
+ | fn parse_sequence< | ||
+ | let mut things = Vec::new(); | ||
+ | let _ = parser.consume_whitespace(); | ||
+ | while !parser.at_eof() { | ||
+ | match parser.peek() { | ||
+ | Ok(Some(ch)) => { | ||
+ | if ch.is_digit(10) { | ||
+ | things.push(Thing:: | ||
+ | } else if ch.is_alphabetic() { | ||
+ | things.push(Thing:: | ||
+ | } else { | ||
+ | return Err(parser.unexpected_char(" | ||
+ | } | ||
+ | } | ||
+ | Ok(None) => break, | ||
+ | Err(err) => return Err(err), | ||
+ | } | ||
+ | let _ = parser.consume_whitespace(); | ||
+ | } | ||
+ | Ok(things) | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Now we just need a main function to pull this all together. | ||
+ | |||
+ | <code Rust> | ||
+ | fn main() { | ||
+ | let mut parser = parser:: | ||
+ | match parse_sequence(& | ||
+ | Err(err) => { | ||
+ | println!(" | ||
+ | } | ||
+ | Ok(seq) => { | ||
+ | println!(" | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | That's pretty much it. If it seems like there' |