パーサジェネレータの続き。
ASTを作る
次は四則演算を作るASTを作り上げる。文法自体はRust
のマクロを使って実装されているので、RustのEnumなどを使ってASTを作り上げることができる。
rust/calculator4/src/ast.rs
pub enum Expr { Number(i32), Op(Box<Expr>, Opcode, Box<Expr>), } #[derive(Copy, Clone)] pub enum Opcode { Mul, Div, Add, Sub, }
rust/calculator4/src/calculator4.lalrpop
use std::str::FromStr; use crate::ast::{Expr, Opcode}; // (0) grammar; pub Expr: Box<Expr> = { // (1) Expr ExprOp Factor => Box::new(Expr::Op(<>)), // (2) Factor, }; ExprOp: Opcode = { // (3) "+" => Opcode::Add, "-" => Opcode::Sub, }; Factor: Box<Expr> = { Factor FactorOp Term => Box::new(Expr::Op(<>)), Term, }; FactorOp: Opcode = { "*" => Opcode::Mul, "/" => Opcode::Div, }; Term: Box<Expr> = { Num => Box::new(Expr::Number(<>)), // (4) "(" <Expr> ")" }; Num: i32 = { r"[0-9]+" => i32::from_str(<>).unwrap() };
rust/calculator4/src/main.rs
#[test] fn calculator4() { let expr = calculator4::ExprParser::new() .parse("22 * 44 + 66") .unwrap(); assert_eq!(&format!("{:?}", expr), "((22 * 44) + 66)"); }
上記のExprParser
は最終的に文字列を出力している。これを扱うのはast.rs
に書かれたfmt(&self, fmt: &mut Formatter)
を使っている。
rust/calculator4/src/ast.rs
impl Debug for Expr { fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { use self::Expr::*; match *self { Number(n) => write!(fmt, "{:?}", n), Op(ref l, op, ref r) => write!(fmt, "({:?} {:?} {:?})", l, op, r), } } } impl Debug for Opcode { fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> { use self::Opcode::*; match *self { Mul => write!(fmt, "*"), Div => write!(fmt, "/"), Add => write!(fmt, "+"), Sub => write!(fmt, "-"), } } }