解答

  1. use thiserror::Error;
  2. use std::iter::Peekable;
  3. use std::str::Chars;
  4. /// An arithmetic operator.
  5. #[derive(Debug, PartialEq, Clone, Copy)]
  6. enum Op {
  7. Add,
  8. Sub,
  9. }
  10. /// A token in the expression language.
  11. #[derive(Debug, PartialEq)]
  12. enum Token {
  13. Number(String),
  14. Identifier(String),
  15. Operator(Op),
  16. }
  17. /// An expression in the expression language.
  18. #[derive(Debug, PartialEq)]
  19. enum Expression {
  20. /// A reference to a variable.
  21. Var(String),
  22. /// A literal number.
  23. Number(u32),
  24. /// A binary operation.
  25. Operation(Box<Expression>, Op, Box<Expression>),
  26. }
  27. fn tokenize(input: &str) -> Tokenizer {
  28. return Tokenizer(input.chars().peekable());
  29. }
  30. #[derive(Debug, Error)]
  31. enum TokenizerError {
  32. #[error("Unexpected character '{0}' in input")]
  33. UnexpectedCharacter(char),
  34. }
  35. struct Tokenizer<'a>(Peekable<Chars<'a>>);
  36. impl<'a> Iterator for Tokenizer<'a> {
  37. type Item = Result<Token, TokenizerError>;
  38. fn next(&mut self) -> Option<Result<Token, TokenizerError>> {
  39. let c = self.0.next()?;
  40. match c {
  41. '0'..='9' => {
  42. let mut num = String::from(c);
  43. while let Some(c @ '0'..='9') = self.0.peek() {
  44. num.push(*c);
  45. self.0.next();
  46. }
  47. Some(Ok(Token::Number(num)))
  48. }
  49. 'a'..='z' => {
  50. let mut ident = String::from(c);
  51. while let Some(c @ ('a'..='z' | '_' | '0'..='9')) = self.0.peek() {
  52. ident.push(*c);
  53. self.0.next();
  54. }
  55. Some(Ok(Token::Identifier(ident)))
  56. }
  57. '+' => Some(Ok(Token::Operator(Op::Add))),
  58. '-' => Some(Ok(Token::Operator(Op::Sub))),
  59. _ => Some(Err(TokenizerError::UnexpectedCharacter(c))),
  60. }
  61. }
  62. }
  63. #[derive(Debug, Error)]
  64. enum ParserError {
  65. #[error("Tokenizer error: {0}")]
  66. TokenizerError(#[from] TokenizerError),
  67. #[error("Unexpected end of input")]
  68. UnexpectedEOF,
  69. #[error("Unexpected token {0:?}")]
  70. UnexpectedToken(Token),
  71. #[error("Invalid number")]
  72. InvalidNumber(#[from] std::num::ParseIntError),
  73. }
  74. fn parse(input: &str) -> Result<Expression, ParserError> {
  75. let mut tokens = tokenize(input);
  76. fn parse_expr<'a>(
  77. tokens: &mut Tokenizer<'a>,
  78. ) -> Result<Expression, ParserError> {
  79. let tok = tokens.next().ok_or(ParserError::UnexpectedEOF)??;
  80. let expr = match tok {
  81. Token::Number(num) => {
  82. let v = num.parse()?;
  83. Expression::Number(v)
  84. }
  85. Token::Identifier(ident) => Expression::Var(ident),
  86. Token::Operator(_) => return Err(ParserError::UnexpectedToken(tok)),
  87. };
  88. // Look ahead to parse a binary operation if present.
  89. Ok(match tokens.next() {
  90. None => expr,
  91. Some(Ok(Token::Operator(op))) => Expression::Operation(
  92. Box::new(expr),
  93. op,
  94. Box::new(parse_expr(tokens)?),
  95. ),
  96. Some(Err(e)) => return Err(e.into()),
  97. Some(Ok(tok)) => return Err(ParserError::UnexpectedToken(tok)),
  98. })
  99. }
  100. parse_expr(&mut tokens)
  101. }
  102. fn main() -> anyhow::Result<()> {
  103. let expr = parse("10+foo+20-30")?;
  104. println!("{expr:?}");
  105. Ok(())
  106. }