Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trying to validate grammar #30

Open
markfirmware opened this issue Mar 9, 2021 · 16 comments
Open

Trying to validate grammar #30

markfirmware opened this issue Mar 9, 2021 · 16 comments

Comments

@markfirmware
Copy link
Contributor

I cannot get validation on a 20.04 cloud host, a gitpod cloud host nor in gh actions. All of the tests have 127 vs 0

cd grammar
./validate.sh
@markfirmware
Copy link
Contributor Author

@markfirmware
Copy link
Contributor Author

markfirmware commented Mar 10, 2021

Is the grammar in working order? Do you typically use some other than linux to run check_parser.sh?

I noticed a different version of the grammar at the web page
https://github.com/ziglang/www.ziglang.org/blob/0888fffe9589b72245f62766e94581adf4784a12/content/documentation/master/index.html#L13092-L13593

@markfirmware
Copy link
Contributor Author

Did not intend to close.

@markfirmware markfirmware reopened this Mar 10, 2021
@mingodad
Copy link

Here is a naive conversion (basically replace <- by ::= and / by | and cut several token declarations) of the grammar at https://github.com/ziglang/zig-spec/blob/master/grammar/grammar.y to EBNF accepted by https://www.bottlecaps.de/rr/ui to generate a railroad diagram (copy the grammar bellow to Edit Grammar tab and then click on View Diagram tab):

Root ::= skip container_doc_comment? ContainerMembers eof

//# *** Top level ***
ContainerMembers
    ::= (
         TestDecl ContainerMembers
         | TopLevelComptime ContainerMembers
         | doc_comment? KEYWORD_pub? TopLevelDecl ContainerMembers
         | ContainerField COMMA ContainerMembers
         | ContainerField
     )

TestDecl ::= doc_comment? KEYWORD_test STRINGLITERALSINGLE? Block

TopLevelComptime ::= doc_comment? KEYWORD_comptime BlockExpr

TopLevelDecl
    ::= (KEYWORD_export | KEYWORD_extern STRINGLITERALSINGLE? | (KEYWORD_inline | KEYWORD_noinline))? FnProto (SEMICOLON | Block)
     | (KEYWORD_export | KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl
     | KEYWORD_usingnamespace Expr SEMICOLON

FnProto ::= KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? CallConv? EXCLAMATIONMARK? (KEYWORD_anytype | TypeExpr)

VarDecl ::= (KEYWORD_const | KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON

ContainerField ::= doc_comment? KEYWORD_comptime? IDENTIFIER (COLON (KEYWORD_anytype | TypeExpr) ByteAlign?)? (EQUAL Expr)?

//# *** Block Level ***
Statement
    ::= KEYWORD_comptime? VarDecl
     | KEYWORD_comptime BlockExprStatement
     | KEYWORD_nosuspend BlockExprStatement
     | KEYWORD_suspend (SEMICOLON | BlockExprStatement)
     | KEYWORD_defer BlockExprStatement
     | KEYWORD_errdefer Payload? BlockExprStatement
     | IfStatement
     | LabeledStatement
     | SwitchExpr
     | AssignExpr SEMICOLON

IfStatement
    ::= IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )?
     | IfPrefix AssignExpr ( SEMICOLON | KEYWORD_else Payload? Statement )

LabeledStatement ::= BlockLabel? (Block | LoopStatement)

LoopStatement ::= KEYWORD_inline? (ForStatement | WhileStatement)

ForStatement
    ::= ForPrefix BlockExpr ( KEYWORD_else Statement )?
     | ForPrefix AssignExpr ( SEMICOLON | KEYWORD_else Statement )

WhileStatement
    ::= WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )?
     | WhilePrefix AssignExpr ( SEMICOLON | KEYWORD_else Payload? Statement )

BlockExprStatement
    ::= BlockExpr
     | AssignExpr SEMICOLON

BlockExpr ::= BlockLabel? Block

//# *** Expression Level ***
AssignExpr ::= Expr (AssignOp Expr)?

Expr ::= BoolOrExpr

BoolOrExpr ::= BoolAndExpr (KEYWORD_or BoolAndExpr)*

BoolAndExpr ::= CompareExpr (KEYWORD_and CompareExpr)*

CompareExpr ::= BitwiseExpr (CompareOp BitwiseExpr)?

BitwiseExpr ::= BitShiftExpr (BitwiseOp BitShiftExpr)*

BitShiftExpr ::= AdditionExpr (BitShiftOp AdditionExpr)*

AdditionExpr ::= MultiplyExpr (AdditionOp MultiplyExpr)*

MultiplyExpr ::= PrefixExpr (MultiplyOp PrefixExpr)*

PrefixExpr ::= PrefixOp* PrimaryExpr

PrimaryExpr
    ::= AsmExpr
     | IfExpr
     | KEYWORD_break BreakLabel? Expr?
     | KEYWORD_comptime Expr
     | KEYWORD_nosuspend Expr
     | KEYWORD_continue BreakLabel?
     | KEYWORD_resume Expr
     | KEYWORD_return Expr?
     | BlockLabel? LoopExpr
     | Block
     | CurlySuffixExpr

IfExpr ::= IfPrefix Expr (KEYWORD_else Payload? Expr)?

Block ::= LBRACE Statement* RBRACE

LoopExpr ::= KEYWORD_inline? (ForExpr | WhileExpr)

ForExpr ::= ForPrefix Expr (KEYWORD_else Expr)?

WhileExpr ::= WhilePrefix Expr (KEYWORD_else Payload? Expr)?

CurlySuffixExpr ::= TypeExpr InitList?

InitList
    ::= LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE
     | LBRACE Expr (COMMA Expr)* COMMA? RBRACE
     | LBRACE RBRACE

TypeExpr ::= PrefixTypeOp* ErrorUnionExpr

ErrorUnionExpr ::= SuffixExpr (EXCLAMATIONMARK TypeExpr)?

SuffixExpr
    ::= KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments
     | PrimaryTypeExpr (SuffixOp | FnCallArguments)*

PrimaryTypeExpr
    ::= BUILTINIDENTIFIER FnCallArguments
     | CHAR_LITERAL
     | ContainerDecl
     | DOT IDENTIFIER
     | DOT InitList
     | ErrorSetDecl
     | FLOAT
     | FnProto
     | GroupedExpr
     | LabeledTypeExpr
     | IDENTIFIER
     | IfTypeExpr
     | INTEGER
     | KEYWORD_comptime TypeExpr
     | KEYWORD_error DOT IDENTIFIER
     | KEYWORD_false
     | KEYWORD_null
     | KEYWORD_anyframe
     | KEYWORD_true
     | KEYWORD_undefined
     | KEYWORD_unreachable
     | STRINGLITERAL
     | SwitchExpr

ContainerDecl ::= (KEYWORD_extern | KEYWORD_packed)? ContainerDeclAuto

ErrorSetDecl ::= KEYWORD_error LBRACE IdentifierList RBRACE

GroupedExpr ::= LPAREN Expr RPAREN

IfTypeExpr ::= IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?

LabeledTypeExpr
    ::= BlockLabel Block
     | BlockLabel? LoopTypeExpr

LoopTypeExpr ::= KEYWORD_inline? (ForTypeExpr | WhileTypeExpr)

ForTypeExpr ::= ForPrefix TypeExpr (KEYWORD_else TypeExpr)?

WhileTypeExpr ::= WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?

SwitchExpr ::= KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE

//# *** Assembly ***
AsmExpr ::= KEYWORD_asm KEYWORD_volatile? LPAREN STRINGLITERAL AsmOutput? RPAREN

AsmOutput ::= COLON AsmOutputList AsmInput?

AsmOutputItem ::= LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr | IDENTIFIER) RPAREN

AsmInput ::= COLON AsmInputList AsmClobbers?

AsmInputItem ::= LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN

AsmClobbers ::= COLON StringList

//# *** Helper grammar ***
BreakLabel ::= COLON IDENTIFIER

BlockLabel ::= IDENTIFIER COLON

FieldInit ::= DOT IDENTIFIER EQUAL Expr

WhileContinueExpr ::= COLON LPAREN AssignExpr RPAREN

LinkSection ::= KEYWORD_linksection LPAREN Expr RPAREN

//# Fn specific
CallConv ::= KEYWORD_callconv LPAREN Expr RPAREN

ParamDecl ::= doc_comment? (KEYWORD_noalias | KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType

ParamType
    ::= KEYWORD_anytype
     | DOT3
     | TypeExpr

//# Control flow prefixes
IfPrefix ::= KEYWORD_if LPAREN Expr RPAREN PtrPayload?

WhilePrefix ::= KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?

ForPrefix ::= KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload

//# Payloads
Payload ::= PIPE IDENTIFIER PIPE

PtrPayload ::= PIPE ASTERISK? IDENTIFIER PIPE

PtrIndexPayload ::= PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE


//# Switch specific
SwitchProng ::= SwitchCase EQUALRARROW PtrPayload? AssignExpr

SwitchCase
    ::= SwitchItem (COMMA SwitchItem)* COMMA?
     | KEYWORD_else

SwitchItem ::= Expr (DOT3 Expr)?

//# Operators
AssignOp
    ::= ASTERISKEQUAL
     | SLASHEQUAL
     | PERCENTEQUAL
     | PLUSEQUAL
     | MINUSEQUAL
     | LARROW2EQUAL
     | RARROW2EQUAL
     | AMPERSANDEQUAL
     | CARETEQUAL
     | PIPEEQUAL
     | ASTERISKPERCENTEQUAL
     | PLUSPERCENTEQUAL
     | MINUSPERCENTEQUAL
     | EQUAL

CompareOp
    ::= EQUALEQUAL
     | EXCLAMATIONMARKEQUAL
     | LARROW
     | RARROW
     | LARROWEQUAL
     | RARROWEQUAL

BitwiseOp
    ::= AMPERSAND
     | CARET
     | PIPE
     | KEYWORD_orelse
     | KEYWORD_catch Payload?

BitShiftOp
    ::= LARROW2
     | RARROW2

AdditionOp
    ::= PLUS
     | MINUS
     | PLUS2
     | PLUSPERCENT
     | MINUSPERCENT

MultiplyOp
    ::= PIPE2
     | ASTERISK
     | SLASH
     | PERCENT
     | ASTERISK2
     | ASTERISKPERCENT

PrefixOp
    ::= EXCLAMATIONMARK
     | MINUS
     | TILDE
     | MINUSPERCENT
     | AMPERSAND
     | KEYWORD_try
     | KEYWORD_await

PrefixTypeOp
    ::= QUESTIONMARK
     | KEYWORD_anyframe MINUSRARROW
     | SliceTypeStart (ByteAlign | KEYWORD_const | KEYWORD_volatile | KEYWORD_allowzero)*
     | PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN | KEYWORD_const | KEYWORD_volatile | KEYWORD_allowzero)*
     | ArrayTypeStart

SuffixOp
    ::= LBRACKET Expr (DOT2 (Expr? (COLON Expr)?)?)? RBRACKET
     | DOT IDENTIFIER
     | DOTASTERISK
     | DOTQUESTIONMARK

FnCallArguments ::= LPAREN ExprList RPAREN

//# Ptr specific
SliceTypeStart ::= LBRACKET (COLON Expr)? RBRACKET

PtrTypeStart
    ::= ASTERISK
     | ASTERISK2
     | LBRACKET ASTERISK (LETTERC | COLON Expr)? RBRACKET

ArrayTypeStart ::= LBRACKET Expr (COLON Expr)? RBRACKET

//# ContainerDecl specific
ContainerDeclAuto ::= ContainerDeclType LBRACE container_doc_comment? ContainerMembers RBRACE

ContainerDeclType
    ::= KEYWORD_struct
     | KEYWORD_opaque
     | KEYWORD_enum (LPAREN Expr RPAREN)?
     | KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? | Expr) RPAREN)?

//# Alignment
ByteAlign ::= KEYWORD_align LPAREN Expr RPAREN

//# Lists
IdentifierList ::= (doc_comment? IDENTIFIER COMMA)* (doc_comment? IDENTIFIER)?

SwitchProngList ::= (SwitchProng COMMA)* SwitchProng?

AsmOutputList ::= (AsmOutputItem COMMA)* AsmOutputItem?

AsmInputList ::= (AsmInputItem COMMA)* AsmInputItem?

StringList ::= (STRINGLITERAL COMMA)* STRINGLITERAL?

ParamDeclList ::= (ParamDecl COMMA)* ParamDecl?

ExprList ::= (Expr COMMA)* Expr?

//# *** Tokens ***

AMPERSAND            ::= '&'
AMPERSANDEQUAL       ::= '&='
ASTERISK             ::= '*'
ASTERISK2            ::= '**'
ASTERISKEQUAL        ::= '*='
ASTERISKPERCENT      ::= '*%'
ASTERISKPERCENTEQUAL ::= '*%='
CARET                ::= '^'
CARETEQUAL           ::= '^='
COLON                ::= ':'
COMMA                ::= ','
DOT                  ::= '.'
DOT2                 ::= '..'
DOT3                 ::= '...'
DOTASTERISK          ::= '.*'
DOTQUESTIONMARK      ::= '.?'
EQUAL                ::= '='
EQUALEQUAL           ::= '=='
EQUALRARROW          ::= '=>'
EXCLAMATIONMARK      ::= '!'
EXCLAMATIONMARKEQUAL ::= '!='
LARROW               ::= '<'
LARROW2              ::= '<<'
LARROW2EQUAL         ::= '<<='
LARROWEQUAL          ::= '<='
LBRACE               ::= '{'
LBRACKET             ::= '['
LPAREN               ::= '('
MINUS                ::= '-'
MINUSEQUAL           ::= '-='
MINUSPERCENT         ::= '-%'
MINUSPERCENTEQUAL    ::= '-%='
MINUSRARROW          ::= '->'
PERCENT              ::= '%'
PERCENTEQUAL         ::= '%='
PIPE                 ::= '|'
PIPE2                ::= '||'
PIPEEQUAL            ::= '|='
PLUS                 ::= '+'
PLUS2                ::= '++'
PLUSEQUAL            ::= '+='
PLUSPERCENT          ::= '+%'
PLUSPERCENTEQUAL     ::= '+%='
LETTERC              ::= 'c'
QUESTIONMARK         ::= '?'
RARROW               ::= '>'
RARROW2              ::= '>>'
RARROW2EQUAL         ::= '>>='
RARROWEQUAL          ::= '>='
RBRACE               ::= '}'
RBRACKET             ::= ']'
RPAREN               ::= ')'
SEMICOLON            ::= ';'
SLASH                ::= '/'
SLASHEQUAL           ::= '/='
TILDE                ::= '~'

KEYWORD_align       ::= 'align'
KEYWORD_allowzero   ::= 'allowzero'
KEYWORD_and         ::= 'and'
KEYWORD_anyframe    ::= 'anyframe'
KEYWORD_anytype     ::= 'anytype'
KEYWORD_asm         ::= 'asm'
KEYWORD_async       ::= 'async'
KEYWORD_await       ::= 'await'
KEYWORD_break       ::= 'break'
KEYWORD_callconv    ::= 'callconv'
KEYWORD_catch       ::= 'catch'
KEYWORD_comptime    ::= 'comptime'
KEYWORD_const       ::= 'const'
KEYWORD_continue    ::= 'continue'
KEYWORD_defer       ::= 'defer'
KEYWORD_else        ::= 'else'
KEYWORD_enum        ::= 'enum'
KEYWORD_errdefer    ::= 'errdefer'
KEYWORD_error       ::= 'error'
KEYWORD_export      ::= 'export'
KEYWORD_extern      ::= 'extern'
KEYWORD_false       ::= 'false'
KEYWORD_fn          ::= 'fn'
KEYWORD_for         ::= 'for'
KEYWORD_if          ::= 'if'
KEYWORD_inline      ::= 'inline'
KEYWORD_noalias     ::= 'noalias'
KEYWORD_nosuspend   ::= 'nosuspend'
KEYWORD_noinline    ::= 'noinline'
KEYWORD_null        ::= 'null'
KEYWORD_opaque      ::= 'opaque'
KEYWORD_or          ::= 'or'
KEYWORD_orelse      ::= 'orelse'
KEYWORD_packed      ::= 'packed'
KEYWORD_pub         ::= 'pub'
KEYWORD_resume      ::= 'resume'
KEYWORD_return      ::= 'return'
KEYWORD_linksection ::= 'linksection'
KEYWORD_struct      ::= 'struct'
KEYWORD_suspend     ::= 'suspend'
KEYWORD_switch      ::= 'switch'
KEYWORD_test        ::= 'test'
KEYWORD_threadlocal ::= 'threadlocal'
KEYWORD_true        ::= 'true'
KEYWORD_try         ::= 'try'
KEYWORD_undefined   ::= 'undefined'
KEYWORD_union       ::= 'union'
KEYWORD_unreachable ::= 'unreachable'
KEYWORD_usingnamespace ::= 'usingnamespace'
KEYWORD_var         ::= 'var'
KEYWORD_volatile    ::= 'volatile'
KEYWORD_while       ::= 'while'

@mingodad
Copy link

Effectively the grammar on ziglang.org documentation do not match the one here, here is the EBNF for the 0.7.1 and the dev versions to be viewd at https://www.bottlecaps.de/rr/ui:

Zig-0.7.1.ebnf:

Root ::= skip ContainerMembers eof

//# *** Top level ***
ContainerMembers
    ::= TestDecl ContainerMembers
     | TopLevelComptime ContainerMembers
     | KEYWORD_pub? TopLevelDecl ContainerMembers
     | ContainerField COMMA ContainerMembers
     | ContainerField


TestDecl ::= KEYWORD_test STRINGLITERALSINGLE Block

TopLevelComptime ::= KEYWORD_comptime BlockExpr

TopLevelDecl
    ::= (KEYWORD_export | KEYWORD_extern STRINGLITERALSINGLE? | KEYWORD_inline)? FnProto (SEMICOLON | Block)
     | (KEYWORD_export | KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl
     | KEYWORD_usingnamespace Expr SEMICOLON

FnProto ::= KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_anytype | TypeExpr)

VarDecl ::= (KEYWORD_const | KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON

ContainerField ::= KEYWORD_comptime? IDENTIFIER (COLON TypeExpr)? (EQUAL Expr)?

//# *** Block Level ***
Statement
    ::= KEYWORD_comptime? VarDecl
     | KEYWORD_comptime BlockExprStatement
     | KEYWORD_nosuspend BlockExprStatement
     | KEYWORD_suspend (SEMICOLON | BlockExprStatement)
     | KEYWORD_defer BlockExprStatement
     | KEYWORD_errdefer BlockExprStatement
     | IfStatement
     | LabeledStatement
     | SwitchExpr
     | AssignExpr SEMICOLON

IfStatement
    ::= IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )?
     | IfPrefix AssignExpr ( SEMICOLON | KEYWORD_else Payload? Statement )

LabeledStatement ::= BlockLabel? (Block | LoopStatement)

LoopStatement ::= KEYWORD_inline? (ForStatement | WhileStatement)

ForStatement
    ::= ForPrefix BlockExpr ( KEYWORD_else Statement )?
     | ForPrefix AssignExpr ( SEMICOLON | KEYWORD_else Statement )

WhileStatement
    ::= WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )?
     | WhilePrefix AssignExpr ( SEMICOLON | KEYWORD_else Payload? Statement )

BlockExprStatement
    ::= BlockExpr
     | AssignExpr SEMICOLON

BlockExpr ::= BlockLabel? Block

//# *** Expression Level ***
AssignExpr ::= Expr (AssignOp Expr)?

Expr ::= KEYWORD_try* BoolOrExpr

BoolOrExpr ::= BoolAndExpr (KEYWORD_or BoolAndExpr)*

BoolAndExpr ::= CompareExpr (KEYWORD_and CompareExpr)*

CompareExpr ::= BitwiseExpr (CompareOp BitwiseExpr)?

BitwiseExpr ::= BitShiftExpr (BitwiseOp BitShiftExpr)*

BitShiftExpr ::= AdditionExpr (BitShiftOp AdditionExpr)*

AdditionExpr ::= MultiplyExpr (AdditionOp MultiplyExpr)*

MultiplyExpr ::= PrefixExpr (MultiplyOp PrefixExpr)*

PrefixExpr ::= PrefixOp* PrimaryExpr

PrimaryExpr
    ::= AsmExpr
     | IfExpr
     | KEYWORD_break BreakLabel? Expr?
     | KEYWORD_comptime Expr
     | KEYWORD_nosuspend Expr
     | KEYWORD_continue BreakLabel?
     | KEYWORD_resume Expr
     | KEYWORD_return Expr?
     | BlockLabel? LoopExpr
     | Block
     | CurlySuffixExpr

IfExpr ::= IfPrefix Expr (KEYWORD_else Payload? Expr)?

Block ::= LBRACE Statement* RBRACE

LoopExpr ::= KEYWORD_inline? (ForExpr | WhileExpr)

ForExpr ::= ForPrefix Expr (KEYWORD_else Expr)?

WhileExpr ::= WhilePrefix Expr (KEYWORD_else Payload? Expr)?

CurlySuffixExpr ::= TypeExpr InitList?

InitList
    ::= LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE
     | LBRACE Expr (COMMA Expr)* COMMA? RBRACE
     | LBRACE RBRACE

TypeExpr ::= PrefixTypeOp* ErrorUnionExpr

ErrorUnionExpr ::= SuffixExpr (EXCLAMATIONMARK TypeExpr)?

SuffixExpr
    ::= KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments
     | PrimaryTypeExpr (SuffixOp | FnCallArguments)*

PrimaryTypeExpr
    ::= BUILTINIDENTIFIER FnCallArguments
     | CHAR_LITERAL
     | ContainerDecl
     | DOT IDENTIFIER
     | DOT InitList
     | ErrorSetDecl
     | FLOAT
     | FnProto
     | GroupedExpr
     | LabeledTypeExpr
     | IDENTIFIER
     | IfTypeExpr
     | INTEGER
     | KEYWORD_comptime TypeExpr
     | KEYWORD_error DOT IDENTIFIER
     | KEYWORD_false
     | KEYWORD_null
     | KEYWORD_anyframe
     | KEYWORD_true
     | KEYWORD_undefined
     | KEYWORD_unreachable
     | STRINGLITERAL
     | SwitchExpr

ContainerDecl ::= (KEYWORD_extern | KEYWORD_packed)? ContainerDeclAuto

ErrorSetDecl ::= KEYWORD_error LBRACE IdentifierList RBRACE

GroupedExpr ::= LPAREN Expr RPAREN

IfTypeExpr ::= IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?

LabeledTypeExpr
    ::= BlockLabel Block
     | BlockLabel? LoopTypeExpr

LoopTypeExpr ::= KEYWORD_inline? (ForTypeExpr | WhileTypeExpr)

ForTypeExpr ::= ForPrefix TypeExpr (KEYWORD_else TypeExpr)?

WhileTypeExpr ::= WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?

SwitchExpr ::= KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE

//# *** Assembly ***
AsmExpr ::= KEYWORD_asm KEYWORD_volatile? LPAREN STRINGLITERAL AsmOutput? RPAREN

AsmOutput ::= COLON AsmOutputList AsmInput?

AsmOutputItem ::= LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr | IDENTIFIER) RPAREN

AsmInput ::= COLON AsmInputList AsmClobbers?

AsmInputItem ::= LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN

AsmClobbers ::= COLON StringList

//# *** Helper grammar ***
BreakLabel ::= COLON IDENTIFIER

BlockLabel ::= IDENTIFIER COLON

FieldInit ::= DOT IDENTIFIER EQUAL Expr

WhileContinueExpr ::= COLON LPAREN AssignExpr RPAREN

LinkSection ::= KEYWORD_linksection LPAREN Expr RPAREN

ParamDecl ::= (KEYWORD_noalias | KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType

ParamType
    ::= KEYWORD_anytype
     | DOT3
     | TypeExpr

//# Control flow prefixes
IfPrefix ::= KEYWORD_if LPAREN Expr RPAREN PtrPayload?

WhilePrefix ::= KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?

ForPrefix ::= KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload

//# Payloads
Payload ::= PIPE IDENTIFIER PIPE

PtrPayload ::= PIPE ASTERISK? IDENTIFIER PIPE

PtrIndexPayload ::= PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE


//# Switch specific
SwitchProng ::= SwitchCase EQUALRARROW PtrPayload? AssignExpr

SwitchCase
    ::= SwitchItem (COMMA SwitchItem)* COMMA?
     | KEYWORD_else

SwitchItem ::= Expr (DOT3 Expr)?

//# Operators
AssignOp
    ::= ASTERISKEQUAL
     | SLASHEQUAL
     | PERCENTEQUAL
     | PLUSEQUAL
     | MINUSEQUAL
     | LARROW2EQUAL
     | RARROW2EQUAL
     | AMPERSANDEQUAL
     | CARETEQUAL
     | PIPEEQUAL
     | ASTERISKPERCENTEQUAL
     | PLUSPERCENTEQUAL
     | MINUSPERCENTEQUAL
     | EQUAL

CompareOp
    ::= EQUALEQUAL
     | EXCLAMATIONMARKEQUAL
     | LARROW
     | RARROW
     | LARROWEQUAL
     | RARROWEQUAL

BitwiseOp
    ::= AMPERSAND
     | CARET
     | PIPE
     | KEYWORD_orelse
     | KEYWORD_catch Payload?

BitShiftOp
    ::= LARROW2
     | RARROW2

AdditionOp
    ::= PLUS
     | MINUS
     | PLUS2
     | PLUSPERCENT
     | MINUSPERCENT

MultiplyOp
    ::= PIPE2
     | ASTERISK
     | SLASH
     | PERCENT
     | ASTERISK2
     | ASTERISKPERCENT

PrefixOp
    ::= EXCLAMATIONMARK
     | MINUS
     | TILDE
     | MINUSPERCENT
     | AMPERSAND
     | KEYWORD_try
     | KEYWORD_await

PrefixTypeOp
    ::= QUESTIONMARK
     | KEYWORD_anyframe MINUSRARROW
     | ArrayTypeStart (ByteAlign | KEYWORD_const | KEYWORD_volatile | KEYWORD_allowzero)*
     | PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN | KEYWORD_const | KEYWORD_volatile | KEYWORD_allowzero)*

SuffixOp
    ::= LBRACKET Expr (DOT2 Expr?)? RBRACKET
     | DOT IDENTIFIER
     | DOTASTERISK
     | DOTQUESTIONMARK

FnCallArguments ::= LPAREN ExprList RPAREN

//# Ptr specific
ArrayTypeStart ::= LBRACKET Expr? RBRACKET

PtrTypeStart
    ::= ASTERISK
     | ASTERISK2
     | PTRUNKNOWN
     | PTRC

//# ContainerDecl specific
ContainerDeclAuto ::= ContainerDeclType LBRACE ContainerMembers RBRACE

ContainerDeclType
    ::= (KEYWORD_struct | KEYWORD_enum | KEYWORD_opaque) (LPAREN Expr RPAREN)?
     | KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? | Expr) RPAREN)?

//# Alignment
ByteAlign ::= KEYWORD_align LPAREN Expr RPAREN

//# Lists
IdentifierList ::= (IDENTIFIER COMMA)* IDENTIFIER?

SwitchProngList ::= (SwitchProng COMMA)* SwitchProng?

AsmOutputList ::= (AsmOutputItem COMMA)* AsmOutputItem?

AsmInputList ::= (AsmInputItem COMMA)* AsmInputItem?

StringList ::= (STRINGLITERAL COMMA)* STRINGLITERAL?

ParamDeclList ::= (ParamDecl COMMA)* ParamDecl?

ExprList ::= (Expr COMMA)* Expr?

//# *** Tokens ***
eof ::= "!."
hex ::= [0-9a-fA-F]
char_escape
    ::= "\\x" hex hex
     | "\\u{" hex+ "}"
     | "\\" [nr\\t'"]
char_char
    ::= char_escape
     | [^\\'\n]
string_char
    ::= char_escape
     | [^\\"\n]

line_comment ::= '//'[^\n]*
line_string ::= ("\\\\" [^\n]* [ \n]*)+
skip ::= ([ \n] | line_comment)*

CHAR_LITERAL ::= "'" char_char "'" skip
FLOAT
    ::= "0x" hex+   "." hex+   ([pP] [-+]? hex+)?   skip
     |      [0-9]+ "." [0-9]+ ([eE] [-+]? [0-9]+)? skip
     | "0x" hex+   "."? [pP] [-+]? hex+   skip
     |      [0-9]+ "."? [eE] [-+]? [0-9]+ skip
INTEGER
    ::= "0b" [01]+  skip
     | "0o" [0-7]+ skip
     | "0x" hex+   skip
     |      [0-9]+ skip
STRINGLITERALSINGLE ::= '"' string_char* '"' skip
STRINGLITERAL
    ::= STRINGLITERALSINGLE
     | line_string                 skip
IDENTIFIER
    ::= '!' keyword [A-Za-z_] [A-Za-z0-9_]* skip
     | '@"' string_char* '"'                            skip
BUILTINIDENTIFIER ::= "@"[A-Za-z_][A-Za-z0-9_]* skip


AMPERSAND            ::= '&'     // ![=]      skip
AMPERSANDEQUAL       ::= '&='    //           skip
ASTERISK             ::= '*'     // ![*%=]    skip
ASTERISK2            ::= '**'    //           skip
ASTERISKEQUAL        ::= '*='    //           skip
ASTERISKPERCENT      ::= '*%'    // ![=]      skip
ASTERISKPERCENTEQUAL ::= '*%='   //           skip
CARET                ::= '^'     // ![=]      skip
CARETEQUAL           ::= '^='    //           skip
COLON                ::= ':'     //           skip
COMMA                ::= ','     //           skip
DOT                  ::= '.'     // ![*.?]    skip
DOT2                 ::= '..'    // ![.]      skip
DOT3                 ::= '...'   //           skip
DOTASTERISK          ::= '.*'    //           skip
DOTQUESTIONMARK      ::= '.?'    //           skip
EQUAL                ::= '='     // ![>=]     skip
EQUALEQUAL           ::= '=='    //           skip
EQUALRARROW          ::= '=>'    //           skip
EXCLAMATIONMARK      ::= '!'     // ![=]      skip
EXCLAMATIONMARKEQUAL ::= '!='    //           skip
LARROW               ::= '<'     // ![<=]     skip
LARROW2              ::= '<<'    // ![=]      skip
LARROW2EQUAL         ::= '<<='   //           skip
LARROWEQUAL          ::= '<='    //           skip
LBRACE               ::= '{'     //           skip
LBRACKET             ::= '['     // ![*]      skip
LPAREN               ::= '('     //           skip
MINUS                ::= '-'     // ![%=>]    skip
MINUSEQUAL           ::= '-='    //           skip
MINUSPERCENT         ::= '-%'    // ![=]      skip
MINUSPERCENTEQUAL    ::= '-%='   //           skip
MINUSRARROW          ::= '->'    //           skip
PERCENT              ::= '%'     // ![=]      skip
PERCENTEQUAL         ::= '%='    //           skip
PIPE                 ::= '|'     // ![|=]     skip
PIPE2                ::= '||'    //           skip
PIPEEQUAL            ::= '|='    //           skip
PLUS                 ::= '+'     // ![%+=]    skip
PLUS2                ::= '++'    //           skip
PLUSEQUAL            ::= '+='    //           skip
PLUSPERCENT          ::= '+%'    // ![=]      skip
PLUSPERCENTEQUAL     ::= '+%='   //           skip
PTRC                 ::= '[*c]'  //           skip
PTRUNKNOWN           ::= '[*]'   //           skip
QUESTIONMARK         ::= '?'     //           skip
RARROW               ::= '>'     // ![>=]     skip
RARROW2              ::= '>>'    // ![=]      skip
RARROW2EQUAL         ::= '>>='   //           skip
RARROWEQUAL          ::= '>='    //           skip
RBRACE               ::= '}'     //           skip
RBRACKET             ::= ']'     //           skip
RPAREN               ::= ')'     //           skip
SEMICOLON            ::= ';'     //           skip
SLASH                ::= '/'     // ![=]      skip
SLASHEQUAL           ::= '/='    //           skip
TILDE                ::= '~'     //           skip

end_of_word ::= '!'[a-zA-Z0-9_] skip
KEYWORD_align       ::= 'align'       //end_of_word
KEYWORD_allowzero   ::= 'allowzero'   //end_of_word
KEYWORD_and         ::= 'and'         //end_of_word
KEYWORD_anyframe    ::= 'anyframe'    //end_of_word
KEYWORD_anytype     ::= 'anytype'     //end_of_word
KEYWORD_asm         ::= 'asm'         //end_of_word
KEYWORD_async       ::= 'async'       //end_of_word
KEYWORD_await       ::= 'await'       //end_of_word
KEYWORD_break       ::= 'break'       //end_of_word
KEYWORD_catch       ::= 'catch'       //end_of_word
KEYWORD_comptime    ::= 'comptime'    //end_of_word
KEYWORD_const       ::= 'const'       //end_of_word
KEYWORD_continue    ::= 'continue'    //end_of_word
KEYWORD_defer       ::= 'defer'       //end_of_word
KEYWORD_else        ::= 'else'        //end_of_word
KEYWORD_enum        ::= 'enum'        //end_of_word
KEYWORD_errdefer    ::= 'errdefer'    //end_of_word
KEYWORD_error       ::= 'error'       //end_of_word
KEYWORD_export      ::= 'export'      //end_of_word
KEYWORD_extern      ::= 'extern'      //end_of_word
KEYWORD_false       ::= 'false'       //end_of_word
KEYWORD_fn          ::= 'fn'          //end_of_word
KEYWORD_for         ::= 'for'         //end_of_word
KEYWORD_if          ::= 'if'          //end_of_word
KEYWORD_inline      ::= 'inline'      //end_of_word
KEYWORD_noalias     ::= 'noalias'     //end_of_word
KEYWORD_nosuspend   ::= 'nosuspend'   //end_of_word
KEYWORD_null        ::= 'null'        //end_of_word
KEYWORD_opaque      ::= 'opaque'      //end_of_word
KEYWORD_or          ::= 'or'          //end_of_word
KEYWORD_orelse      ::= 'orelse'      //end_of_word
KEYWORD_packed      ::= 'packed'      //end_of_word
KEYWORD_pub         ::= 'pub'         //end_of_word
KEYWORD_resume      ::= 'resume'      //end_of_word
KEYWORD_return      ::= 'return'      //end_of_word
KEYWORD_linksection ::= 'linksection' //end_of_word
KEYWORD_struct      ::= 'struct'      //end_of_word
KEYWORD_suspend     ::= 'suspend'     //end_of_word
KEYWORD_switch      ::= 'switch'      //end_of_word
KEYWORD_test        ::= 'test'        //end_of_word
KEYWORD_threadlocal ::= 'threadlocal' //end_of_word
KEYWORD_true        ::= 'true'        //end_of_word
KEYWORD_try         ::= 'try'         //end_of_word
KEYWORD_undefined   ::= 'undefined'   //end_of_word
KEYWORD_union       ::= 'union'       //end_of_word
KEYWORD_unreachable ::= 'unreachable' //end_of_word
KEYWORD_usingnamespace ::= 'usingnamespace' //end_of_word
KEYWORD_var         ::= 'var'         //end_of_word
KEYWORD_volatile    ::= 'volatile'    //end_of_word
KEYWORD_while       ::= 'while'       //end_of_word

keyword ::= KEYWORD_align | KEYWORD_and | KEYWORD_anyframe | KEYWORD_anytype
         | KEYWORD_allowzero | KEYWORD_asm | KEYWORD_async | KEYWORD_await | KEYWORD_break
         | KEYWORD_catch | KEYWORD_comptime | KEYWORD_const | KEYWORD_continue
         | KEYWORD_defer | KEYWORD_else | KEYWORD_enum | KEYWORD_errdefer
         | KEYWORD_error | KEYWORD_export | KEYWORD_extern | KEYWORD_false
         | KEYWORD_fn | KEYWORD_for | KEYWORD_if | KEYWORD_inline
         | KEYWORD_noalias | KEYWORD_null | KEYWORD_opaque | KEYWORD_or
         | KEYWORD_orelse | KEYWORD_packed | KEYWORD_pub
         | KEYWORD_resume | KEYWORD_return | KEYWORD_linksection
         | KEYWORD_struct | KEYWORD_suspend
         | KEYWORD_switch | KEYWORD_test | KEYWORD_threadlocal | KEYWORD_true | KEYWORD_try
         | KEYWORD_undefined | KEYWORD_union | KEYWORD_unreachable
         | KEYWORD_usingnamespace | KEYWORD_var | KEYWORD_volatile | KEYWORD_while

Zig-dev.ebnf:

Root ::= skip ContainerMembers eof

//# *** Top level ***
ContainerMembers
    ::= TestDecl ContainerMembers
     | TopLevelComptime ContainerMembers
     | KEYWORD_pub? TopLevelDecl ContainerMembers
     | ContainerField COMMA ContainerMembers
     | ContainerField


TestDecl ::= KEYWORD_test STRINGLITERALSINGLE Block

TopLevelComptime ::= KEYWORD_comptime BlockExpr

TopLevelDecl
    ::= (KEYWORD_export | KEYWORD_extern STRINGLITERALSINGLE? | (KEYWORD_inline | KEYWORD_noinline))? FnProto (SEMICOLON | Block)
     | (KEYWORD_export | KEYWORD_extern STRINGLITERALSINGLE?)? KEYWORD_threadlocal? VarDecl
     | KEYWORD_usingnamespace Expr SEMICOLON

FnProto ::= KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? CallConv? EXCLAMATIONMARK? (KEYWORD_anytype | TypeExpr)

VarDecl ::= (KEYWORD_const | KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON

ContainerField ::= KEYWORD_comptime? IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)?

//# *** Block Level ***
Statement
    ::= KEYWORD_comptime? VarDecl
     | KEYWORD_comptime BlockExprStatement
     | KEYWORD_nosuspend BlockExprStatement
     | KEYWORD_suspend (SEMICOLON | BlockExprStatement)
     | KEYWORD_defer BlockExprStatement
     | KEYWORD_errdefer BlockExprStatement
     | IfStatement
     | LabeledStatement
     | SwitchExpr
     | AssignExpr SEMICOLON

IfStatement
    ::= IfPrefix BlockExpr ( KEYWORD_else Payload? Statement )?
     | IfPrefix AssignExpr ( SEMICOLON | KEYWORD_else Payload? Statement )

LabeledStatement ::= BlockLabel? (Block | LoopStatement)

LoopStatement ::= KEYWORD_inline? (ForStatement | WhileStatement)

ForStatement
    ::= ForPrefix BlockExpr ( KEYWORD_else Statement )?
     | ForPrefix AssignExpr ( SEMICOLON | KEYWORD_else Statement )

WhileStatement
    ::= WhilePrefix BlockExpr ( KEYWORD_else Payload? Statement )?
     | WhilePrefix AssignExpr ( SEMICOLON | KEYWORD_else Payload? Statement )

BlockExprStatement
    ::= BlockExpr
     | AssignExpr SEMICOLON

BlockExpr ::= BlockLabel? Block

//# *** Expression Level ***
AssignExpr ::= Expr (AssignOp Expr)?

Expr ::= BoolOrExpr

BoolOrExpr ::= BoolAndExpr (KEYWORD_or BoolAndExpr)*

BoolAndExpr ::= CompareExpr (KEYWORD_and CompareExpr)*

CompareExpr ::= BitwiseExpr (CompareOp BitwiseExpr)?

BitwiseExpr ::= BitShiftExpr (BitwiseOp BitShiftExpr)*

BitShiftExpr ::= AdditionExpr (BitShiftOp AdditionExpr)*

AdditionExpr ::= MultiplyExpr (AdditionOp MultiplyExpr)*

MultiplyExpr ::= PrefixExpr (MultiplyOp PrefixExpr)*

PrefixExpr ::= PrefixOp* PrimaryExpr

PrimaryExpr
    ::= AsmExpr
     | IfExpr
     | KEYWORD_break BreakLabel? Expr?
     | KEYWORD_comptime Expr
     | KEYWORD_nosuspend Expr
     | KEYWORD_continue BreakLabel?
     | KEYWORD_resume Expr
     | KEYWORD_return Expr?
     | BlockLabel? LoopExpr
     | Block
     | CurlySuffixExpr

IfExpr ::= IfPrefix Expr (KEYWORD_else Payload? Expr)?

Block ::= LBRACE Statement* RBRACE

LoopExpr ::= KEYWORD_inline? (ForExpr | WhileExpr)

ForExpr ::= ForPrefix Expr (KEYWORD_else Expr)?

WhileExpr ::= WhilePrefix Expr (KEYWORD_else Payload? Expr)?

CurlySuffixExpr ::= TypeExpr InitList?

InitList
    ::= LBRACE FieldInit (COMMA FieldInit)* COMMA? RBRACE
     | LBRACE Expr (COMMA Expr)* COMMA? RBRACE
     | LBRACE RBRACE

TypeExpr ::= PrefixTypeOp* ErrorUnionExpr

ErrorUnionExpr ::= SuffixExpr (EXCLAMATIONMARK TypeExpr)?

SuffixExpr
    ::= KEYWORD_async PrimaryTypeExpr SuffixOp* FnCallArguments
     | PrimaryTypeExpr (SuffixOp | FnCallArguments)*

PrimaryTypeExpr
    ::= BUILTINIDENTIFIER FnCallArguments
     | CHAR_LITERAL
     | ContainerDecl
     | DOT IDENTIFIER
     | DOT InitList
     | ErrorSetDecl
     | FLOAT
     | FnProto
     | GroupedExpr
     | LabeledTypeExpr
     | IDENTIFIER
     | IfTypeExpr
     | INTEGER
     | KEYWORD_comptime TypeExpr
     | KEYWORD_error DOT IDENTIFIER
     | KEYWORD_false
     | KEYWORD_null
     | KEYWORD_anyframe
     | KEYWORD_true
     | KEYWORD_undefined
     | KEYWORD_unreachable
     | STRINGLITERAL
     | SwitchExpr

ContainerDecl ::= (KEYWORD_extern | KEYWORD_packed)? ContainerDeclAuto

ErrorSetDecl ::= KEYWORD_error LBRACE IdentifierList RBRACE

GroupedExpr ::= LPAREN Expr RPAREN

IfTypeExpr ::= IfPrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?

LabeledTypeExpr
    ::= BlockLabel Block
     | BlockLabel? LoopTypeExpr

LoopTypeExpr ::= KEYWORD_inline? (ForTypeExpr | WhileTypeExpr)

ForTypeExpr ::= ForPrefix TypeExpr (KEYWORD_else TypeExpr)?

WhileTypeExpr ::= WhilePrefix TypeExpr (KEYWORD_else Payload? TypeExpr)?

SwitchExpr ::= KEYWORD_switch LPAREN Expr RPAREN LBRACE SwitchProngList RBRACE

//# *** Assembly ***
AsmExpr ::= KEYWORD_asm KEYWORD_volatile? LPAREN STRINGLITERAL AsmOutput? RPAREN

AsmOutput ::= COLON AsmOutputList AsmInput?

AsmOutputItem ::= LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr | IDENTIFIER) RPAREN

AsmInput ::= COLON AsmInputList AsmClobbers?

AsmInputItem ::= LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN

AsmClobbers ::= COLON StringList

//# *** Helper grammar ***
BreakLabel ::= COLON IDENTIFIER

BlockLabel ::= IDENTIFIER COLON

FieldInit ::= DOT IDENTIFIER EQUAL Expr

WhileContinueExpr ::= COLON LPAREN AssignExpr RPAREN

LinkSection ::= KEYWORD_linksection LPAREN Expr RPAREN

CallConv ::= KEYWORD_callconv LPAREN Expr RPAREN

ParamDecl ::= (KEYWORD_noalias | KEYWORD_comptime)? (IDENTIFIER COLON)? ParamType

ParamType
    ::= KEYWORD_anytype
     | DOT3
     | TypeExpr

//# Control flow prefixes
IfPrefix ::= KEYWORD_if LPAREN Expr RPAREN PtrPayload?

WhilePrefix ::= KEYWORD_while LPAREN Expr RPAREN PtrPayload? WhileContinueExpr?

ForPrefix ::= KEYWORD_for LPAREN Expr RPAREN PtrIndexPayload

//# Payloads
Payload ::= PIPE IDENTIFIER PIPE

PtrPayload ::= PIPE ASTERISK? IDENTIFIER PIPE

PtrIndexPayload ::= PIPE ASTERISK? IDENTIFIER (COMMA IDENTIFIER)? PIPE


//# Switch specific
SwitchProng ::= SwitchCase EQUALRARROW PtrPayload? AssignExpr

SwitchCase
    ::= SwitchItem (COMMA SwitchItem)* COMMA?
     | KEYWORD_else

SwitchItem ::= Expr (DOT3 Expr)?

//# Operators
AssignOp
    ::= ASTERISKEQUAL
     | SLASHEQUAL
     | PERCENTEQUAL
     | PLUSEQUAL
     | MINUSEQUAL
     | LARROW2EQUAL
     | RARROW2EQUAL
     | AMPERSANDEQUAL
     | CARETEQUAL
     | PIPEEQUAL
     | ASTERISKPERCENTEQUAL
     | PLUSPERCENTEQUAL
     | MINUSPERCENTEQUAL
     | EQUAL

CompareOp
    ::= EQUALEQUAL
     | EXCLAMATIONMARKEQUAL
     | LARROW
     | RARROW
     | LARROWEQUAL
     | RARROWEQUAL

BitwiseOp
    ::= AMPERSAND
     | CARET
     | PIPE
     | KEYWORD_orelse
     | KEYWORD_catch Payload?

BitShiftOp
    ::= LARROW2
     | RARROW2

AdditionOp
    ::= PLUS
     | MINUS
     | PLUS2
     | PLUSPERCENT
     | MINUSPERCENT

MultiplyOp
    ::= PIPE2
     | ASTERISK
     | SLASH
     | PERCENT
     | ASTERISK2
     | ASTERISKPERCENT

PrefixOp
    ::= EXCLAMATIONMARK
     | MINUS
     | TILDE
     | MINUSPERCENT
     | AMPERSAND
     | KEYWORD_try
     | KEYWORD_await

PrefixTypeOp
    ::= QUESTIONMARK
     | KEYWORD_anyframe MINUSRARROW
     | ArrayTypeStart (ByteAlign | KEYWORD_const | KEYWORD_volatile | KEYWORD_allowzero)*
     | PtrTypeStart (KEYWORD_align LPAREN Expr (COLON INTEGER COLON INTEGER)? RPAREN | KEYWORD_const | KEYWORD_volatile | KEYWORD_allowzero)*

SuffixOp
    ::= LBRACKET Expr (DOT2 Expr?)? RBRACKET
     | DOT IDENTIFIER
     | DOTASTERISK
     | DOTQUESTIONMARK

FnCallArguments ::= LPAREN ExprList RPAREN

//# Ptr specific
ArrayTypeStart ::= LBRACKET Expr? (COLON Expr)? RBRACKET

PtrTypeStart
    ::= ASTERISK
     | ASTERISK2
     | LBRACKET ASTERISK (LETTERC | COLON Expr)? RBRACKET

//# ContainerDecl specific
ContainerDeclAuto ::= ContainerDeclType LBRACE ContainerMembers RBRACE

ContainerDeclType
    ::= KEYWORD_struct
     | KEYWORD_opaque
     | KEYWORD_enum (LPAREN Expr RPAREN)?
     | KEYWORD_union (LPAREN (KEYWORD_enum (LPAREN Expr RPAREN)? | Expr) RPAREN)?

//# Alignment
ByteAlign ::= KEYWORD_align LPAREN Expr RPAREN

//# Lists
IdentifierList ::= (IDENTIFIER COMMA)* IDENTIFIER?

SwitchProngList ::= (SwitchProng COMMA)* SwitchProng?

AsmOutputList ::= (AsmOutputItem COMMA)* AsmOutputItem?

AsmInputList ::= (AsmInputItem COMMA)* AsmInputItem?

StringList ::= (STRINGLITERAL COMMA)* STRINGLITERAL?

ParamDeclList ::= (ParamDecl COMMA)* ParamDecl?

ExprList ::= (Expr COMMA)* Expr?

//# *** Tokens ***
eof ::= '!.'
eol ::= ('\r'? '\n') | eof
hex ::= [0-9a-fA-F]
hex_ ::= ('_'/hex)
dec ::= [0-9]
dec_ ::= ('_'/dec)

dec_int ::= dec (dec_* dec)?
hex_int ::= hex (hex_* dec)?

char_escape
    ::= '\\x' hex hex
     | '\\u{' hex+ '}'
     | '\\' [nr\\t'"]
char_char
    ::= char_escape
     | [^\\'\r\n]
string_char
    ::= char_escape
     | [^\\"\r\n]

line_comment ::= '//'[^\r\n]* eol
line_string ::= ('\\\\' [^\r\n]* eol skip)+
skip ::= ([ \t] | eol | line_comment)*

CHAR_LITERAL ::= "'" char_char "'" skip
FLOAT
    ::= '0x' hex_* hex '.' hex_int ([pP] [-+]? hex_int)? skip
     |      dec_int   '.' dec_int ([eE] [-+]? dec_int)? skip
     | '0x' hex_* hex '.'? [pP] [-+]? hex_int skip
     |      dec_int   '.'? [eE] [-+]? dec_int skip
INTEGER
    ::= '0b' [_01]*  [01]  skip
     | '0o' [_0-7]* [0-7] skip
     | '0x' hex_* hex skip
     |      dec_int   skip
STRINGLITERALSINGLE ::= '"' string_char* '"' skip
STRINGLITERAL
    ::= STRINGLITERALSINGLE
     | line_string skip
IDENTIFIER
    ::= '!'keyword [A-Za-z_] [A-Za-z0-9_]* skip
     | '@"' string_char* '"' skip
BUILTINIDENTIFIER ::= '@'[A-Za-z_][A-Za-z0-9_]* skip


AMPERSAND            ::= '&'      //![=]      skip
AMPERSANDEQUAL       ::= '&='     //          skip
ASTERISK             ::= '*'      //![*%=]    skip
ASTERISK2            ::= '**'     //          skip
ASTERISKEQUAL        ::= '*='     //          skip
ASTERISKPERCENT      ::= '*%'     //![=]      skip
ASTERISKPERCENTEQUAL ::= '*%='    //          skip
CARET                ::= '^'      //![=]      skip
CARETEQUAL           ::= '^='     //          skip
COLON                ::= ':'      //          skip
COMMA                ::= ','      //          skip
DOT                  ::= '.'      //![*.?]    skip
DOT2                 ::= '..'     //![.]      skip
DOT3                 ::= '...'    //          skip
DOTASTERISK          ::= '.*'     //          skip
DOTQUESTIONMARK      ::= '.?'     //          skip
EQUAL                ::= '='      //![>=]     skip
EQUALEQUAL           ::= '=='     //          skip
EQUALRARROW          ::= '=>'     //          skip
EXCLAMATIONMARK      ::= '!'      //![=]      skip
EXCLAMATIONMARKEQUAL ::= '!='     //          skip
LARROW               ::= '<'      //![<=]     skip
LARROW2              ::= '<<'     //![=]      skip
LARROW2EQUAL         ::= '<<='    //          skip
LARROWEQUAL          ::= '<='     //          skip
LBRACE               ::= '{'      //          skip
LBRACKET             ::= '['      //          skip
LPAREN               ::= '('      //          skip
MINUS                ::= '-'      //![%=>]    skip
MINUSEQUAL           ::= '-='     //          skip
MINUSPERCENT         ::= '-%'     //![=]      skip
MINUSPERCENTEQUAL    ::= '-%='    //          skip
MINUSRARROW          ::= '->'     //          skip
PERCENT              ::= '%'      //![=]      skip
PERCENTEQUAL         ::= '%='     //          skip
PIPE                 ::= '|'      //![|=]     skip
PIPE2                ::= '||'     //          skip
PIPEEQUAL            ::= '|='     //          skip
PLUS                 ::= '+'      //![%+=]    skip
PLUS2                ::= '++'     //          skip
PLUSEQUAL            ::= '+='     //          skip
PLUSPERCENT          ::= '+%'     //![=]      skip
PLUSPERCENTEQUAL     ::= '+%='    //          skip
LETTERC              ::= 'c'      //          skip
QUESTIONMARK         ::= '?'      //          skip
RARROW               ::= '>'      //![>=]     skip
RARROW2              ::= '>>'     //![=]      skip
RARROW2EQUAL         ::= '>>='    //          skip
RARROWEQUAL          ::= '>='     //          skip
RBRACE               ::= '}'      //          skip
RBRACKET             ::= ']'      //          skip
RPAREN               ::= ')'      //          skip
SEMICOLON            ::= ';'      //          skip
SLASH                ::= '/'      //![=]      skip
SLASHEQUAL           ::= '/='     //          skip
TILDE                ::= '~'      //          skip

end_of_word ::= '!'[a-zA-Z0-9_] skip
KEYWORD_align       ::= 'align'       //end_of_word
KEYWORD_allowzero   ::= 'allowzero'   //end_of_word
KEYWORD_and         ::= 'and'         //end_of_word
KEYWORD_anyframe    ::= 'anyframe'    //end_of_word
KEYWORD_anytype     ::= 'anytype'     //end_of_word
KEYWORD_asm         ::= 'asm'         //end_of_word
KEYWORD_async       ::= 'async'       //end_of_word
KEYWORD_await       ::= 'await'       //end_of_word
KEYWORD_break       ::= 'break'       //end_of_word
KEYWORD_callconv    ::= 'callconv'    //end_of_word
KEYWORD_catch       ::= 'catch'       //end_of_word
KEYWORD_comptime    ::= 'comptime'    //end_of_word
KEYWORD_const       ::= 'const'       //end_of_word
KEYWORD_continue    ::= 'continue'    //end_of_word
KEYWORD_defer       ::= 'defer'       //end_of_word
KEYWORD_else        ::= 'else'        //end_of_word
KEYWORD_enum        ::= 'enum'        //end_of_word
KEYWORD_errdefer    ::= 'errdefer'    //end_of_word
KEYWORD_error       ::= 'error'       //end_of_word
KEYWORD_export      ::= 'export'      //end_of_word
KEYWORD_extern      ::= 'extern'      //end_of_word
KEYWORD_false       ::= 'false'       //end_of_word
KEYWORD_fn          ::= 'fn'          //end_of_word
KEYWORD_for         ::= 'for'         //end_of_word
KEYWORD_if          ::= 'if'          //end_of_word
KEYWORD_inline      ::= 'inline'      //end_of_word
KEYWORD_noalias     ::= 'noalias'     //end_of_word
KEYWORD_nosuspend   ::= 'nosuspend'   //end_of_word
KEYWORD_noinline    ::= 'noinline'    //end_of_word
KEYWORD_null        ::= 'null'        //end_of_word
KEYWORD_opaque      ::= 'opaque'      //end_of_word
KEYWORD_or          ::= 'or'          //end_of_word
KEYWORD_orelse      ::= 'orelse'      //end_of_word
KEYWORD_packed      ::= 'packed'      //end_of_word
KEYWORD_pub         ::= 'pub'         //end_of_word
KEYWORD_resume      ::= 'resume'      //end_of_word
KEYWORD_return      ::= 'return'      //end_of_word
KEYWORD_linksection ::= 'linksection' //end_of_word
KEYWORD_struct      ::= 'struct'      //end_of_word
KEYWORD_suspend     ::= 'suspend'     //end_of_word
KEYWORD_switch      ::= 'switch'      //end_of_word
KEYWORD_test        ::= 'test'        //end_of_word
KEYWORD_threadlocal ::= 'threadlocal' //end_of_word
KEYWORD_true        ::= 'true'        //end_of_word
KEYWORD_try         ::= 'try'         //end_of_word
KEYWORD_undefined   ::= 'undefined'   //end_of_word
KEYWORD_union       ::= 'union'       //end_of_word
KEYWORD_unreachable ::= 'unreachable' //end_of_word
KEYWORD_usingnamespace ::= 'usingnamespace' //end_of_word
KEYWORD_var         ::= 'var'         //end_of_word
KEYWORD_volatile    ::= 'volatile'    //end_of_word
KEYWORD_while       ::= 'while'       //end_of_word

keyword ::= KEYWORD_align | KEYWORD_allowzero | KEYWORD_and | KEYWORD_anyframe
         | KEYWORD_anytype | KEYWORD_asm | KEYWORD_async | KEYWORD_await
         | KEYWORD_break | KEYWORD_callconv | KEYWORD_catch | KEYWORD_comptime
         | KEYWORD_const | KEYWORD_continue | KEYWORD_defer | KEYWORD_else
         | KEYWORD_enum | KEYWORD_errdefer | KEYWORD_error | KEYWORD_export
         | KEYWORD_extern | KEYWORD_false | KEYWORD_fn | KEYWORD_for | KEYWORD_if
         | KEYWORD_inline | KEYWORD_noalias | KEYWORD_nosuspend | KEYWORD_noinline
         | KEYWORD_null | KEYWORD_opaque | KEYWORD_or | KEYWORD_orelse | KEYWORD_packed
         | KEYWORD_pub | KEYWORD_resume | KEYWORD_return | KEYWORD_linksection
         | KEYWORD_struct | KEYWORD_suspend | KEYWORD_switch
         | KEYWORD_test | KEYWORD_threadlocal | KEYWORD_true | KEYWORD_try
         | KEYWORD_undefined | KEYWORD_union | KEYWORD_unreachable
         | KEYWORD_usingnamespace | KEYWORD_var | KEYWORD_volatile | KEYWORD_while

@mingodad
Copy link

Looking through the code in src/stage1/parser.cpp the statement in grammar.y should be:

Statement
    <- KEYWORD_comptime? VarDecl
     / KEYWORD_comptime BlockExprStatement
     / KEYWORD_nosuspend BlockExprStatement
     / KEYWORD_suspend (SEMICOLON / BlockExprStatement)
     / KEYWORD_defer Payload? BlockExprStatement //////!!!! missing Payload here
     / KEYWORD_errdefer Payload? BlockExprStatement
     / IfStatement
     / LabeledStatement
     / SwitchExpr
     / AssignExpr SEMICOLON

@ifreund
Copy link
Member

ifreund commented May 11, 2021

@mingodad you'd be better off looking at the self hosted parser in lib/std/zig/parse.zig. The grammar in this repo is correct and defer does not allow a Payload.

@mingodad
Copy link

Thanks for pointing out !
This mean that the src/stage1/parser.cpp is out of sync ?

@ifreund
Copy link
Member

ifreund commented May 11, 2021

This mean that the src/stage1/parser.cpp is out of sync ?

No, on looking at it myself the stage1 parser adhears to the grammar in this case:
https://github.com/ziglang/zig/blob/ac546f56eb2b9fd50a69f1d0bda3d0d070b76f52/src/stage1/parser.cpp#L965-L966

@mingodad
Copy link

Thank you for pointing out !
Looking at it again as you pointed out I can see that I failed to understand the code.
Thank you again !

@ifreund
Copy link
Member

ifreund commented May 11, 2021

Thank you for pointing out !
Looking at it again as you pointed out I can see that I failed to understand the code.
Thank you again !

No problem, as usual the self hosted parser is much more readable :)

@mingodad
Copy link

I'm trying to write a zig parser using CocoR https://ssw.jku.at/Research/Projects/Coco/ and in doing so I'm getting lots of warnings/errors due to grammar ambiguity and recursion, for example comptime in PimaryExpr is recursive and zig actually accepts things like this (also with other qualifiers/attributes):

const std = @import("std");

fn fibonacci(index: u32) u32 {
    if (index < 2) return index;
    return fibonacci(index - 1) + fibonacci(index - 2);
}

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();
    try stdout.print("Hello, {}!\n", .{"world"});
    try stdout.print("fibonacci(7)= {}\n", .{fibonacci(7)});
    var x7 = comptime comptime comptime fibonacci(7); ////!!! we can have an infinite/long sequence of comptime
    try stdout.print("fibonacci(7)= {}\n", .{x7});
}

@ifreund
Copy link
Member

ifreund commented May 11, 2021

I'm trying to write a zig parser using CocoR https://ssw.jku.at/Research/Projects/Coco/ and in doing so I'm getting lots of warnings/errors due to grammar ambiguity and recursion, for example comptime in PimaryExpr is recursive and zig actually accepts things like this (also with other qualifiers/attributes):

Parsing Expression Grammars such as the grammar in this repo are by definition unambiguous. I don't see recursion as an issue in general either, although that specific case of repeated comptime keywords will be addressed by ziglang/zig#8364.

@mingodad
Copy link

One recursion/duplicate/ambiguity for comptime starts in Statement:

Statement
    <- KEYWORD_comptime? VarDecl
     / KEYWORD_comptime BlockExprStatement ///!!! BlockExprStatement can start with comptime
...
BlockExprStatement
    <- BlockExpr
     / AssignExpr SEMICOLON ///!!! from here
...
AssignExpr <- Expr (AssignOp Expr)? ///!!! going down here Expr can start recursively with comptime
...
PrimaryExpr
    <- AsmExpr
...
     / KEYWORD_comptime Expr ///!!! here the recursion starts
...

@mingodad
Copy link

mingodad commented May 11, 2021

It also happen with nosuspend:

const std = @import("std");

fn fibonacci(index: u32) u32 {
    if (index < 2) return index;
    return fibonacci(index - 1) + fibonacci(index - 2);
}

pub fn main() !void {
    const stdout = std.io.getStdOut().writer();
    try stdout.print("Hello, {}!\n", .{"world"});
    try stdout.print("fibonacci(7)= {}\n", .{fibonacci(7)});
    var x7 = comptime nosuspend comptime nosuspend comptime comptime nosuspend nosuspend fibonacci(7);
    try stdout.print("fibonacci(7)= {}\n", .{x7});
}

Output:

zig run hello-ct.zig 
Hello, world!
fibonacci(7)= 13
fibonacci(7)= 13

@mingodad
Copy link

After talking with my pillow I'm convinced that one good way to make this grammar less trick/ambiguous/recursive would be to create a subgroup of Expr let's call it AssignableExpr with all valid Expr elements that are valid on the left hand side of an assignment.

//# *** Expression Level ***
AssignExpr =
	AssignableExpr [AssignOp Expr]
	.

AssignableExpr =
	/*Expr*/
	IDENTIFIER
        ...
	.

Also remove all recursive elements from PrimaryExpr and PrimaryTypeExpr like comptime that as I could see so far is used/valid in four cases: TopLevelComptime, VarDecl, prefixing function calls and prefixing parameter declarations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants