I have put together a grammar in Lemon (which is similar to YACC) but it is producing an S/R conflict.
I am not used to LALR parsing and don't understand what the problem is, nor how to resolve it.
The grammar is:
%right EQUALS.
%right RIGHT_ASSIGN LEFT_ASSIGN MOD_ASSIGN DIV_ASSIGN MUL_ASSIGN.
%right QUESTION COLON.
%left EQ_OP.
%left NE_OP LE_OP GE_OP LCARET RCARET.
%left PLUS MINUS.
%left STAR PERCENT FSLASH.
%right UNA.
%left DOT PTR_OP.
%left UN.
%left LBRACKET LSBRACKET RBRACKET RSBRACKET.
%right DOTACCESS.
file ::= statement_list EOF.
statement_break ::= EOL.
statement_list ::= statement statement_break.
statement_list ::= statement_list statement statement_break.
statement ::= expr.
statement ::= assign_expr argument_expr_list. [UN]
primary_expr
::= IDENTIFIER.
primary_expr
::= CONSTANT.
primary_expr
::= STRING_LITERAL.
primary_expr
::= LBRACKET expr RBRACKET.
postfix_expr
::= primary_expr.
postfix_expr
::= postfix_expr LSBRACKET expr RSBRACKET. [UN]
postfix_expr
::= postfix_expr LBRACKET RBRACKET. [UN]
postfix_expr
::= postfix_expr LBRACKET argument_expr_list RBRACKET. [UN]
postfix_expr
::= postfix_expr DOT IDENTIFIER. [DOTACCESS]
postfix_expr
::= postfix_expr PTR_OP IDENTIFIER. [DOTACCESS]
postfix_expr
::= postfix_expr INC_OP.
postfix_expr
::= postfix_expr DEC_OP.
argument_expr_list
::= assign_expr.
argument_expr_list
::= argument_expr_list COMMA assign_expr.
unary_expr
::= postfix_expr.
unary_expr
::= unary_operator cast_expr. [UNA]
unary_expr
::= SIZEOF unary_expr. [UN]
unary_expr
::= SIZEOF LBRACKET type_name RBRACKET. [UN]
unary_operator
::= EXCLAMATION.
cast_expr
::= unary_expr.
cast_expr
::= LBRACKET type_name RBRACKET cast_expr. [UNA]
mul_expr
::= cast_expr.
mul_expr
::= mul_expr STAR cast_expr.
mul_expr
::= mul_expr FSLASH cast_expr.
mul_expr
::= mul_expr PERCENT cast_expr.
add_expr
::= mul_expr.
add_expr
::= add_expr PLUS mul_expr.
add_expr
::= add_expr MINUS mul_expr.
shift_expr
::= add_expr.
shift_expr
::= shift_expr LEFT_OP add_expr.
shift_expr
::= shift_expr RIGHT_OP add_expr.
rel_expr
::= shift_expr.
rel_expr
::= rel_expr LCARET shift_expr.
rel_expr
::= rel_expr RCARET shift_expr.
rel_expr
::= rel_expr LE_OP shift_expr.
rel_expr
::= rel_expr GE_OP shift_expr.
eq_expr
::= rel_expr.
eq_expr
::= eq_expr EQ_OP rel_expr.
eq_expr
::= eq_expr NE_OP rel_expr.
and_expr
::= eq_expr.
and_expr
::= and_expr AND eq_expr.
excl_or_expr
::= and_expr.
excl_or_expr
::= excl_or_expr HAT and_expr.
incl_or_expr
::= excl_or_expr.
incl_or_expr
::= incl_or_expr BAR excl_or_expr.
log_and_expr
::= incl_or_expr.
log_and_expr
::= log_and_expr AND_OP incl_or_expr.
log_or_expr
::= log_and_expr.
log_or_expr
::= log_or_expr OR_OP log_and_expr.
cond_expr
::= log_or_expr.
cond_expr
::= log_or_expr QUESTION expr COLON cond_expr.
assign_expr
::= cond_expr.
assign_expr
::= unary_expr assign_op assign_expr.
assign_op
::= EQUALS. [EQUALS]
assign_op
::= MUL_ASSIGN. [EQUALS]
assign_op
::= DIV_ASSIGN. [EQUALS]
assign_op
::= MOD_ASSIGN. [EQUALS]
assign_op
::= ADD_ASSIGN. [EQUALS]
assign_op
::= SUB_ASSIGN. [EQUALS]
assign_op
::= LEFT_ASSIGN. [EQUALS]
assign_op
::= RIGHT_ASSIGN. [EQUALS]
assign_op
::= AND_ASSIGN. [EQUALS]
assign_op
::= XOR_ASSIGN. [EQUALS]
assign_op
::= OR_ASSIGN. [EQUALS]
expr
::= assign_expr.
expr
::= expr COMMA assign_expr.
type_name
::= TYPE.
and the output from Lemon is:
State 4:
primary_expr ::= * IDENTIFIER
primary_expr ::= * CONSTANT
primary_expr ::= * STRING_LITERAL
primary_expr ::= * LBRACKET expr RBRACKET
postfix_expr ::= * primary_expr
postfix_expr ::= * postfix_expr LSBRACKET expr RSBRACKET
postfix_expr ::= * postfix_expr LBRACKET RBRACKET
postfix_expr ::= postfix_expr LBRACKET * RBRACKET
postfix_expr ::= * postfix_expr LBRACKET argument_expr_list RBRACKET
postfix_expr ::= postfix_expr LBRACKET * argument_expr_list RBRACKET
postfix_expr ::= * postfix_expr DOT IDENTIFIER
postfix_expr ::= * postfix_expr PTR_OP IDENTIFIER
postfix_expr ::= * postfix_expr INC_OP
postfix_expr ::= * postfix_expr DEC_OP
argument_expr_list ::= * assign_expr
argument_expr_list ::= * argument_expr_list COMMA assign_expr
unary_expr ::= * postfix_expr
unary_expr ::= * unary_operator cast_expr
unary_expr ::= * SIZEOF unary_expr
unary_expr ::= * SIZEOF LBRACKET type_name RBRACKET
unary_operator ::= * EXCLAMATION
cast_expr ::= * unary_expr
cast_expr ::= * LBRACKET type_name RBRACKET cast_expr
mul_expr ::= * cast_expr
mul_expr ::= * mul_expr STAR cast_expr
mul_expr ::= * mul_expr FSLASH cast_expr
mul_expr ::= * mul_expr PERCENT cast_expr
add_expr ::= * mul_expr
add_expr ::= * add_expr PLUS mul_expr
add_expr ::= * add_expr MINUS mul_expr
shift_expr ::= * add_expr
shift_expr ::= * shift_expr LEFT_OP add_expr
shift_expr ::= * shift_expr RIGHT_OP add_expr
rel_expr ::= * shift_expr
rel_expr ::= * rel_expr LCARET shift_expr
rel_expr ::= * rel_expr RCARET shift_expr
rel_expr ::= * rel_expr LE_OP shift_expr
rel_expr ::= * rel_expr GE_OP shift_expr
eq_expr ::= * rel_expr
eq_expr ::= * eq_expr EQ_OP rel_expr
eq_expr ::= * eq_expr NE_OP rel_expr
and_expr ::= * eq_expr
and_expr ::= * and_expr AND eq_expr
excl_or_expr ::= * and_expr
excl_or_expr ::= * excl_or_expr HAT and_expr
incl_or_expr ::= * excl_or_expr
incl_or_expr ::= * incl_or_expr BAR excl_or_expr
log_and_expr ::= * incl_or_expr
log_and_expr ::= * log_and_expr AND_OP incl_or_expr
log_or_expr ::= * log_and_expr
log_or_expr ::= * log_or_expr OR_OP log_and_expr
cond_expr ::= * log_or_expr
cond_expr ::= * log_or_expr QUESTION expr COLON cond_expr
assign_expr ::= * cond_expr
assign_expr ::= * unary_expr assign_op assign_expr
LBRACKET shift 2
RBRACKET shift-reduce 12 postfix_expr ::= postfix_expr LBRACKET RBRACKET
IDENTIFIER shift-reduce 6 primary_expr ::= IDENTIFIER
CONSTANT shift-reduce 7 primary_expr ::= CONSTANT
STRING_LITERAL shift-reduce 8 primary_expr ::= STRING_LITERAL
SIZEOF shift 32
EXCLAMATION shift-reduce 24 unary_operator ::= EXCLAMATION
assign_expr shift 43 /* because assign_expr==argument_expr_list */
argument_expr_list shift 43
primary_expr shift 36 /* because primary_expr==postfix_expr */
postfix_expr shift 36
unary_expr shift 33
unary_operator shift 31
cast_expr shift 42 /* because cast_expr==mul_expr */
mul_expr shift 42
add_expr shift 55
shift_expr shift 54
rel_expr shift 39
eq_expr shift 47
and_expr shift 69
excl_or_expr shift 68
incl_or_expr shift 66
log_and_expr shift 64
log_or_expr shift 45
cond_expr shift 43 /* because cond_expr==assign_expr */
State 20:
primary_expr ::= * IDENTIFIER
primary_expr ::= * CONSTANT
primary_expr ::= * STRING_LITERAL
primary_expr ::= * LBRACKET expr RBRACKET
postfix_expr ::= * primary_expr
postfix_expr ::= * postfix_expr LSBRACKET expr RSBRACKET
postfix_expr ::= * postfix_expr LBRACKET RBRACKET
postfix_expr ::= * postfix_expr LBRACKET argument_expr_list RBRACKET
postfix_expr ::= * postfix_expr DOT IDENTIFIER
postfix_expr ::= * postfix_expr PTR_OP IDENTIFIER
postfix_expr ::= * postfix_expr INC_OP
postfix_expr ::= * postfix_expr DEC_OP
unary_expr ::= * postfix_expr
unary_expr ::= * unary_operator cast_expr
unary_expr ::= * SIZEOF unary_expr
unary_expr ::= * SIZEOF LBRACKET type_name RBRACKET
unary_operator ::= * EXCLAMATION
cast_expr ::= * unary_expr
cast_expr ::= * LBRACKET type_name RBRACKET cast_expr
mul_expr ::= * cast_expr
mul_expr ::= * mul_expr STAR cast_expr
mul_expr ::= * mul_expr FSLASH cast_expr
mul_expr ::= * mul_expr PERCENT cast_expr
add_expr ::= * mul_expr
add_expr ::= * add_expr PLUS mul_expr
add_expr ::= * add_expr MINUS mul_expr
shift_expr ::= * add_expr
shift_expr ::= * shift_expr LEFT_OP add_expr
shift_expr ::= * shift_expr RIGHT_OP add_expr
rel_expr ::= rel_expr LE_OP * shift_expr
LBRACKET shift 2
IDENTIFIER shift-reduce 6 primary_expr ::= IDENTIFIER
CONSTANT shift-reduce 7 primary_expr ::= CONSTANT
STRING_LITERAL shift-reduce 8 primary_expr ::= STRING_LITERAL
SIZEOF shift 32
EXCLAMATION shift-reduce 24 unary_operator ::= EXCLAMATION
primary_expr shift 36 /* because primary_expr==postfix_expr */
postfix_expr shift 36
unary_expr shift 42 /* because unary_expr==mul_expr */
unary_operator shift 31
cast_expr shift 42 /* because cast_expr==mul_expr */
mul_expr shift 42
add_expr shift 55
shift_expr shift 49
State 36:
postfix_expr ::= postfix_expr * LSBRACKET expr RSBRACKET
postfix_expr ::= postfix_expr * LBRACKET RBRACKET
postfix_expr ::= postfix_expr * LBRACKET argument_expr_list RBRACKET
postfix_expr ::= postfix_expr * DOT IDENTIFIER
postfix_expr ::= postfix_expr * PTR_OP IDENTIFIER
postfix_expr ::= postfix_expr * INC_OP
postfix_expr ::= postfix_expr * DEC_OP
(20) unary_expr ::= postfix_expr *
DOT shift 61
PTR_OP shift 60
LBRACKET shift 4
LBRACKET reduce 20 ** Parsing conflict **
LSBRACKET shift 7
INC_OP shift-reduce 16 postfix_expr ::= postfix_expr INC_OP
DEC_OP shift-reduce 17 postfix_expr ::= postfix_expr DEC_OP
{default} reduce 20 unary_expr ::= postfix_expr
You can find the conflict in the 'State 36' (I culled excess output). I believe it should be resolveable with Precedence rules but I cannot figure out how.
The conflict comes from the rule
statement ::= assign_expr argument_expr_list. [UN]
which seems to me to be completely unnecessary. Any statement derived from this production could also derived from
statement: expr.
So the grammar is ambiguous:
An example of an assign_expr would be a = b (unary_expr assign_op assign_expr). Another example would be a = sin(0.5). Since we also have statement ::= expr (and expr ::= assign_expr), a = sin(0.5) could be parsed as statement in two ways: as the assign_expr a = sin(0.5), reduced directly to expr, or as the assign_expr a = sin followed by argument_expr_list. It seems to me that the second case is never useful, and that the production should just be deleted from the grammar. But perhaps you have some specific semantic in mind.
Your grammar is full of precedence declarations which probably don't do any harm, but I doubt whether any of those precedence declarations have any effect whatsoever. It's certainly the case that the particular shift/reduce conflict being reported cannot be resolved by means of any of the precedence declarations, because the possible reduction is a unit rule which has no declared precedence. (unary_expr ::= postfix_expr.) Giving it a an arbitrary precedence might resolve the conflict, but it seems to me unlikely that it will resolve it in a useful way; however you resolve it, some other rule will become unusable, which is a bad sign.
Related
I have the following grammar rules:
%precedence KW2
%left "or"
%left "and"
%left "==" "!=" ">=" ">" "<=" "<"
%left "-" "+"
%left "/" "*"
%start statement1
%%
param
: id
| id ":" expr // Conflict is caused by this line
| id "=" expr
;
param_list
: param_list "," param
| param
;
defparam
: param_list "," "/"
| param_list "," "/" ","
;
param_arg_list
: defparam param_list
| param_list
;
statement1
: KEYWORD1 "(" param_arg_list ")" ":" expr {}
expression1
: KEYWORD2 param_arg_list ":" expr %prec KW2 {} // This causes shift/reduce conflicts
expr
: id
| expr "+" expr
| expr "-" expr
| expr "*" expr
| expr "/" expr
| expr "==" expr
| expr "!=" expr
| expr "<" expr
| expr "<=" expr
| expr ">" expr
| expr ">=" expr
| expr "and" expr
| expr "or" expr
| expression1
id
: TK_NAME {}
.output
State 33
12 param: id . [":", ",", ")"]
13 | id . ":" expr
14 | id . "=" expr
":" shift, and go to state 55
"=" shift, and go to state 56
":" [reduce using rule 12 (param)]
$default reduce using rule 12 (param)
The problem here is that, For the expression1, id ":" expr rule in param is not required, so If I remove id ":" expr, the conflicts are resolved. But, I can not remove id ":" expr rule in param, because statement1 requires it.
I wanted to use para_arg_list for statement1 and expression1 is that, it simplifies the grammar rules by not allowing to use the grammar rules again and again.
My question is that is there any other way to resolve the conflict?
I'm attempting to use pomelo in rust to parse a scripting language and have reached a roadblock in the backus-naur representation of the language, it cannot parse if-else statements the way i've defined them.
for example, if it were to parse the statement
if (1) {
return;
}
the parser would succeed, but if I were to add an else statment to the code, like
if (1) {
return;
} else {
return;
}
it will throw a syntax error at the else token, specifically,
the output I get is
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
It doesn't seem obvious to me why this is failing when looking at the bnf form.
Im sorry for the large amount of code for this minimal reproducible example but I don't know the exact cause of the error in the bnf form and thus I don't know how to condense it to produce the same errors.
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();
}
For anyone who stumbles across a similar problem, the issue was the associativity of the else token, changing the else token from left association to right association did the trick
I'm trying to create a parser for a simple language, but I can't get rid of some reduce/reduce conflicts because of the rules expr: l_value and r_value: '#' l_value. I tried to fix it determining a precedence for the symbol '#' but it didn't help. A minimal, reproducible example is that:
%{
#include <cstdio>
#include "lexer.hpp"
%}
%define parse.error verbose /*to help me debug the parser*
%token T_if "if"
%token T_then "then"
%token T_do "do"
%token T_begin "begin"
%token T_end "end"
%token T_and "and"
%token T_of "of"
%token T_array "array"
%token T_else "else"
%token T_integer "integer"
%token T_or "or"
%token T_true "true"
%token T_label "label"
%token T_procedure "procedure"
%token T_var "var"
%token T_boolean "boolean"
%token T_false "false"
%token T_mod "mod"
%token T_program "program"
%token T_while "while"
%token T_char "char"
%token T_forward "forward"
%token T_new "new"
%token T_real "real"
%token T_dispose "dispose"
%token T_function "function"
%token T_nil "nil"
%token T_result "result"
%token T_div "div"
%token T_goto "goto"
%token T_not "not"
%token T_return "return"
%token T_id
%token T_realnum
%token T_int
%token T_character
%token T_string
%token T_assign ":="
%token T_greaterequal ">="
%token T_lessequal "<="
%token T_notequal "<>"
%nonassoc '=' '<' '>' "<=" ">=" "<>" ":="
%left '+' '-' "or"
%left '*' '/' "div" "mod" "and"
%left UMINUS
%right '^'
%left '#'
%left '[' '('
%expect 1
%%
expr:
l_value
|r_value
;
l_value:
T_id
|"result"
|T_string
|l_value '[' expr ']'
|expr '^'
|'(' l_value ')'
;
r_value:
T_int
|"true"
|"false"
|T_realnum
|T_character
|'(' r_value ')'
|"nil"
|call
| expr '<' expr
| expr '>' expr
| expr "<=" expr
| expr ">=" expr
| expr '=' expr
| expr "<>" expr
| expr '+' expr
| expr '-' expr
| expr "or" expr
| expr '*' expr
| expr '/' expr
| expr "and" expr
| expr "div" expr
| expr "mod" expr
|"not" expr %prec UMINUS
|'+' expr %prec UMINUS
|'-' expr %prec UMINUS
|'#' l_value
;
call:
T_id '(' expr text6
;
text6:
')' | ',' expr text6
;
%%
extern int lineno;
int main() {
#ifdef YYDEBUG
yydebug = 1;
#endif
int result = yyparse();
if (result == 0) printf("Success.\n");
return result;
}
`
In parser.output I get this:
1 expr: l_value .
6 l_value: l_value . '[' expr ']'
34 r_value: '#' l_value .
'[' shift, and go to state 43
$end reduce using rule 34 (r_value)
"and" reduce using rule 1 (expr)
"and" [reduce using rule 34 (r_value)]
"or" reduce using rule 1 (expr)
"or" [reduce using rule 34 (r_value)]
"mod" reduce using rule 1 (expr)
"mod" [reduce using rule 34 (r_value)]
"div" reduce using rule 1 (expr)
"div" [reduce using rule 34 (r_value)]
">=" reduce using rule 1 (expr)
">=" [reduce using rule 34 (r_value)]
"<=" reduce using rule 1 (expr)
"<=" [reduce using rule 34 (r_value)]
"<>" reduce using rule 1 (expr)
"<>" [reduce using rule 34 (r_value)]
'=' reduce using rule 1 (expr)
'=' [reduce using rule 34 (r_value)]
'<' reduce using rule 1 (expr)
'<' [reduce using rule 34 (r_value)]
'>' reduce using rule 1 (expr)
'>' [reduce using rule 34 (r_value)]
'+' reduce using rule 1 (expr)
'+' [reduce using rule 34 (r_value)]
'-' reduce using rule 1 (expr)
'-' [reduce using rule 34 (r_value)]
'*' reduce using rule 1 (expr)
'*' [reduce using rule 34 (r_value)]
'/' reduce using rule 1 (expr)
'/' [reduce using rule 34 (r_value)]
'^' reduce using rule 1 (expr)
'^' [reduce using rule 34 (r_value)]
']' reduce using rule 34 (r_value)
')' reduce using rule 34 (r_value)
',' reduce using rule 34 (r_value)
$default reduce using rule 1 (expr)
Does anyone have or know where to find a EBNF grammar for OData URI query?
I want to use it with SableCC to generate C++ classes for parsing OData URI queries.
http://bottlecaps.de/convert does some conversion from ABNF to W3C-style EBNF.
But the ODATA grammar says:
; This grammar uses the ABNF defined in RFC5234 with one extension: literals
; enclosed in single quotes (e.g. '$metadata') are treated case-sensitive.
After manually reverting single quotes to double quotes, the converter will handle it, with the result shown below. It is directly suitable for producing syntax diagrams at http://bottlecaps.de/rr
/* converted on Tue Sep 2, 2014, 16:37 (UTC+02) by abnf-to-w3c v0.33.722 which is Copyright (c) 2011-2013 by Gunther Rademacher <grd#gmx.net> */
dummyStartRule
::= odataUri
| header
| primitiveValue
odataUri ::= serviceRoot odataRelativeUri?
serviceRoot
::= ( 'https' | 'http' ) '://' host ( ':' port )? '/' ( segment-nz '/' )*
odataRelativeUri
::= '$batch'
| '$entity' '?' entityOptions
| '$entity' '/' qualifiedEntityTypeName '?' entityCastOptions
| '$metadata' ( '?' format )? context?
| resourcePath ( '?' queryOptions )?
resourcePath
::= entitySetName collectionNavigation?
| singletonEntity singleNavigation?
| actionImportCall
| entityColFunctionImportCall collectionNavigation?
| entityFunctionImportCall singleNavigation?
| complexColFunctionImportCall collectionPath?
| complexFunctionImportCall complexPath?
| primitiveColFunctionImportCall collectionPath?
| primitiveFunctionImportCall singlePath?
| crossjoin
| '$all'
collectionNavigation
::= ( '/' qualifiedEntityTypeName )? collectionNavPath?
collectionNavPath
::= keyPredicate singleNavigation?
| collectionPath
| ref
keyPredicate
::= simpleKey
| compoundKey
simpleKey
::= OPEN keyPropertyValue CLOSE
compoundKey
::= OPEN keyValuePair ( COMMA keyValuePair )* CLOSE
keyValuePair
::= ( primitiveKeyProperty | keyPropertyAlias ) EQ keyPropertyValue
keyPropertyValue
::= primitiveLiteral
keyPropertyAlias
::= odataIdentifier
singleNavigation
::= ( '/' qualifiedEntityTypeName )? ( '/' propertyPath | boundOperation | ref | value )?
propertyPath
::= entityColNavigationProperty collectionNavigation?
| entityNavigationProperty singleNavigation?
| complexColProperty collectionPath?
| complexProperty complexPath?
| primitiveColProperty collectionPath?
| primitiveProperty singlePath?
| streamProperty boundOperation?
collectionPath
::= count
| boundOperation
singlePath
::= value
| boundOperation
complexPath
::= ( '/' qualifiedComplexTypeName )? ( '/' propertyPath | boundOperation )
count ::= '/$count'
ref ::= '/$ref'
value ::= '/$value'
boundOperation
::= '/' ( boundActionCall | boundEntityColFuncCall collectionNavigation? | boundEntityFuncCall singleNavigation? | boundComplexColFuncCall collectionPath? | boundComplexFuncCall complexPath? | boundPrimitiveColFuncCall collectionPath? | boundPrimitiveFuncCall singlePath? )
actionImportCall
::= actionImport
boundActionCall
::= namespace '.' action
boundEntityFuncCall
::= namespace '.' entityFunction functionParameters
boundEntityColFuncCall
::= namespace '.' entityColFunction functionParameters
boundComplexFuncCall
::= namespace '.' complexFunction functionParameters
boundComplexColFuncCall
::= namespace '.' complexColFunction functionParameters
boundPrimitiveFuncCall
::= namespace '.' primitiveFunction functionParameters
boundPrimitiveColFuncCall
::= namespace '.' primitiveColFunction functionParameters
entityFunctionImportCall
::= entityFunctionImport functionParameters
entityColFunctionImportCall
::= entityColFunctionImport functionParameters
complexFunctionImportCall
::= complexFunctionImport functionParameters
complexColFunctionImportCall
::= complexColFunctionImport functionParameters
primitiveFunctionImportCall
::= primitiveFunctionImport functionParameters
primitiveColFunctionImportCall
::= primitiveColFunctionImport functionParameters
functionParameters
::= OPEN ( functionParameter ( COMMA functionParameter )* )? CLOSE
functionParameter
::= parameterName EQ ( parameterAlias | primitiveLiteral )
parameterName
::= odataIdentifier
parameterAlias
::= AT odataIdentifier
crossjoin
::= '$crossjoin' OPEN entitySetName ( COMMA entitySetName )* CLOSE
queryOptions
::= queryOption ( '&' queryOption )*
queryOption
::= systemQueryOption
| aliasAndValue
| customQueryOption
entityOptions
::= ( entityIdOption '&' )* id ( '&' entityIdOption )*
entityIdOption
::= format
| customQueryOption
entityCastOptions
::= ( entityCastOption '&' )* id ( '&' entityCastOption )*
entityCastOption
::= entityIdOption
| expand
| select
id ::= '$id' EQ IRI-in-query
systemQueryOption
::= expand
| filter
| format
| id
| inlinecount
| orderby
| search
| select
| skip
| skiptoken
| top
expand ::= '$expand' EQ expandItem ( COMMA expandItem )*
expandItem
::= STAR ( ref | OPEN levels CLOSE )?
| expandPath ( ref ( OPEN expandRefOption ( SEMI expandRefOption )* CLOSE )? | count ( OPEN expandCountOption ( SEMI expandCountOption )* CLOSE )? | OPEN expandOption ( SEMI expandOption )* CLOSE )?
expandPath
::= ( qualifiedEntityTypeName '/' )? ( ( complexProperty | complexColProperty ) '/' ( qualifiedComplexTypeName '/' )? )* navigationProperty ( '/' qualifiedEntityTypeName )?
expandCountOption
::= filter
| search
expandRefOption
::= expandCountOption
| orderby
| skip
| top
| inlinecount
expandOption
::= expandRefOption
| select
| expand
| levels
levels ::= '$levels' EQ ( DIGIT+ | 'max' )
filter ::= '$filter' EQ boolCommonExpr
orderby ::= '$orderby' EQ orderbyItem ( COMMA orderbyItem )*
orderbyItem
::= commonExpr ( RWS ( 'asc' | 'desc' ) )?
skip ::= '$skip' EQ DIGIT+
top ::= '$top' EQ DIGIT+
format ::= '$format' EQ ( 'atom' | 'json' | 'xml' | pchar+ '/' pchar+ )
inlinecount
::= '$count' EQ booleanValue
search ::= '$search' EQ BWS searchExpr
searchExpr
::= ( OPEN BWS searchExpr BWS CLOSE | searchTerm ) ( searchOrExpr | searchAndExpr )?
searchOrExpr
::= RWS 'OR' RWS searchExpr
searchAndExpr
::= RWS ( 'AND' RWS )? searchExpr
searchTerm
::= ( 'NOT' RWS )? ( searchPhrase | searchWord )
searchPhrase
::= quotation-mark qchar-no-AMP-DQUOTE+ quotation-mark
searchWord
::= ALPHA+
select ::= '$select' EQ selectItem ( COMMA selectItem )*
selectItem
::= STAR
| allOperationsInSchema
| ( qualifiedEntityTypeName '/' )? ( selectProperty | qualifiedActionName | qualifiedFunctionName )
selectProperty
::= primitiveProperty
| primitiveColProperty
| navigationProperty
| selectPath ( '/' selectProperty )?
selectPath
::= ( complexProperty | complexColProperty ) ( '/' qualifiedComplexTypeName )?
allOperationsInSchema
::= namespace '.' STAR
qualifiedActionName
::= namespace '.' action
qualifiedFunctionName
::= namespace '.' function ( OPEN parameterNames CLOSE )?
parameterNames
::= parameterName ( COMMA parameterName )*
skiptoken
::= '$skiptoken' EQ qchar-no-AMP+
aliasAndValue
::= parameterAlias EQ parameterValue
parameterValue
::= arrayOrObject
| commonExpr
customQueryOption
::= customName ( EQ customValue )?
customName
::= qchar-no-AMP-EQ-AT-DOLLAR qchar-no-AMP-EQ*
customValue
::= qchar-no-AMP*
context ::= '#' contextFragment
contextFragment
::= 'Collection($ref)'
| '$ref'
| 'Collection(Edm.EntityType)'
| 'Collection(Edm.ComplexType)'
| singletonEntity
| qualifiedTypeName
| entitySet ( '/$deletedEntity' | '/$link' | '/$deletedLink' )
| entitySet keyPredicate '/' contextPropertyPath
| entitySet selectList? ( '/$entity' | '/$delta' )?
entitySet
::= entitySetName containmentNavigation* ( '/' qualifiedEntityTypeName )?
containmentNavigation
::= keyPredicate ( '/' qualifiedEntityTypeName )? ( '/' complexProperty ( '/' qualifiedComplexTypeName )? )* '/' navigationProperty
selectList
::= OPEN selectListItem ( COMMA selectListItem )* CLOSE
selectListItem
::= STAR
| allOperationsInSchema
| ( qualifiedEntityTypeName '/' )? ( qualifiedActionName | qualifiedFunctionName | selectListProperty )
selectListProperty
::= primitiveProperty
| primitiveColProperty
| navigationProperty '+'? selectList?
| selectPath ( '/' selectListProperty )?
contextPropertyPath
::= primitiveProperty
| primitiveColProperty
| complexColProperty
| complexProperty ( ( '/' qualifiedComplexTypeName )? '/' contextPropertyPath )?
commonExpr
::= ( primitiveLiteral | parameterAlias | arrayOrObject | rootExpr | firstMemberExpr | functionExpr | negateExpr | methodCallExpr | parenExpr | castExpr ) ( addExpr | subExpr | mulExpr | divExpr | modExpr )?
boolCommonExpr
::= ( isofExpr | boolMethodCallExpr | notExpr | commonExpr ( eqExpr | neExpr | ltExpr | leExpr | gtExpr | geExpr | hasExpr )? | boolParenExpr ) ( andExpr | orExpr )?
rootExpr ::= '$root/' ( entitySetName keyPredicate | singletonEntity ) singleNavigationExpr?
firstMemberExpr
::= memberExpr
| inscopeVariableExpr ( '/' memberExpr )?
memberExpr
::= ( qualifiedEntityTypeName '/' )? ( propertyPathExpr | boundFunctionExpr )
propertyPathExpr
::= entityColNavigationProperty collectionNavigationExpr?
| entityNavigationProperty singleNavigationExpr?
| complexColProperty collectionPathExpr?
| complexProperty complexPathExpr?
| primitiveColProperty collectionPathExpr?
| primitiveProperty singlePathExpr?
| streamProperty
inscopeVariableExpr
::= implicitVariableExpr
| lambdaVariableExpr
implicitVariableExpr
::= '$it'
lambdaVariableExpr
::= odataIdentifier
collectionNavigationExpr
::= ( '/' qualifiedEntityTypeName )? ( keyPredicate singleNavigationExpr? | collectionPathExpr )
singleNavigationExpr
::= '/' memberExpr
collectionPathExpr
::= count
| '/' boundFunctionExpr
| '/' anyExpr
| '/' allExpr
complexPathExpr
::= '/' ( qualifiedComplexTypeName '/' )? ( propertyPathExpr | boundFunctionExpr )
singlePathExpr
::= '/' boundFunctionExpr
boundFunctionExpr
::= functionExpr
functionExpr
::= namespace '.' ( entityColFunction functionExprParameters collectionNavigationExpr? | entityFunction functionExprParameters singleNavigationExpr? | complexColFunction functionExprParameters collectionPathExpr? | complexFunction functionExprParameters complexPathExpr? | primitiveColFunction functionExprParameters collectionPathExpr? | primitiveFunction functionExprParameters singlePathExpr? )
functionExprParameters
::= OPEN ( functionExprParameter ( COMMA functionExprParameter )* )? CLOSE
functionExprParameter
::= parameterName EQ ( parameterAlias | parameterValue )
anyExpr ::= 'any' OPEN BWS ( lambdaVariableExpr BWS COLON BWS lambdaPredicateExpr )? BWS CLOSE
allExpr ::= 'all' OPEN BWS lambdaVariableExpr BWS COLON BWS lambdaPredicateExpr BWS CLOSE
lambdaPredicateExpr
::= boolCommonExpr
methodCallExpr
::= indexOfMethodCallExpr
| toLowerMethodCallExpr
| toUpperMethodCallExpr
| trimMethodCallExpr
| substringMethodCallExpr
| concatMethodCallExpr
| lengthMethodCallExpr
| yearMethodCallExpr
| monthMethodCallExpr
| dayMethodCallExpr
| hourMethodCallExpr
| minuteMethodCallExpr
| secondMethodCallExpr
| fractionalsecondsMethodCallExpr
| totalsecondsMethodCallExpr
| dateMethodCallExpr
| timeMethodCallExpr
| roundMethodCallExpr
| floorMethodCallExpr
| ceilingMethodCallExpr
| distanceMethodCallExpr
| geoLengthMethodCallExpr
| totalOffsetMinutesMethodCallExpr
| minDateTimeMethodCallExpr
| maxDateTimeMethodCallExpr
| nowMethodCallExpr
boolMethodCallExpr
::= endsWithMethodCallExpr
| startsWithMethodCallExpr
| containsMethodCallExpr
| intersectsMethodCallExpr
containsMethodCallExpr
::= 'contains' OPEN BWS commonExpr BWS COMMA BWS commonExpr BWS CLOSE
startsWithMethodCallExpr
::= 'startswith' OPEN BWS commonExpr BWS COMMA BWS commonExpr BWS CLOSE
endsWithMethodCallExpr
::= 'endswith' OPEN BWS commonExpr BWS COMMA BWS commonExpr BWS CLOSE
lengthMethodCallExpr
::= 'length' OPEN BWS commonExpr BWS CLOSE
indexOfMethodCallExpr
::= 'indexof' OPEN BWS commonExpr BWS COMMA BWS commonExpr BWS CLOSE
substringMethodCallExpr
::= 'substring' OPEN BWS commonExpr BWS COMMA BWS commonExpr BWS ( COMMA BWS commonExpr BWS )? CLOSE
toLowerMethodCallExpr
::= 'tolower' OPEN BWS commonExpr BWS CLOSE
toUpperMethodCallExpr
::= 'toupper' OPEN BWS commonExpr BWS CLOSE
trimMethodCallExpr
::= 'trim' OPEN BWS commonExpr BWS CLOSE
concatMethodCallExpr
::= 'concat' OPEN BWS commonExpr BWS COMMA BWS commonExpr BWS CLOSE
yearMethodCallExpr
::= 'year' OPEN BWS commonExpr BWS CLOSE
monthMethodCallExpr
::= 'month' OPEN BWS commonExpr BWS CLOSE
dayMethodCallExpr
::= 'day' OPEN BWS commonExpr BWS CLOSE
hourMethodCallExpr
::= 'hour' OPEN BWS commonExpr BWS CLOSE
minuteMethodCallExpr
::= 'minute' OPEN BWS commonExpr BWS CLOSE
secondMethodCallExpr
::= 'second' OPEN BWS commonExpr BWS CLOSE
fractionalsecondsMethodCallExpr
::= 'fractionalseconds' OPEN BWS commonExpr BWS CLOSE
totalsecondsMethodCallExpr
::= 'totalseconds' OPEN BWS commonExpr BWS CLOSE
dateMethodCallExpr
::= 'date' OPEN BWS commonExpr BWS CLOSE
timeMethodCallExpr
::= 'time' OPEN BWS commonExpr BWS CLOSE
totalOffsetMinutesMethodCallExpr
::= 'totaloffsetminutes' OPEN BWS commonExpr BWS CLOSE
minDateTimeMethodCallExpr
::= 'mindatetime(' BWS ')'
maxDateTimeMethodCallExpr
::= 'maxdatetime(' BWS ')'
nowMethodCallExpr
::= 'now(' BWS ')'
roundMethodCallExpr
::= 'round' OPEN BWS commonExpr BWS CLOSE
floorMethodCallExpr
::= 'floor' OPEN BWS commonExpr BWS CLOSE
ceilingMethodCallExpr
::= 'ceiling' OPEN BWS commonExpr BWS CLOSE
distanceMethodCallExpr
::= 'geo.distance' OPEN BWS commonExpr BWS COMMA BWS commonExpr BWS CLOSE
geoLengthMethodCallExpr
::= 'geo.length' OPEN BWS commonExpr BWS CLOSE
intersectsMethodCallExpr
::= 'geo.intersects' OPEN BWS commonExpr BWS COMMA BWS commonExpr BWS CLOSE
boolParenExpr
::= OPEN BWS boolCommonExpr BWS CLOSE
parenExpr
::= OPEN BWS commonExpr BWS CLOSE
andExpr ::= RWS 'and' RWS boolCommonExpr
orExpr ::= RWS 'or' RWS boolCommonExpr
eqExpr ::= RWS 'eq' RWS commonExpr
neExpr ::= RWS 'ne' RWS commonExpr
ltExpr ::= RWS 'lt' RWS commonExpr
leExpr ::= RWS 'le' RWS commonExpr
gtExpr ::= RWS 'gt' RWS commonExpr
geExpr ::= RWS 'ge' RWS commonExpr
hasExpr ::= RWS 'has' RWS commonExpr
addExpr ::= RWS 'add' RWS commonExpr
subExpr ::= RWS 'sub' RWS commonExpr
mulExpr ::= RWS 'mul' RWS commonExpr
divExpr ::= RWS 'div' RWS commonExpr
modExpr ::= RWS 'mod' RWS commonExpr
negateExpr
::= '-' BWS commonExpr
notExpr ::= 'not' RWS boolCommonExpr
isofExpr ::= 'isof' OPEN BWS ( commonExpr BWS COMMA BWS )? qualifiedTypeName BWS CLOSE
castExpr ::= 'cast' OPEN BWS ( commonExpr BWS COMMA BWS )? qualifiedTypeName BWS CLOSE
arrayOrObject
::= complexColInUri
| complexInUri
| rootExprCol
| primitiveColInUri
complexColInUri
::= begin-array ( complexInUri ( value-separator complexInUri )* )? end-array
complexInUri
::= begin-object ( ( annotationInUri | primitivePropertyInUri | complexPropertyInUri | collectionPropertyInUri | navigationPropertyInUri ) ( value-separator ( annotationInUri | primitivePropertyInUri | complexPropertyInUri | collectionPropertyInUri | navigationPropertyInUri ) )* )? end-object
collectionPropertyInUri
::= quotation-mark primitiveColProperty quotation-mark name-separator primitiveColInUri
| quotation-mark complexColProperty quotation-mark name-separator complexColInUri
primitiveColInUri
::= begin-array ( primitiveLiteralInJSON ( value-separator primitiveLiteralInJSON )* )? end-array
complexPropertyInUri
::= quotation-mark complexProperty quotation-mark name-separator complexInUri
annotationInUri
::= quotation-mark namespace '.' termName quotation-mark name-separator ( complexInUri | complexColInUri | primitiveLiteralInJSON | primitiveColInUri )
primitivePropertyInUri
::= quotation-mark primitiveProperty quotation-mark name-separator primitiveLiteralInJSON
navigationPropertyInUri
::= singleNavPropInJSON
| collectionNavPropInJSON
singleNavPropInJSON
::= quotation-mark entityNavigationProperty quotation-mark name-separator rootExpr
collectionNavPropInJSON
::= quotation-mark entityColNavigationProperty quotation-mark name-separator rootExprCol
rootExprCol
::= begin-array ( rootExpr ( value-separator rootExpr )* )? end-array
begin-object
::= BWS ( '{' | '%7B' ) BWS
end-object
::= BWS ( '}' | '%7D' ) BWS
begin-array
::= BWS ( '[' | '%5B' ) BWS
end-array
::= BWS ( ']' | '%5D' ) BWS
quotation-mark
::= DQUOTE
| '%22'
name-separator
::= BWS COLON BWS
value-separator
::= BWS COMMA BWS
primitiveLiteralInJSON
::= stringInJSON
| numberInJSON
| 'true'
| 'false'
| 'null'
stringInJSON
::= quotation-mark charInJSON* quotation-mark
charInJSON
::= qchar-unescaped
| qchar-JSON-special
| escape ( quotation-mark | escape | ( '/' | '%2F' ) | 'b' | 'f' | 'n' | 'r' | 't' | 'u' HEXDIG HEXDIG HEXDIG HEXDIG )
qchar-JSON-special
::= SP
| ':'
| '{'
| '}'
| '['
| ']'
escape ::= '\'
| '%5C'
numberInJSON
::= '-'? int frac? exp?
int ::= '0'
| oneToNine DIGIT*
frac ::= '.' DIGIT+
exp ::= 'e' ( '-' | '+' )? DIGIT+
singleQualifiedTypeName
::= qualifiedEntityTypeName
| qualifiedComplexTypeName
| qualifiedTypeDefinitionName
| qualifiedEnumTypeName
| primitiveTypeName
qualifiedTypeName
::= singleQualifiedTypeName
| 'Collection' OPEN singleQualifiedTypeName CLOSE
qualifiedEntityTypeName
::= namespace '.' entityTypeName
qualifiedComplexTypeName
::= namespace '.' complexTypeName
qualifiedTypeDefinitionName
::= namespace '.' typeDefinitionName
qualifiedEnumTypeName
::= namespace '.' enumerationTypeName
namespace
::= namespacePart ( '.' namespacePart )*
namespacePart
::= odataIdentifier
entitySetName
::= odataIdentifier
singletonEntity
::= odataIdentifier
entityTypeName
::= odataIdentifier
complexTypeName
::= odataIdentifier
typeDefinitionName
::= odataIdentifier
enumerationTypeName
::= odataIdentifier
enumerationMember
::= odataIdentifier
termName ::= odataIdentifier
odataIdentifier
::= identifierLeadingCharacter identifierCharacter*
identifierLeadingCharacter
::= ALPHA
| '_'
identifierCharacter
::= ALPHA
| '_'
| DIGIT
primitiveTypeName
::= 'Edm.' ( 'Binary' | 'Boolean' | 'Byte' | 'Date' | 'DateTimeOffset' | 'Decimal' | 'Double' | 'Duration' | 'Guid' | 'Int16' | 'Int32' | 'Int64' | 'SByte' | 'Single' | 'Stream' | 'String' | 'TimeOfDay' | abstractSpatialTypeName concreteSpatialTypeName? )
abstractSpatialTypeName
::= 'Geography'
| 'Geometry'
concreteSpatialTypeName
::= 'Collection'
| 'LineString'
| 'MultiLineString'
| 'MultiPoint'
| 'MultiPolygon'
| 'Point'
| 'Polygon'
primitiveProperty
::= primitiveKeyProperty
| primitiveNonKeyProperty
primitiveKeyProperty
::= odataIdentifier
primitiveNonKeyProperty
::= odataIdentifier
primitiveColProperty
::= odataIdentifier
complexProperty
::= odataIdentifier
complexColProperty
::= odataIdentifier
streamProperty
::= odataIdentifier
navigationProperty
::= entityNavigationProperty
| entityColNavigationProperty
entityNavigationProperty
::= odataIdentifier
entityColNavigationProperty
::= odataIdentifier
action ::= odataIdentifier
actionImport
::= odataIdentifier
function ::= entityFunction
| entityColFunction
| complexFunction
| complexColFunction
| primitiveFunction
| primitiveColFunction
entityFunction
::= odataIdentifier
entityColFunction
::= odataIdentifier
complexFunction
::= odataIdentifier
complexColFunction
::= odataIdentifier
primitiveFunction
::= odataIdentifier
primitiveColFunction
::= odataIdentifier
entityFunctionImport
::= odataIdentifier
entityColFunctionImport
::= odataIdentifier
complexFunctionImport
::= odataIdentifier
complexColFunctionImport
::= odataIdentifier
primitiveFunctionImport
::= odataIdentifier
primitiveColFunctionImport
::= odataIdentifier
primitiveLiteral
::= nullValue
| booleanValue
| guidValue
| dateValue
| dateTimeOffsetValue
| timeOfDayValue
| decimalValue
| doubleValue
| singleValue
| sbyteValue
| byteValue
| int16Value
| int32Value
| int64Value
| string
| duration
| binary
| enum
| geographyCollection
| geographyLineString
| geographyMultiLineString
| geographyMultiPoint
| geographyMultiPolygon
| geographyPoint
| geographyPolygon
| geometryCollection
| geometryLineString
| geometryMultiLineString
| geometryMultiPoint
| geometryMultiPolygon
| geometryPoint
| geometryPolygon
primitiveValue
::= booleanValue
| guidValue
| durationValue
| dateValue
| dateTimeOffsetValue
| timeOfDayValue
| enumValue
| fullCollectionLiteral
| fullLineStringLiteral
| fullMultiPointLiteral
| fullMultiLineStringLiteral
| fullMultiPolygonLiteral
| fullPointLiteral
| fullPolygonLiteral
| decimalValue
| doubleValue
| singleValue
| sbyteValue
| byteValue
| int16Value
| int32Value
| int64Value
| binaryValue
nullValue
::= 'null'
binary ::= 'binary' SQUOTE binaryValue SQUOTE
binaryValue
::= ( base64char base64char base64char base64char )* ( base64b16 | base64b8 )?
base64b16
::= base64char base64char ( 'A' | 'E' | 'I' | 'M' | 'Q' | 'U' | 'Y' | 'c' | 'g' | 'k' | 'o' | 's' | 'w' | '0' | '4' | '8' ) '='?
base64b8 ::= base64char ( 'A' | 'Q' | 'g' | 'w' ) '=='?
base64char
::= ALPHA
| DIGIT
| '-'
| '_'
booleanValue
::= 'true'
| 'false'
decimalValue
::= SIGN? DIGIT+ ( '.' DIGIT+ )?
doubleValue
::= decimalValue ( 'e' SIGN? DIGIT+ )?
| nanInfinity
singleValue
::= doubleValue
nanInfinity
::= 'NaN'
| '-INF'
| 'INF'
guidValue
::= HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG '-' HEXDIG HEXDIG HEXDIG HEXDIG '-' HEXDIG HEXDIG HEXDIG HEXDIG '-' HEXDIG HEXDIG HEXDIG HEXDIG '-' HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG HEXDIG+
byteValue
::= DIGIT ( DIGIT DIGIT? )?
sbyteValue
::= SIGN? DIGIT ( DIGIT DIGIT? )?
int16Value
::= SIGN? DIGIT ( DIGIT ( DIGIT ( DIGIT DIGIT? )? )? )?
int32Value
::= SIGN? DIGIT+
int64Value
::= SIGN? DIGIT+
string ::= SQUOTE ( SQUOTE-in-string | pchar-no-SQUOTE )* SQUOTE
SQUOTE-in-string
::= SQUOTE SQUOTE
dateValue
::= year '-' month '-' day
dateTimeOffsetValue
::= year '-' month '-' day 'T' hour ':' minute ( ':' second ( '.' fractionalSeconds )? )? ( 'Z' | SIGN hour ':' minute )
duration ::= 'duration' SQUOTE durationValue SQUOTE
durationValue
::= SIGN? 'P' ( DIGIT+ 'D' )? ( 'T' ( DIGIT+ 'H' )? ( DIGIT+ 'M' )? ( DIGIT+ ( '.' DIGIT+ )? 'S' )? )?
timeOfDayValue
::= hour ':' minute ( ':' second ( '.' fractionalSeconds )? )?
oneToNine
::= '1'
| '2'
| '3'
| '4'
| '5'
| '6'
| '7'
| '8'
| '9'
zeroToFiftyNine
::= ( '0' | '1' | '2' | '3' | '4' | '5' ) DIGIT
year ::= '-'? ( '0' DIGIT DIGIT DIGIT | oneToNine DIGIT DIGIT DIGIT+ )
// ... remainder omitted, because too large for SO post
If the ABNF grammar would also be OK, you can find the ABNF construction rules for OData V4 URIs here.
I'm writing a GoldParser VBScript grammar. In my grammar array assignment statements such as id(1) = 2 are not parsed as assignment statements, but as call statements id ((1) = 2) (the = symbol can be both the assignment operator and the comparison operator). How can I change the following grammar to correctly parse array assignment statements?
<CallStmt> ::= 'Call' <CallExpr>
| '.' <CallPath>
| <CallPath>
<AssignStmt> ::= <CallExpr> '=' <Expr>
| 'Set' <CallExpr> '=' <Expr>
| 'Set' <CallExpr> '=' 'New' <CtorPath>
<CtorPath> ::= IDDot <CtorPath>
| <Member>
<CallPath> ::= <MemberDot> <CallPath>
| ID '(' ')'
| ID <ParameterList>
<CallExpr> ::= '.' <MemberPath>
| <MemberPath>
<MemberPath> ::= <MemberDot> <MemberPath>
| <Member>
<Member> ::= ID
| ID '(' <ParameterList> ')'
<MemberDot> ::= IDDot
| ID '(' <ParameterList> ').'
!VBScript allows to skip parameters a(1,,2)
<ParameterList> ::= <Expr> ',' <ParameterList>
| ',' <ParameterList>
| <Expr>
|
! Value can be reduced from <Expr>
<Value> ::= NumberLiteral
| StringLiteral
| <CallExpr>
| '(' <Expr> ')'
!--- The rest of the grammar ---
"Start Symbol" = <Start>
{WS} = {Whitespace} - {CR} - {LF}
{ID Head} = {Letter} + [_]
{ID Tail} = {Alphanumeric} + [_]
{String Chars} = {Printable} + {HT} - ["]
Whitespace = {WS}+
NewLine = {CR}{LF} | {CR} | {LF}
ID = {ID Head}{ID Tail}*
IDDot = {ID Head}{ID Tail}* '.'
StringLiteral = ('"' {String Chars}* '"')+
NumberLiteral = {Number}+ ('.' {Number}+ )?
<nl> ::= NewLine <nl> !One or more
| NewLine
<nl Opt> ::= NewLine <nl Opt> !Zero or more
| !Empty
<Start> ::= <nl opt> <StmtList>
<StmtList> ::= <CallStmt> <nl> <StmtList>
| <AssignStmt> <nl> <StmtList>
|
<Expr> ::= <Compare Exp>
<Compare Exp> ::= <Compare Exp> '=' <Add Exp>
| <Add Exp>
<Add Exp> ::= <Add Exp> '+' <Mult Exp>
| <Add Exp> '-' <Mult Exp>
| <Mult Exp>
<Mult Exp> ::= <Mult Exp> '*' <Negate Exp>
| <Mult Exp> '/' <Negate Exp>
| <Negate Exp>
<Negate Exp> ::= '-' <Value>
| <Value>
Note: I added the IDDot terminal to parse statements within With correctly, e.g: .obj.sub .obj.par1.