EBNF grammar for OData URI query - odata

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.

Related

tatsu.exceptions.FailedParse while using a C BNF grammar adapted to Tatsu

tatsu.exceptions.FailedParse: (52:24) expecting one of: "'" '"' :
declarator = {pointer}? direct_declarator ;
^
I found a C BNF grammar here: https://cs.wmich.edu/~gupta/teaching/cs4850/sumII06/The%20syntax%20of%20C%20in%20Backus-Naur%20form.htm
I adapted so it can work with tatsu, but I'm not sure I did everything right.
The tatsu grammar:
translation_unit = {external_declaration}* ;
external_declaration = function_definition
| declaration ;
function_definition = {declaration_specifier}* declarator {declaration}* compound_statement ;
declaration_specifier = storage_class_specifier
| type_specifier
| type_qualifier ;
storage_class_specifier = "auto"
| "register"
| "static"
| "extern"
| "typedef" ;
type_specifier = "void"
| "char"
| "short"
| "int"
| "long"
| "float"
| "double"
| "signed"
| "unsigned"
| struct_or_union_specifier
| enum_specifier
| typedef_name ;
struct_or_union_specifier = struct_or_union identifier "{" {struct_declaration}+ "}"
| struct_or_union "{" {struct_declaration}+ "}"
| struct_or_union identifier ;
struct_or_union = "struct"
| "union" ;
struct_declaration = {specifier_qualifier}* struct_declarator_list ;
specifier_qualifier = type_specifier
| type_qualifier ;
struct_declarator_list = struct_declarator
| struct_declarator_list "," struct_declarator ;
struct_declarator = declarator
| declarator ":" constant_expression
| ":" constant_expression ;
declarator = {pointer}? direct_declarator ;
pointer = "*" {type_qualifier}* {pointer}? ;
type_qualifier = "const"
| "volatile" ;
direct_declarator = identifier
| "(" declarator ")"
| direct_declarator "[" {constant_expression}? "]"
| direct_declarator "(" parameter_type_list ")"
| direct_declarator "(" {identifier}* ")" ;
constant_expression = conditional_expression ;
conditional_expression = logical_or_expression
| logical_or_expression "?" expression ":" conditional_expression ;
logical_or_expression = logical_and_expression
| logical_or_expression "||" logical_and_expression ;
logical_and_expression = inclusive_or_expression
| logical_and_expression "&&" inclusive_or_expression ;
inclusive_or_expression = exclusive_or_expression
| inclusive_or_expression "|" exclusive_or_expression ;
exclusive_or_expression = and_expression
| exclusive_or_expression "^" and_expression ;
and_expression = equality_expression
| and_expression "&" equality_expression ;
equality_expression = relational_expression
| equality_expression "==" relational_expression
| equality_expression "!=" relational_expression ;
relational_expression = shift_expression
| relational_expression "<" shift_expression
| relational_expression ">" shift_expression
| relational_expression "<=" shift_expression
| relational_expression ">=" shift_expression ;
shift_expression = additive_expression
| shift_expression "<<" additive_expression
| shift_expression ">>" additive_expression ;
additive_expression = multiplicative_expression
| additive_expression "+" multiplicative_expression
| additive_expression "-" multiplicative_expression ;
multiplicative_expression = cast_expression
| multiplicative_expression "*" cast_expression
| multiplicative_expression "/" cast_expression
| multiplicative_expression "%" cast_expression ;
cast_expression = unary_expression
| "(" type_name ")" cast_expression ;
unary_expression = postfix_expression
| "++" unary_expression
| "--" unary_expression
| unary_operator cast_expression
| "sizeof" unary_expression
| "sizeof" type_name ;
postfix_expression = primary_expression
| postfix_expression "[" expression "]"
| postfix_expression "(" {assignment_expression}* ")"
| postfix_expression "." identifier
| postfix_expression "->" identifier
| postfix_expression "++"
| postfix_expression "--" ;
primary_expression = identifier
| constant
| string
| "(" expression ")" ;
constant = integer_constant
| character_constant
| floating_constant
| enumeration_constant ;
expression = assignment_expression
| expression "," assignment_expression ;
assignment_expression = conditional_expression
| unary_expression assignment_operator assignment_expression ;
assignment_operator = "="
| "/="
| "*="
| "%="
| "+="
| "-="
| "<<="
| ">>="
| "&="
| "^="
| "|=" ;
unary_operator = "&"
| "*"
| "+"
| "-"
| "~"
| "!" ;
type_name = {specifier_qualifier}+ {abstract_declarator}? ;
parameter_type_list = parameter_list
| parameter_list "," "..." ;
parameter_list = parameter_declaration
| parameter_list "," parameter_declaration ;
parameter_declaration = {declaration_specifier}+ declarator
| {declaration_specifier}+ abstract_declarator
| {declaration_specifier}+ ;
abstract_declarator = pointer
| pointer direct_abstract_declarator
| direct_abstract_declarator ;
direct_abstract_declarator = "(" abstract_declarator ")"
| {direct_abstract_declarator}? "[" {constant_expression}? "]"
| {direct_abstract_declarator}? "(" {parameter_type_list}? ")" ;
enum_specifier = "enum" identifier "{" enumerator_list "}"
| "enum" "{" enumerator_list "}"
| "enum" identifier ;
enumerator_list = enumerator
| enumerator_list "," enumerator ;
enumerator = identifier
| identifier "=" constant_expression ;
typedef_name = identifier ;
declaration = {declaration_specifier}+ {init_declarator}* ";" ;
init_declarator = declarator
| declarator "=" initializer ;
initializer = assignment_expression
| "{" initializer_list "}"
| "{" initializer_list "," "}" ;
initializer_list = initializer
| initializer_list "," initializer ;
compound_statement = "{" {declaration}* {statement}* "}" ;
statement = labeled_statement
| expression_statement
| compound_statement
| selection_statement
| iteration_statement
| jump_statement ;
labeled_statement = identifier ":" statement
| "case" constant_expression ":" statement
| "default" ":" statement ;
expression_statement = {expression}? ";" ;
selection_statement = "if" "(" expression ")" statement
| "if" "(" expression ")" statement "else" statement
| "switch" "(" expression ")" statement ;
iteration_statement = "while" "(" expression ")" statement
| "do" statement "while" "(" expression ")" ";"
| "for" "(" {expression}? ";" {expression}? ";" {expression}? ")" statement ;
jump_statement = "goto" identifier ";"
| "continue" ";"
| "break" ";"
| "return" {expression}? ";" ;
The C code:
int func(int i, char c) {
float f = 3;
}
The python code:
def main():
import pprint
import json
from tatsu import parse
from tatsu.util import asjson
csample = open('sample.c').read()
gram = open('cbnf_tatsu.txt').read()
ast = parse(gram, csample)
print('PPRINT')
pprint.pprint(ast, indent=2, width=20)
print()
print('JSON')
print(json.dumps(asjson(ast), indent=2))
print()
if __name__ == '__main__':
main()
Tatsu doesn't accept {rulename}?, it uses [rulename] instead.

Resolving Shift/reduce conflicts in GNU Bison

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?

SR conflict in a grammar - how to resolve it? (Lemon/yacc)

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.

VBScript parser grammar: Array assignment modelling

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.

Antlr3 - Non Greedy Double Quoted String with Escaped Double Quote

The following Antlr3 Grammar file doesn't cater for escaped double quotes as part of the STRING lexer rule. Any ideas why?
Expressions working:
\"hello\"
ref(\"hello\",\"hello\")
Expressions NOT working:
\"h\"e\"l\"l\"o\"
ref(\"hello\", \"hel\"lo\")
Antlr3 grammar file runnable in AntlrWorks:
grammar Grammar;
options
{
output=AST;
ASTLabelType=CommonTree;
language=CSharp3;
}
public oaExpression
: exponentiationExpression EOF!
;
exponentiationExpression
: equalityExpression ( '^' equalityExpression )*
;
equalityExpression
: relationalExpression ( ( ('==' | '=' ) | ('!=' | '<>' ) ) relationalExpression )*
;
relationalExpression
: additiveExpression ( ( '>' | '>=' | '<' | '<=' ) additiveExpression )*
;
additiveExpression
: multiplicativeExpression ( ( '+' | '-' ) multiplicativeExpression )*
;
multiplicativeExpression
: primaryExpression ( ( '*' | '/' ) primaryExpression )*
;
primaryExpression
: '(' exponentiationExpression ')' | value | identifier (arguments )?
;
value
: STRING
;
identifier
: ID
;
expressionList
: exponentiationExpression ( ',' exponentiationExpression )*
;
arguments
: '(' ( expressionList )? ')'
;
/*
* Lexer rules
*/
ID
: LETTER (LETTER | DIGIT)*
;
STRING
: '"' ( options { greedy=false; } : ~'"' )* '"'
;
WS
: (' '|'\r'|'\t'|'\u000C'|'\n') {$channel=Hidden;}
;
/*
* Fragment Lexer rules
*/
fragment
LETTER
: 'a'..'z'
| 'A'..'Z'
| '_'
;
fragment
EXPONENT
: ('e'|'E') ('+'|'-')? ( DIGIT )+
;
fragment
HEX_DIGIT
: ( DIGIT |'a'..'f'|'A'..'F')
;
fragment
DIGIT
: '0'..'9'
;
Try this:
STRING
: '"' // a opening quote
( // start group
'\\' ~('\r' | '\n') // an escaped char other than a line break char
| // OR
~('\\' | '"'| '\r' | '\n') // any char other than '"', '\' and line breaks
)* // end group and repeat zero or more times
'"' // the closing quote
;
When I test the 4 different test cases from your comment:
"\"hello\""
"ref(\"hello\",\"hello\")"
"\"h\"e\"l\"l\"o\""
"ref(\"hello\", \"hel\"lo\")"
with the lexer rule I suggested:
grammar T;
parse
: string+ EOF
;
string
: STRING
;
STRING
: '"' ('\\' ~('\r' | '\n') | ~('\\' | '"'| '\r' | '\n'))* '"'
;
SPACE
: (' ' | '\t' | '\r' | '\n')+ {skip();}
;
ANTLRWorks' debugger produces the following parse tree:
In other words: it works just fine (on my machine :)).
EDIT II
And I've also used your grammar (making some small changes to make it Java compatible) where I replaced the incorrect STRING rule into the one I suggested:
oaExpression
: STRING+ EOF!
//: exponentiationExpression EOF!
;
exponentiationExpression
: equalityExpression ( '^' equalityExpression )*
;
equalityExpression
: relationalExpression ( ( ('==' | '=' ) | ('!=' | '<>' ) ) relationalExpression )*
;
relationalExpression
: additiveExpression ( ( '>' | '>=' | '<' | '<=' ) additiveExpression )*
;
additiveExpression
: multiplicativeExpression ( ( '+' | '-' ) multiplicativeExpression )*
;
multiplicativeExpression
: primaryExpression ( ( '*' | '/' ) primaryExpression )*
;
primaryExpression
: '(' exponentiationExpression ')' | value | identifier (arguments )?
;
value
: STRING
;
identifier
: ID
;
expressionList
: exponentiationExpression ( ',' exponentiationExpression )*
;
arguments
: '(' ( expressionList )? ')'
;
/*
* Lexer rules
*/
ID
: LETTER (LETTER | DIGIT)*
;
//STRING
// : '"' ( options { greedy=false; } : ~'"' )* '"'
// ;
STRING
: '"' ('\\' ~('\r' | '\n') | ~('\\' | '"'| '\r' | '\n'))* '"'
;
WS
: (' '|'\r'|'\t'|'\u000C'|'\n') {$channel=HIDDEN;} /*{$channel=Hidden;}*/
;
/*
* Fragment Lexer rules
*/
fragment
LETTER
: 'a'..'z'
| 'A'..'Z'
| '_'
;
fragment
EXPONENT
: ('e'|'E') ('+'|'-')? ( DIGIT )+
;
fragment
HEX_DIGIT
: ( DIGIT |'a'..'f'|'A'..'F')
;
fragment
DIGIT
: '0'..'9'
;
which parses the input from my previous example in an identical parse tree.
This is how I do this with strings that can contain escape sequences (not just \" but any):
DOUBLE_QUOTED_TEXT
#init { int escape_count = 0; }:
DOUBLE_QUOTE
(
DOUBLE_QUOTE DOUBLE_QUOTE { escape_count++; }
| ESCAPE_OPERATOR . { escape_count++; }
| ~(DOUBLE_QUOTE | ESCAPE_OPERATOR)
)*
DOUBLE_QUOTE
{ EMIT(); LTOKEN->user1 = escape_count; }
;
The rule additionally counts the escapes and stores them in the token. This allows the receiver to quickly see if it needs to do anything with the string (if user1 > 0). If you don't need that remove the #init part and the actions.

Resources