如何使用 rust 和 pomelo 以 backus naur 形式表示 if-else 语句?

How to represent an if-else statment in backus naur form using rust and pomelo?

我正在尝试使用 rust 中的 pomelo 来解析脚本语言,但在该语言的 backus-naur 表示中遇到了障碍,它无法按照我定义的方式解析 if-else 语句。 例如,如果要解析语句

if (1) {
  return;
}

解析器会成功,但如果我要在代码中添加一个 else 语句,比如

if (1) {
 return;
} else {
 return;
}

它会在 else 标记处抛出语法错误,具体来说, 我得到的输出是

gettin If
gettin LParen
gettin Num(1)
gettin RParen
gettin LBrace
gettin Return
gettin Semicolon
gettin RBrace
gettin Else
should not execute this
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: "syntax Some(Else)"', src/main.rs:122:24
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

在查看 bnf 表单时,我似乎不太清楚为什么会失败。 对于这个最小可重现示例的大量代码,我感到抱歉,但我不知道 bnf 表单中错误的确切原因,因此我不知道如何压缩它以产生相同的错误。

extern crate pomelo;
use pomelo::pomelo;
pomelo!{
   %error String;
   %syntax_error{
       Err(format!("syntax {:?}",token))
   }
   %parse_fail {
        "Giving up.  Parser is hopelessly lost...".to_string()
   }
   %token #[derive(Debug)] pub enum Token {};
   //define types to make the compiler happy
   %type Ident String;
   %type Type String;
   %type Num i64;
   %type String String;
   %type expr Vec<String>;
   %type expr_list Vec<Vec<String>>;
   %type stmt Vec<String>;
   %type input Option<Vec<Vec<String>>>;
   %type block Vec<Vec<String>>;
   %type decl_list Vec<Vec<String>>;
   %type stmt_list Vec<Vec<String>>;
   %type func_list Vec<Vec<String>>;
   %type arg_list Vec<String>;
   %type type_list Vec<String>;
   %type package String;
   %type imports Vec<String>;
   %type f_decl Vec<String>;
   %type type_t Vec<Vec<String>>;
   %type type_s Vec<Vec<String>>;
   %type decl Vec<Vec<String>>;
   %type assignment String;
   %type CheckMark String;
   %type Todo String;
   %left Else;
   %right Eq;
   %left Or;
   %left And;
   %nonassoc Equal Neq;
   %nonassoc Less LessEq Greater GreaterEq;
   %left Add Sub;
   %left Mul Div;
   %nonassoc Not;
   input ::= type_s?(v) {v /*assigning worthless values to make the compiler happy*/};
   type_t ::= stmt(a) {vec![a]}
   type_s ::= type_t(t) {t}
   type_s ::= type_s(mut a) type_t(b) {a.extend(b);a}
   stmt ::= KeyFunction Ident(name) LParen arg_list?(args) RParen block(code) {vec![name]}
   assignment ::= Ident(a) Eq expr(b) {a}
   arg_list ::= Ident(n)  [Semicolon] { vec![n] }
   arg_list ::= assignment(n) {vec![n]}
   arg_list ::= arg_list(mut args) Comma Ident(n) { args.push(n); args }
   block ::= LBrace stmt_list?(ss) RBrace { ss.unwrap_or(Vec::new()) }
   stmt_list ::= stmt(s) { vec![s] }
   stmt_list ::= stmt_list(mut ss) stmt(s) { ss.push(s); ss }
   stmt ::= block(ss) { ss.get(0).unwrap_or(&Vec::new()).clone() }
   stmt ::= expr(e) Semicolon {e}
   stmt ::= Ident(a) Eq expr(b) Semicolon { vec![a] }
   stmt ::= Var Ident(a) Eq expr(b) Semicolon { vec![a]}    
   stmt ::= If LParen expr(e) RParen stmt(s1) Else stmt(s2) {println!("should execute this"); s1  }
   stmt ::= If LParen expr(e) RParen stmt(s1) [Else] {println!("should not execute this"); s1 }
   stmt ::= While LParen expr(e) RParen stmt(s) { s }
   stmt ::= Return expr(e) Semicolon { e }
   stmt ::= Return Semicolon { vec!["".to_string()] }
   stmt ::= Break Semicolon { vec!["".to_string()] }
   stmt ::= Continue Semicolon {vec!["".to_string()] }
   stmt ::= Todo(a) expr(b) Semicolon {vec![a]}
   stmt ::= CheckMark(a) {vec![a]}
   expr ::= Num(n) { vec!["".to_string()] }
   expr ::= String(n) {vec!["".to_string()]}
   expr ::= Ident(n) {vec!["".to_string()] }
   expr ::= Ident(n) LParen expr_list?(es) RParen {vec![n]}
   expr ::= LParen expr(e) RParen { e }
   expr ::= expr(a) Add expr(b) { a}
   expr ::= expr(a) Sub expr(b) { a }
   expr ::= expr(a) Mul expr(b) {a}
   expr ::= expr(a) Div expr(b) {a}
   expr ::= Sub expr(a) [Not]     { a }
   expr ::= expr(a) Equal expr(b) { a }
   expr ::= expr(a) Neq expr(b) { a }
   expr ::= expr(a) And expr(b) { a }
   expr ::= expr(a) Or expr(b) {a }
   expr ::= Not expr(a) { a }
   expr ::= expr(a) Less expr(b) { a }
   expr ::= expr(a) Greater expr(b) { a }
   expr ::= expr(a) LessEq expr(b) { a }
   expr ::= expr(a) GreaterEq expr(b) { a }
   expr_list ::= expr(e) { vec![e] }
   expr_list ::= expr_list(mut es) Comma expr(e) { es.push(e); es }
}
fn main() {
    let mut parse = parser::Parser::new();
    let code = vec![
        parser::Token::If,
        parser::Token::LParen,
        parser::Token::Num(1),
        parser::Token::RParen,
        parser::Token::LBrace,
        parser::Token::Return,
        parser::Token::Semicolon,
        parser::Token::RBrace,
        parser::Token::Else,
        parser::Token::LBrace,
        parser::Token::Return,
        parser::Token::Semicolon,
        parser::Token::RBrace   
    ];
    for i in code {
        println!("gettin {:?}",i);
        parse.parse(i).unwrap();
    }
    parse.end_of_input().unwrap();
}

对于遇到类似问题的任何人,问题是 else 标记的关联性,将 else 标记从左关联更改为右关联就可以解决问题