Как представить утверждение if-else в форме backus naur с использованием ржавчины и помело?

#parsing #rust #syntax #syntax-error #bnf

Вопрос:

Я пытаюсь использовать pomelo в rust для анализа языка сценариев и столкнулся с препятствием в представлении языка backus-naur, он не может анализировать операторы if-else так, как я их определил. например, если бы он анализировал оператор

 if (1) {
  return;
}
 

синтаксический анализатор удался бы, но если бы я добавил в код другое утверждение, например

 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(amp;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();
}
 

Ответ №1:

Для любого, кто столкнется с подобной проблемой, проблема заключалась в ассоциативности токена else, изменение токена else с левой ассоциации на правую ассоциацию сделало свое дело