#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 с левой ассоциации на правую ассоциацию сделало свое дело