p4lang / p4c

P4_16 reference compiler
https://p4.org/
Apache License 2.0
665 stars 439 forks source link

Grammar railroad diagram #4017

Open mingodad opened 1 year ago

mingodad commented 1 year ago

Using some online tools like https://www.bottlecaps.de/rr/ui and https://www.bottlecaps.de/convert/ and manually adding the tokens from the lexer we can have a nice navigable railroad diagram.

Copy and paste the EBNF shown bellow on https://www.bottlecaps.de/rr/ui on the tab Edit Grammar the click on the tab View Diagram to see/download a navigable railroad diagram.

/* converted on Fri May 26, 2023, 09:33 (UTC+02) by bison-to-w3c v0.64 which is Copyright (c) 2011-2023 by Gunther Rademacher <grd@gmx.net> */
//https://github.com/p4lang/p4c/blob/main/frontends/parsers/p4/p4parser.ypp

start    ::= fragment END_ANNOTATION
           | START_PROGRAM program
fragment ::= START_EXPRESSION_LIST expressionList
           | START_KV_LIST kvList
           | ( START_INTEGER_LIST ( INTEGER ',' )* | START_INTEGER | ( START_INTEGER_PAIR | START_INTEGER_TRIPLE INTEGER ',' ) INTEGER ',' ) INTEGER
           | ( START_INTEGER_OR_STRING_LITERAL_LIST ( intOrStr ',' )* | START_INTEGER_OR_STRING_LITERAL ) intOrStr
           | ( START_STRING_LITERAL_LIST ( STRING_LITERAL ',' )* | START_STRING_LITERAL | ( START_STRING_LITERAL_PAIR | START_STRING_LITERAL_TRIPLE STRING_LITERAL ',' ) STRING_LITERAL ',' ) STRING_LITERAL
           | ( START_EXPRESSION | ( START_EXPRESSION_PAIR | START_EXPRESSION_TRIPLE expression ',' ) expression ',' ) expression
           | START_P4RT_TRANSLATION_ANNOTATION STRING_LITERAL ',' p4rtControllerType
p4rtControllerType
         ::= STRING
           | BIT l_angle INTEGER r_angle
           | INTEGER
program  ::= ( declaration | ';' )* END
declaration
         ::= constantDeclaration
           | externDeclaration
           | actionDeclaration
           | parserDeclaration
           | typeDeclaration
           | controlDeclaration
           | instantiation
           | errorDeclaration
           | matchKindDeclaration
           | functionDeclaration
nonTypeName
         ::= IDENTIFIER
           | APPLY
           | KEY
           | ACTIONS
           | STATE
           | ENTRIES
           | TYPE
name     ::= nonTypeName
           | LIST
           | TYPE_IDENTIFIER
nonTableKwName
         ::= IDENTIFIER
           | TYPE_IDENTIFIER
           | APPLY
           | STATE
           | TYPE
optCONST ::= CONST?
optAnnotations
         ::= annotations?
annotations
         ::= annotation+
annotation
         ::= '@' name ( '(' annotationBody ')' | '[' ( expressionList | kvList ) optTrailingComma ']' )?
           | PRAGMA name annotationBody END_PRAGMA
annotationBody
         ::= ( annotationBody ( '(' annotationBody ')' | annotationToken ) )?
annotationToken
         ::= UNEXPECTED_TOKEN
           | ABSTRACT
           | ACTION
           | ACTIONS
           | APPLY
           | BOOL
           | BIT
           | CONST
           | CONTROL
           | DEFAULT
           | ELSE
           | ENTRIES
           | ENUM
           | ERROR
           | EXIT
           | EXTERN
           | FALSE
           | HEADER
           | HEADER_UNION
           | IF
           | IN
           | INOUT
           | INT
           | KEY
           | MATCH_KIND
           | TYPE
           | OUT
           | PARSER
           | PACKAGE
           | PRAGMA
           | RETURN
           | SELECT
           | STATE
           | STRING
           | STRUCT
           | SWITCH
           | TABLE
           | THIS
           | TRANSITION
           | TRUE
           | TUPLE
           | TYPEDEF
           | VARBIT
           | VALUESET
           | LIST
           | VOID
           | '_'
           | IDENTIFIER
           | TYPE_IDENTIFIER
           | STRING_LITERAL
           | INTEGER
           | '&&&'
           | '..'
           | '<<'
           | '&&'
           | '||'
           | '=='
           | '!='
           | '>='
           | '<='
           | '++'
           | '+'
           | '|+|'
           | '-'
           | '|-|'
           | '*'
           | '/'
           | '%'
           | '|'
           | '&'
           | '^'
           | '~'
           | '['
           | ']'
           | '{'
           | '}'
           | '<'
           | L_ANGLE_ARGS
           | '>'
           | R_ANGLE_SHIFT
           | '!'
           | ':'
           | ','
           | '?'
           | '.'
           | '='
           | ';'
           | '@'
kvList   ::= kvPair ( ',' kvPair )*
kvPair   ::= name '=' expression
parameterList
         ::= ( parameter ( ',' parameter )* )?
parameter
         ::= optAnnotations direction typeRef name ( '=' expression )?
direction
         ::= ( IN | OUT | INOUT )?
packageTypeDeclaration
         ::= optAnnotations PACKAGE name optTypeParameters '(' parameterList ')'
instantiation
         ::= annotations? typeRef '(' argumentList ')' name ( '=' objInitializer )? ';'
objInitializer
         ::= '{' objDeclaration* '}'
objDeclaration
         ::= functionDeclaration
           | instantiation
optConstructorParameters
         ::= ( '(' parameterList ')' )?
parserDeclaration
         ::= parserTypeDeclaration optConstructorParameters '{' parserLocalElement* parserState+ '}'
parserLocalElement
         ::= constantDeclaration
           | instantiation
           | variableDeclaration
           | valueSetDeclaration
parserTypeDeclaration
         ::= optAnnotations PARSER name optTypeParameters '(' parameterList ')'
parserState
         ::= optAnnotations STATE name '{' parserStatements transitionStatement '}'
parserStatements
         ::= parserStatement*
parserStatement
         ::= assignmentOrMethodCallStatement
           | directApplication
           | ';'
           | variableDeclaration
           | constantDeclaration
           | parserBlockStatement
           | conditionalStatement
parserBlockStatement
         ::= optAnnotations '{' parserStatements '}'
transitionStatement
         ::= ( TRANSITION stateExpression )?
stateExpression
         ::= name ';'
           | selectExpression
selectExpression
         ::= SELECT '(' expressionList ')' '{' selectCase* '}'
selectCase
         ::= keysetExpression ':' name ';'
keysetExpression
         ::= tupleKeysetExpression
           | simpleKeysetExpression
tupleKeysetExpression
         ::= '(' ( simpleKeysetExpression ( ',' simpleKeysetExpression )+ | reducedSimpleKeysetExpression ) ')'
optTrailingComma
         ::= ','?
reducedSimpleKeysetExpression
         ::= expression ( '&&&' | '..' ) expression
           | DEFAULT
           | '_'
simpleKeysetExpression
         ::= expression ( ( '&&&' | '..' ) expression )?
           | DEFAULT
           | '_'
valueSetDeclaration
         ::= optAnnotations VALUESET l_angle ( baseType | tupleType | typeName ) r_angle '(' expression ')' name ';'
controlDeclaration
         ::= controlTypeDeclaration optConstructorParameters '{' controlLocalDeclaration* APPLY controlBody '}'
controlTypeDeclaration
         ::= optAnnotations CONTROL name optTypeParameters '(' parameterList ')'
controlLocalDeclaration
         ::= constantDeclaration
           | actionDeclaration
           | tableDeclaration
           | instantiation
           | variableDeclaration
controlBody
         ::= blockStatement
externDeclaration
         ::= optAnnotations EXTERN ( nonTypeName optTypeParameters '{' methodPrototype* '}' | ( functionPrototype | name ) ';' )
functionPrototype
         ::= typeOrVoid name optTypeParameters '(' parameterList ')'
methodPrototype
         ::= optAnnotations ( ABSTRACT? functionPrototype | TYPE_IDENTIFIER '(' parameterList ')' ) ';'
typeRef  ::= baseType
           | typeName
           | specializedType
           | headerStackType
           | p4listType
           | tupleType
namedType
         ::= typeName
           | specializedType
prefixedType
         ::= '.'? TYPE_IDENTIFIER
typeName ::= prefixedType
p4listType
         ::= LIST l_angle typeArg r_angle
tupleType
         ::= TUPLE l_angle typeArgumentList r_angle
headerStackType
         ::= ( typeName | specializedType ) '[' expression ']'
specializedType
         ::= typeName l_angle typeArgumentList r_angle
baseType ::= BOOL
           | MATCH_KIND
           | ERROR
           | ( BIT | INT ) ( l_angle ( INTEGER | '(' expression ')' ) r_angle )?
           | STRING
           | VARBIT l_angle ( INTEGER | '(' expression ')' ) r_angle
typeOrVoid
         ::= typeRef
           | VOID
           | IDENTIFIER
optTypeParameters
         ::= typeParameters?
typeParameters
         ::= l_angle name ( ',' name )* r_angle
typeArg  ::= typeRef
           | nonTypeName
           | VOID
           | '_'
typeArgumentList
         ::= typeArg? ( ',' typeArg )*
realTypeArg
         ::= typeRef
           | VOID
           | '_'
realTypeArgumentList
         ::= realTypeArg ( ',' typeArg )*
typeDeclaration
         ::= derivedTypeDeclaration
           | ( typedefDeclaration | parserTypeDeclaration | controlTypeDeclaration | packageTypeDeclaration ) ';'
derivedTypeDeclaration
         ::= headerTypeDeclaration
           | headerUnionDeclaration
           | structTypeDeclaration
           | enumDeclaration
headerTypeDeclaration
         ::= optAnnotations HEADER name optTypeParameters '{' structFieldList '}'
structTypeDeclaration
         ::= optAnnotations STRUCT name optTypeParameters '{' structFieldList '}'
headerUnionDeclaration
         ::= optAnnotations HEADER_UNION name optTypeParameters '{' structFieldList '}'
structFieldList
         ::= structField*
structField
         ::= optAnnotations typeRef name ';'
enumDeclaration
         ::= optAnnotations ENUM ( name '{' identifierList | typeRef name '{' specifiedIdentifier ( ',' specifiedIdentifier )* ) optTrailingComma '}'
specifiedIdentifier
         ::= name '=' initializer
errorDeclaration
         ::= ERROR '{' identifierList '}'
matchKindDeclaration
         ::= MATCH_KIND '{' identifierList optTrailingComma '}'
identifierList
         ::= name ( ',' name )*
typedefDeclaration
         ::= optAnnotations ( TYPEDEF ( typeRef | derivedTypeDeclaration ) | TYPE typeRef ) name
assignmentOrMethodCallStatement
         ::= lvalue ( ( l_angle typeArgumentList r_angle )? '(' argumentList ')' | '=' expression ) ';'
exitStatement
         ::= EXIT ';'
returnStatement
         ::= RETURN expression? ';'
conditionalStatement
         ::= IF '(' expression ')' statement ( ELSE statement )?
directApplication
         ::= ( typeName | specializedType ) '.' APPLY '(' argumentList ')' ';'
statement
         ::= assignmentOrMethodCallStatement
           | directApplication
           | conditionalStatement
           | ';'
           | blockStatement
           | returnStatement
           | exitStatement
           | switchStatement
blockStatement
         ::= optAnnotations '{' statementOrDeclaration* '}'
switchStatement
         ::= SWITCH '(' expression ')' '{' switchCase* '}'
switchCase
         ::= switchLabel ':' blockStatement?
switchLabel
         ::= DEFAULT
           | ( INTEGER | STRING_LITERAL | TRUE | FALSE | THIS | prefixedNonTypeName | '(' ( expression ')' | typeRef ')' expression ) | ( '!' | '~' | '-' | '+' ) expression | typeName dot_name | ERROR '.' name | namedType '(' argumentList ')' ) ( '[' expression ( ':' expression )? ']' | dot_name | ( '*' | '/' | '%' | '+' | '-' | '|+|' | '|-|' | '<<' | R_ANGLE_SHIFT? '>' | '<=' | '>=' | '!=' | '==' | '&' | '^' | '|' | '++' | '&&' | '||' | '?' expression ':' ) expression | l_angle ( expression | realTypeArgumentList r_angle '(' argumentList ')' ) | '(' argumentList ')' )*
statementOrDeclaration
         ::= variableDeclaration
           | constantDeclaration
           | statement
           | instantiation
tableDeclaration
         ::= optAnnotations TABLE name '{' tableProperty+ '}'
tableProperty
         ::= ( KEY '=' '{' keyElement* | ACTIONS '=' '{' ( optAnnotations actionRef ';' )* ) '}'
           | optAnnotations optCONST ( ENTRIES '=' '{' entry* '}' | nonTableKwName '=' initializer ';' )
keyElement
         ::= expression ':' name optAnnotations ';'
actionRef
         ::= prefixedNonTypeName ( '(' argumentList ')' )?
entry    ::= keysetExpression ':' actionRef optAnnotations ';'
actionDeclaration
         ::= optAnnotations ACTION name '(' parameterList ')' blockStatement
variableDeclaration
         ::= annotations? typeRef name optInitializer ';'
constantDeclaration
         ::= optAnnotations CONST typeRef name '=' initializer ';'
optInitializer
         ::= ( '=' initializer )?
initializer
         ::= expression
functionDeclaration
         ::= functionPrototype blockStatement
argumentList
         ::= ( argument ( ',' argument )* )?
argument ::= ( name '=' )? ( expression | '_' )
expressionList
         ::= expression? ( ',' expression )*
prefixedNonTypeName
         ::= '.'? nonTypeName
dot_name ::= '.' name
lvalue   ::= ( prefixedNonTypeName | THIS ) ( dot_name | '[' expression ( ':' expression )? ']' )*
expression
         ::= INTEGER
           | DOTS
           | STRING_LITERAL
           | TRUE
           | FALSE
           | THIS
           | prefixedNonTypeName
           | expression ( '[' expression ( ':' expression )? ']' | dot_name | ( '*' | '/' | '%' | '+' | '-' | '|+|' | '|-|' | '<<' | R_ANGLE_SHIFT? '>' | '<=' | '>=' | '!=' | '==' | '&' | '^' | '|' | '++' | '&&' | '||' | '?' expression ':' ) expression | l_angle ( expression | realTypeArgumentList r_angle '(' argumentList ')' ) | '(' argumentList ')' )
           | '{' ( expressionList | kvList ( ',' DOTS )? ) optTrailingComma '}'
           | INVALID
           | '(' ( expression ')' | typeRef ')' expression )
           | ( '!' | '~' | '-' | '+' ) expression
           | typeName dot_name
           | ERROR '.' name
           | namedType '(' argumentList ')'
intOrStr ::= INTEGER
           | STRING_LITERAL
l_angle  ::= '<'
           | L_ANGLE_ARGS
r_angle  ::= '>'
           | R_ANGLE_SHIFT

// Tokens

//\("[^"]+"\)\s+{ BEGIN(driver.saveState); return makeToken(\([^)]+\)); }

PRAGMA ::= "@pragma"
ABSTRACT ::= "abstract"
ACTION ::= "action"
ACTIONS ::= "actions"
APPLY ::= "apply"
BOOL ::= "bool"
BIT ::= "bit"
CONST ::= "const"
CONTROL ::= "control"
DEFAULT ::= "default"
ELSE ::= "else"
ENTRIES ::= "entries"
ENUM ::= "enum"
ERROR ::= "error"
EXIT ::= "exit"
EXTERN ::= "extern"
FALSE ::= "false"
HEADER ::= "header"
HEADER_UNION ::= "header_union"
IF ::= "if"
IN ::= "in"
INOUT ::= "inout"
INT ::= "int"
KEY ::= "key"
MATCH_KIND ::= "match_kind"
TYPE ::= "type"
OUT ::= "out"
PARSER ::= "parser"
PACKAGE ::= "package"
RETURN ::= "return"
SELECT ::= "select"
STATE ::= "state"
STRUCT ::= "struct"
SWITCH ::= "switch"
TABLE ::= "table"
THIS ::= "this"
TRANSITION ::= "transition"
TRUE ::= "true"
TUPLE ::= "tuple"
TYPEDEF ::= "typedef"
VARBIT ::= "varbit"
VALUESET ::= "value_set"
VOID ::= "void"
DONTCARE ::= "_"

MASK ::= "&&&"
RANGE ::= ".."
SHL ::= "<<"
AND ::= "&&"
OR ::= "||"
EQ ::= "=="
NE ::= "!="
GE ::= ">="
LE ::= "<="
PP ::= "++"

PLUS ::= "+"
PLUS_SAT ::= "|+|"
MINUS ::= "-"
MINUS_SAT ::= "|-|"
MUL ::= "*"
DIV ::= "/"
MOD ::= "%"

BIT_OR ::= "|"
BIT_AND ::= "&"
BIT_XOR ::= "^"
COMPLEMENT ::= "~"

L_PAREN ::= "("
R_PAREN ::= ")"
L_BRACKET ::= "["
R_BRACKET ::= "]"
L_BRACE ::= "{"
R_BRACE ::= "}"
L_ANGLE ::= "<"
R_ANGLE ::= ">"

NOT ::= "!"
COLON ::= ":"
COMMA ::= ","
QUESTION ::= "?"
DOT ::= "."
ASSIGN ::= "="
SEMICOLON ::= ";"
AT ::= "@"
jafingerhut commented 1 year ago

Thanks for sharing that.

We do tend to update the P4_16 grammar several times per year, as we add enhancements to the language. If p4c developers would like your work saved somehow, either:

(a) it would be good to have an automated way from the latest grammar to produce input usable for that visualization

or

(b) periodically someone should do the work manually to take the latest grammar and put it into this form, and check that in.

I do not know whether p4c developers find it useful enough to look at the railroad diagrams to justify the effort required, though. For me personally, I am so accustomed to the text format for specifying the grammar that it conveys all the information I want, in an ready-to-use format.

fruffy commented 1 year ago

I do not know whether p4c developers find it useful enough to look at the railroad diagrams to justify the effort required, though. For me personally, I am so accustomed to the text format for specifying the grammar that it conveys all the information I want, in an ready-to-use format.

I think having an EBNF grammar to accompany the spec can be generally useful to produce parsers etc. I am not sure how easy it is to maintain and who would currently use it.

mingodad commented 1 year ago

I also made some extensions to bison/byacc/lemon to output an EBNF and a naked grammar here https://github.com/mingodad/lalr-parser-test , for example here is the naked output of p4parser.yy:


/*Tokens*/
%token YYEOF
%token YYerror
%token YYUNDEF
%token START_PROGRAM
%token START_EXPRESSION_LIST
%token START_KV_LIST
%token START_INTEGER_LIST
%token START_INTEGER_OR_STRING_LITERAL_LIST
%token START_STRING_LITERAL_LIST
%token START_EXPRESSION
%token START_INTEGER
%token START_INTEGER_OR_STRING_LITERAL
%token START_STRING_LITERAL
%token START_EXPRESSION_PAIR
%token START_INTEGER_PAIR
%token START_STRING_LITERAL_PAIR
%token START_EXPRESSION_TRIPLE
%token START_INTEGER_TRIPLE
%token START_STRING_LITERAL_TRIPLE
%token START_P4RT_TRANSLATION_ANNOTATION
%token END
%token END_ANNOTATION
%token UNEXPECTED_TOKEN
%token END_PRAGMA
%token LE
%token GE
%token SHL
%token AND
%token OR
%token NE
%token EQ
%token PLUS
%token MINUS
%token PLUS_SAT
%token MINUS_SAT
%token MUL
%token INVALID
%token DIV
%token MOD
%token BIT_OR
%token BIT_AND
%token BIT_XOR
%token COMPLEMENT
%token L_BRACKET
%token R_BRACKET
%token L_BRACE
%token R_BRACE
%token L_ANGLE
%token L_ANGLE_ARGS
%token R_ANGLE
%token R_ANGLE_SHIFT
%token L_PAREN
%token R_PAREN
%token NOT
%token COLON
%token COMMA
%token QUESTION
%token DOT
%token ASSIGN
%token SEMICOLON
%token AT
%token PP
%token DONTCARE
%token MASK
%token DOTS
%token RANGE
%token TRUE
%token FALSE
%token THIS
%token ABSTRACT
%token ACTION
%token ACTIONS
%token APPLY
%token BOOL
%token BIT
%token CONST
%token CONTROL
%token DEFAULT
%token ELSE
%token ENTRIES
%token ENUM
%token ERROR
%token EXIT
%token EXTERN
%token HEADER
%token HEADER_UNION
%token IF
%token IN
%token INOUT
%token INT
%token KEY
%token LIST
%token SELECT
%token MATCH_KIND
%token TYPE
%token OUT
%token PACKAGE
%token PARSER
%token PRAGMA
%token RETURN
%token STATE
%token STRING
%token STRUCT
%token SWITCH
%token TABLE
%token TRANSITION
%token TUPLE
%token TYPEDEF
%token VARBIT
%token VALUESET
%token VOID
%token IDENTIFIER
%token TYPE_IDENTIFIER
%token STRING_LITERAL
%token INTEGER
%token PREFIX
%token THEN

%precedence /*1*/ QUESTION
%precedence /*2*/ COLON
%left /*3*/ OR
%left /*4*/ AND
%left /*5*/ NE EQ
%left /*6*/ LE GE L_ANGLE R_ANGLE
%left /*7*/ BIT_OR
%left /*8*/ BIT_XOR
%left /*9*/ BIT_AND
%left /*10*/ SHL R_ANGLE_SHIFT
%left /*11*/ PLUS MINUS PLUS_SAT MINUS_SAT PP
%left /*12*/ MUL DIV MOD
%precedence /*13*/ PREFIX
%precedence /*14*/ L_BRACKET R_BRACKET L_ANGLE_ARGS L_PAREN
%precedence /*15*/ DOT
%right /*16*/ ELSE THEN

%start start

%%

start :
    YYEOF 
    | fragment END_ANNOTATION 
    | START_PROGRAM program 
    ;

fragment :
    START_EXPRESSION_LIST expressionList 
    | START_KV_LIST kvList 
    | START_INTEGER_LIST intList 
    | START_INTEGER_OR_STRING_LITERAL_LIST intOrStrList 
    | START_STRING_LITERAL_LIST strList 
    | START_EXPRESSION expression 
    | START_INTEGER INTEGER 
    | START_INTEGER_OR_STRING_LITERAL intOrStr 
    | START_STRING_LITERAL STRING_LITERAL 
    | START_EXPRESSION_PAIR expression "," expression 
    | START_INTEGER_PAIR INTEGER "," INTEGER 
    | START_STRING_LITERAL_PAIR STRING_LITERAL "," STRING_LITERAL 
    | START_EXPRESSION_TRIPLE expression "," expression "," expression 
    | START_INTEGER_TRIPLE INTEGER "," INTEGER "," INTEGER 
    | START_STRING_LITERAL_TRIPLE STRING_LITERAL "," STRING_LITERAL "," STRING_LITERAL 
    | START_P4RT_TRANSLATION_ANNOTATION STRING_LITERAL "," p4rtControllerType 
    ;

p4rtControllerType :
    STRING 
    | BIT l_angle INTEGER r_angle 
    | INTEGER 
    ;

program :
    input END 
    ;

input :
    /*empty*/
    | input declaration 
    | input ";" 
    ;

declaration :
    constantDeclaration 
    | externDeclaration 
    | actionDeclaration 
    | parserDeclaration 
    | typeDeclaration 
    | controlDeclaration 
    | instantiation 
    | errorDeclaration 
    | matchKindDeclaration 
    | functionDeclaration 
    ;

nonTypeName :
    IDENTIFIER 
    | APPLY 
    | KEY 
    | ACTIONS 
    | STATE 
    | ENTRIES 
    | TYPE 
    ;

name :
    nonTypeName 
    | LIST 
    | TYPE_IDENTIFIER 
    ;

nonTableKwName :
    IDENTIFIER 
    | TYPE_IDENTIFIER 
    | APPLY 
    | STATE 
    | TYPE 
    ;

optCONST :
    /*empty*/
    | CONST 
    ;

optAnnotations :
    /*empty*/
    | annotations 
    ;

annotations :
    annotation 
    | annotations annotation 
    ;

annotation :
    "@" name 
    | "@" name "(" /*14P*/ annotationBody ")" 
    | "@" name "[" /*14P*/ expressionList optTrailingComma "]" /*14P*/ 
    | "@" name "[" /*14P*/ kvList optTrailingComma "]" /*14P*/ 
    | PRAGMA name annotationBody END_PRAGMA 
    ;

annotationBody :
    /*empty*/
    | annotationBody "(" /*14P*/ annotationBody ")" 
    | annotationBody annotationToken 
    ;

annotationToken :
    UNEXPECTED_TOKEN 
    | ABSTRACT 
    | ACTION 
    | ACTIONS 
    | APPLY 
    | BOOL 
    | BIT 
    | CONST 
    | CONTROL 
    | DEFAULT 
    | ELSE /*16R*/ 
    | ENTRIES 
    | ENUM 
    | ERROR 
    | EXIT 
    | EXTERN 
    | FALSE 
    | HEADER 
    | HEADER_UNION 
    | IF 
    | IN 
    | INOUT 
    | INT 
    | KEY 
    | MATCH_KIND 
    | TYPE 
    | OUT 
    | PARSER 
    | PACKAGE 
    | PRAGMA 
    | RETURN 
    | SELECT 
    | STATE 
    | STRING 
    | STRUCT 
    | SWITCH 
    | TABLE 
    | THIS 
    | TRANSITION 
    | TRUE 
    | TUPLE 
    | TYPEDEF 
    | VARBIT 
    | VALUESET 
    | LIST 
    | VOID 
    | "_" 
    | IDENTIFIER 
    | TYPE_IDENTIFIER 
    | STRING_LITERAL 
    | INTEGER 
    | "&&&" 
    | ".." 
    | "<<" /*10L*/ 
    | "&&" /*4L*/ 
    | "||" /*3L*/ 
    | "==" /*5L*/ 
    | "!=" /*5L*/ 
    | ">=" /*6L*/ 
    | "<=" /*6L*/ 
    | "++" /*11L*/ 
    | "+" /*11L*/ 
    | "|+|" /*11L*/ 
    | "-" /*11L*/ 
    | "|-|" /*11L*/ 
    | "*" /*12L*/ 
    | "/" /*12L*/ 
    | "%" /*12L*/ 
    | "|" /*7L*/ 
    | "&" /*9L*/ 
    | "^" /*8L*/ 
    | "~" 
    | "[" /*14P*/ 
    | "]" /*14P*/ 
    | "{" 
    | "}" 
    | "<" /*6L*/ 
    | L_ANGLE_ARGS /*14P*/ 
    | ">" /*6L*/ 
    | R_ANGLE_SHIFT /*10L*/ 
    | "!" 
    | ":" /*2P*/ 
    | "," 
    | "?" /*1P*/ 
    | "." /*15P*/ 
    | "=" 
    | ";" 
    | "@" 
    ;

kvList :
    kvPair 
    | kvList "," kvPair 
    ;

kvPair :
    name "=" expression 
    ;

parameterList :
    /*empty*/
    | nonEmptyParameterList 
    ;

nonEmptyParameterList :
    parameter 
    | nonEmptyParameterList "," parameter 
    ;

parameter :
    optAnnotations direction typeRef name 
    | optAnnotations direction typeRef name "=" expression 
    ;

direction :
    IN 
    | OUT 
    | INOUT 
    | /*empty*/
    ;

packageTypeDeclaration :
    optAnnotations PACKAGE name optTypeParameters "(" /*14P*/ parameterList ")" 
    ;

instantiation :
    annotations typeRef "(" /*14P*/ argumentList ")" name ";" 
    | typeRef "(" /*14P*/ argumentList ")" name ";" 
    | annotations typeRef "(" /*14P*/ argumentList ")" name "=" objInitializer ";" 
    | typeRef "(" /*14P*/ argumentList ")" name "=" objInitializer ";" 
    ;

objInitializer :
    "{" objDeclarations "}" 
    ;

objDeclarations :
    /*empty*/
    | objDeclarations objDeclaration 
    ;

objDeclaration :
    functionDeclaration 
    | instantiation 
    ;

optConstructorParameters :
    /*empty*/
    | "(" /*14P*/ parameterList ")" 
    ;

dotPrefix :
    "." /*15P*/ 
    ;

parserDeclaration :
    parserTypeDeclaration optConstructorParameters "{" parserLocalElements parserStates "}" 
    ;

parserLocalElements :
    /*empty*/
    | parserLocalElements parserLocalElement 
    ;

parserLocalElement :
    constantDeclaration 
    | instantiation 
    | variableDeclaration 
    | valueSetDeclaration 
    ;

parserTypeDeclaration :
    optAnnotations PARSER name optTypeParameters "(" /*14P*/ parameterList ")" 
    ;

parserStates :
    parserState 
    | parserStates parserState 
    ;

parserState :
    optAnnotations STATE name "{" parserStatements transitionStatement "}" 
    ;

parserStatements :
    /*empty*/
    | parserStatements parserStatement 
    ;

parserStatement :
    assignmentOrMethodCallStatement 
    | directApplication 
    | emptyStatement 
    | variableDeclaration 
    | constantDeclaration 
    | parserBlockStatement 
    | conditionalStatement 
    ;

parserBlockStatement :
    optAnnotations "{" parserStatements "}" 
    ;

transitionStatement :
    /*empty*/
    | TRANSITION stateExpression 
    ;

stateExpression :
    name ";" 
    | selectExpression 
    ;

selectExpression :
    SELECT "(" /*14P*/ expressionList ")" "{" selectCaseList "}" 
    ;

selectCaseList :
    /*empty*/
    | selectCaseList selectCase 
    ;

selectCase :
    keysetExpression ":" /*2P*/ name ";" 
    ;

keysetExpression :
    tupleKeysetExpression 
    | simpleKeysetExpression 
    ;

tupleKeysetExpression :
    "(" /*14P*/ simpleKeysetExpression "," simpleExpressionList ")" 
    | "(" /*14P*/ reducedSimpleKeysetExpression ")" 
    ;

optTrailingComma :
    /*empty*/
    | "," 
    ;

simpleExpressionList :
    simpleKeysetExpression 
    | simpleExpressionList "," simpleKeysetExpression 
    ;

reducedSimpleKeysetExpression :
    expression "&&&" expression 
    | expression ".." expression 
    | DEFAULT 
    | "_" 
    ;

simpleKeysetExpression :
    expression 
    | expression "&&&" expression 
    | expression ".." expression 
    | DEFAULT 
    | "_" 
    ;

valueSetDeclaration :
    optAnnotations VALUESET l_angle baseType r_angle "(" /*14P*/ expression ")" name ";" 
    | optAnnotations VALUESET l_angle tupleType r_angle "(" /*14P*/ expression ")" name ";" 
    | optAnnotations VALUESET l_angle typeName r_angle "(" /*14P*/ expression ")" name ";" 
    ;

controlDeclaration :
    controlTypeDeclaration optConstructorParameters "{" controlLocalDeclarations APPLY controlBody "}" 
    ;

controlTypeDeclaration :
    optAnnotations CONTROL name optTypeParameters "(" /*14P*/ parameterList ")" 
    ;

controlLocalDeclarations :
    /*empty*/
    | controlLocalDeclarations controlLocalDeclaration 
    ;

controlLocalDeclaration :
    constantDeclaration 
    | actionDeclaration 
    | tableDeclaration 
    | instantiation 
    | variableDeclaration 
    ;

controlBody :
    blockStatement 
    ;

externDeclaration :
    optAnnotations EXTERN nonTypeName optTypeParameters "{" methodPrototypes "}" 
    | optAnnotations EXTERN functionPrototype ";" 
    | optAnnotations EXTERN name ";" 
    ;

methodPrototypes :
    /*empty*/
    | methodPrototypes methodPrototype 
    ;

functionPrototype :
    typeOrVoid name optTypeParameters "(" /*14P*/ parameterList ")" 
    ;

methodPrototype :
    optAnnotations functionPrototype ";" 
    | optAnnotations ABSTRACT functionPrototype ";" 
    | optAnnotations TYPE_IDENTIFIER "(" /*14P*/ parameterList ")" ";" 
    ;

typeRef :
    baseType 
    | typeName 
    | specializedType 
    | headerStackType 
    | p4listType 
    | tupleType 
    ;

namedType :
    typeName 
    | specializedType 
    ;

prefixedType :
    TYPE_IDENTIFIER 
    | dotPrefix TYPE_IDENTIFIER 
    ;

typeName :
    prefixedType 
    ;

p4listType :
    LIST l_angle typeArg r_angle 
    ;

tupleType :
    TUPLE l_angle typeArgumentList r_angle 
    ;

headerStackType :
    typeName "[" /*14P*/ expression "]" /*14P*/ 
    | specializedType "[" /*14P*/ expression "]" /*14P*/ 
    ;

specializedType :
    typeName l_angle typeArgumentList r_angle 
    ;

baseType :
    BOOL 
    | MATCH_KIND 
    | ERROR 
    | BIT 
    | STRING 
    | INT 
    | BIT l_angle INTEGER r_angle 
    | INT l_angle INTEGER r_angle 
    | VARBIT l_angle INTEGER r_angle 
    | BIT l_angle "(" /*14P*/ expression ")" r_angle 
    | INT l_angle "(" /*14P*/ expression ")" r_angle 
    | VARBIT l_angle "(" /*14P*/ expression ")" r_angle 
    ;

typeOrVoid :
    typeRef 
    | VOID 
    | IDENTIFIER 
    ;

optTypeParameters :
    /*empty*/
    | typeParameters 
    ;

typeParameters :
    l_angle typeParameterList r_angle 
    ;

typeParameterList :
    name 
    | typeParameterList "," name 
    ;

typeArg :
    typeRef 
    | nonTypeName 
    | VOID 
    | "_" 
    ;

typeArgumentList :
    /*empty*/
    | typeArg 
    | typeArgumentList "," typeArg 
    ;

realTypeArg :
    typeRef 
    | VOID 
    | "_" 
    ;

realTypeArgumentList :
    realTypeArg 
    | realTypeArgumentList "," typeArg 
    ;

typeDeclaration :
    derivedTypeDeclaration 
    | typedefDeclaration ";" 
    | parserTypeDeclaration ";" 
    | controlTypeDeclaration ";" 
    | packageTypeDeclaration ";" 
    ;

derivedTypeDeclaration :
    headerTypeDeclaration 
    | headerUnionDeclaration 
    | structTypeDeclaration 
    | enumDeclaration 
    ;

headerTypeDeclaration :
    optAnnotations HEADER name optTypeParameters "{" structFieldList "}" 
    ;

structTypeDeclaration :
    optAnnotations STRUCT name optTypeParameters "{" structFieldList "}" 
    ;

headerUnionDeclaration :
    optAnnotations HEADER_UNION name optTypeParameters "{" structFieldList "}" 
    ;

structFieldList :
    /*empty*/
    | structFieldList structField 
    ;

structField :
    optAnnotations typeRef name ";" 
    ;

enumDeclaration :
    optAnnotations ENUM name "{" identifierList optTrailingComma "}" 
    | optAnnotations ENUM typeRef name "{" specifiedIdentifierList optTrailingComma "}" 
    ;

specifiedIdentifierList :
    specifiedIdentifier 
    | specifiedIdentifierList "," specifiedIdentifier 
    ;

specifiedIdentifier :
    name "=" initializer 
    ;

errorDeclaration :
    ERROR "{" identifierList "}" 
    ;

matchKindDeclaration :
    MATCH_KIND "{" identifierList optTrailingComma "}" 
    ;

identifierList :
    name 
    | identifierList "," name 
    ;

typedefDeclaration :
    optAnnotations TYPEDEF typeRef name 
    | optAnnotations TYPEDEF derivedTypeDeclaration name 
    | optAnnotations TYPE typeRef name 
    ;

assignmentOrMethodCallStatement :
    lvalue "(" /*14P*/ argumentList ")" ";" 
    | lvalue l_angle typeArgumentList r_angle "(" /*14P*/ argumentList ")" ";" 
    | lvalue "=" expression ";" 
    ;

emptyStatement :
    ";" 
    ;

exitStatement :
    EXIT ";" 
    ;

returnStatement :
    RETURN ";" 
    | RETURN expression ";" 
    ;

conditionalStatement :
    IF "(" /*14P*/ expression ")" statement %prec THEN /*16R*/ 
    | IF "(" /*14P*/ expression ")" statement ELSE /*16R*/ statement %prec THEN /*16R*/ 
    ;

directApplication :
    typeName "." /*15P*/ APPLY "(" /*14P*/ argumentList ")" ";" 
    | specializedType "." /*15P*/ APPLY "(" /*14P*/ argumentList ")" ";" 
    ;

statement :
    assignmentOrMethodCallStatement 
    | directApplication 
    | conditionalStatement 
    | emptyStatement 
    | blockStatement 
    | returnStatement 
    | exitStatement 
    | switchStatement 
    ;

blockStatement :
    optAnnotations "{" statOrDeclList "}" 
    ;

statOrDeclList :
    /*empty*/
    | statOrDeclList statementOrDeclaration 
    ;

switchStatement :
    SWITCH "(" /*14P*/ expression ")" "{" switchCases "}" 
    ;

switchCases :
    /*empty*/
    | switchCases switchCase 
    ;

switchCase :
    switchLabel ":" /*2P*/ blockStatement 
    | switchLabel ":" /*2P*/ 
    ;

switchLabel :
    DEFAULT 
    | nonBraceExpression 
    ;

statementOrDeclaration :
    variableDeclaration 
    | constantDeclaration 
    | statement 
    | instantiation 
    ;

tableDeclaration :
    optAnnotations TABLE name "{" tablePropertyList "}" 
    ;

tablePropertyList :
    tableProperty 
    | tablePropertyList tableProperty 
    ;

tableProperty :
    KEY "=" "{" keyElementList "}" 
    | ACTIONS "=" "{" actionList "}" 
    | optAnnotations optCONST ENTRIES "=" "{" entriesList "}" 
    | optAnnotations optCONST nonTableKwName "=" initializer ";" 
    ;

keyElementList :
    /*empty*/
    | keyElementList keyElement 
    ;

keyElement :
    expression ":" /*2P*/ name optAnnotations ";" 
    ;

actionList :
    /*empty*/
    | actionList optAnnotations actionRef ";" 
    ;

actionRef :
    prefixedNonTypeName 
    | prefixedNonTypeName "(" /*14P*/ argumentList ")" 
    ;

entry :
    keysetExpression ":" /*2P*/ actionRef optAnnotations ";" 
    ;

entriesList :
    /*empty*/
    | entriesList entry 
    ;

actionDeclaration :
    optAnnotations ACTION name "(" /*14P*/ parameterList ")" blockStatement 
    ;

variableDeclaration :
    annotations typeRef name optInitializer ";" 
    | typeRef name optInitializer ";" 
    ;

constantDeclaration :
    optAnnotations CONST typeRef name "=" initializer ";" 
    ;

optInitializer :
    /*empty*/
    | "=" initializer 
    ;

initializer :
    expression 
    ;

functionDeclaration :
    functionPrototype blockStatement 
    ;

argumentList :
    /*empty*/
    | nonEmptyArgList 
    ;

nonEmptyArgList :
    argument 
    | nonEmptyArgList "," argument 
    ;

argument :
    expression 
    | name "=" expression 
    | "_" 
    | name "=" "_" 
    ;

expressionList :
    /*empty*/
    | expression 
    | expressionList "," expression 
    ;

prefixedNonTypeName :
    nonTypeName 
    | dotPrefix nonTypeName 
    ;

dot_name :
    "." /*15P*/ name 
    ;

lvalue :
    prefixedNonTypeName 
    | THIS 
    | lvalue dot_name %prec DOT /*15P*/ 
    | lvalue "[" /*14P*/ expression "]" /*14P*/ 
    | lvalue "[" /*14P*/ expression ":" /*2P*/ expression "]" /*14P*/ 
    ;

expression :
    INTEGER 
    | DOTS 
    | STRING_LITERAL 
    | TRUE 
    | FALSE 
    | THIS 
    | prefixedNonTypeName 
    | expression "[" /*14P*/ expression "]" /*14P*/ 
    | expression "[" /*14P*/ expression ":" /*2P*/ expression "]" /*14P*/ 
    | "{" expressionList optTrailingComma "}" 
    | INVALID 
    | "{" kvList optTrailingComma "}" 
    | "{" kvList "," DOTS optTrailingComma "}" 
    | "(" /*14P*/ expression ")" 
    | "!" expression %prec PREFIX /*13P*/ 
    | "~" expression %prec PREFIX /*13P*/ 
    | "-" /*11L*/ expression %prec PREFIX /*13P*/ 
    | "+" /*11L*/ expression %prec PREFIX /*13P*/ 
    | typeName dot_name %prec DOT /*15P*/ 
    | ERROR "." /*15P*/ name 
    | expression dot_name %prec DOT /*15P*/ 
    | expression "*" /*12L*/ expression 
    | expression "/" /*12L*/ expression 
    | expression "%" /*12L*/ expression 
    | expression "+" /*11L*/ expression 
    | expression "-" /*11L*/ expression 
    | expression "|+|" /*11L*/ expression 
    | expression "|-|" /*11L*/ expression 
    | expression "<<" /*10L*/ expression 
    | expression R_ANGLE_SHIFT /*10L*/ ">" /*6L*/ expression %prec R_ANGLE_SHIFT /*10L*/ 
    | expression "<=" /*6L*/ expression 
    | expression ">=" /*6L*/ expression 
    | expression l_angle expression %prec "<" /*6L*/ 
    | expression ">" /*6L*/ expression 
    | expression "!=" /*5L*/ expression 
    | expression "==" /*5L*/ expression 
    | expression "&" /*9L*/ expression 
    | expression "^" /*8L*/ expression 
    | expression "|" /*7L*/ expression 
    | expression "++" /*11L*/ expression 
    | expression "&&" /*4L*/ expression 
    | expression "||" /*3L*/ expression 
    | expression "?" /*1P*/ expression ":" /*2P*/ expression 
    | expression l_angle realTypeArgumentList r_angle "(" /*14P*/ argumentList ")" 
    | expression "(" /*14P*/ argumentList ")" 
    | namedType "(" /*14P*/ argumentList ")" 
    | "(" /*14P*/ typeRef ")" expression %prec PREFIX /*13P*/ 
    ;

nonBraceExpression :
    INTEGER 
    | STRING_LITERAL 
    | TRUE 
    | FALSE 
    | THIS 
    | prefixedNonTypeName 
    | nonBraceExpression "[" /*14P*/ expression "]" /*14P*/ 
    | nonBraceExpression "[" /*14P*/ expression ":" /*2P*/ expression "]" /*14P*/ 
    | "(" /*14P*/ expression ")" 
    | "!" expression %prec PREFIX /*13P*/ 
    | "~" expression %prec PREFIX /*13P*/ 
    | "-" /*11L*/ expression %prec PREFIX /*13P*/ 
    | "+" /*11L*/ expression %prec PREFIX /*13P*/ 
    | typeName dot_name %prec DOT /*15P*/ 
    | ERROR "." /*15P*/ name 
    | nonBraceExpression dot_name %prec DOT /*15P*/ 
    | nonBraceExpression "*" /*12L*/ expression 
    | nonBraceExpression "/" /*12L*/ expression 
    | nonBraceExpression "%" /*12L*/ expression 
    | nonBraceExpression "+" /*11L*/ expression 
    | nonBraceExpression "-" /*11L*/ expression 
    | nonBraceExpression "|+|" /*11L*/ expression 
    | nonBraceExpression "|-|" /*11L*/ expression 
    | nonBraceExpression "<<" /*10L*/ expression 
    | nonBraceExpression R_ANGLE_SHIFT /*10L*/ ">" /*6L*/ expression %prec R_ANGLE_SHIFT /*10L*/ 
    | nonBraceExpression "<=" /*6L*/ expression 
    | nonBraceExpression ">=" /*6L*/ expression 
    | nonBraceExpression l_angle expression %prec "<" /*6L*/ 
    | nonBraceExpression ">" /*6L*/ expression 
    | nonBraceExpression "!=" /*5L*/ expression 
    | nonBraceExpression "==" /*5L*/ expression 
    | nonBraceExpression "&" /*9L*/ expression 
    | nonBraceExpression "^" /*8L*/ expression 
    | nonBraceExpression "|" /*7L*/ expression 
    | nonBraceExpression "++" /*11L*/ expression 
    | nonBraceExpression "&&" /*4L*/ expression 
    | nonBraceExpression "||" /*3L*/ expression 
    | nonBraceExpression "?" /*1P*/ expression ":" /*2P*/ expression 
    | nonBraceExpression l_angle realTypeArgumentList r_angle "(" /*14P*/ argumentList ")" 
    | nonBraceExpression "(" /*14P*/ argumentList ")" 
    | namedType "(" /*14P*/ argumentList ")" 
    | "(" /*14P*/ typeRef ")" expression %prec PREFIX /*13P*/ 
    ;

intOrStr :
    INTEGER 
    | STRING_LITERAL 
    ;

intList :
    INTEGER 
    | intList "," INTEGER 
    ;

intOrStrList :
    intOrStr 
    | intOrStrList "," intOrStr 
    ;

strList :
    STRING_LITERAL 
    | strList "," STRING_LITERAL 
    ;

l_angle :
    "<" /*6L*/ 
    | L_ANGLE_ARGS /*14P*/ 
    ;

r_angle :
    ">" /*6L*/ 
    | R_ANGLE_SHIFT /*10L*/ 
    ;
fruffy commented 1 year ago

I guess the question is, if and how we should add this to P4C? I can see this being difficult to maintain if there is no other interest. Or it becomes part of the p4-spec instead. It is an intuitive place for it.