Skip to content

Refine parserStatement grammar in P4 parser#5638

Open
jaehyun1ee wants to merge 1 commit into
p4lang:mainfrom
jaehyun1ee:parser-statement-grammar
Open

Refine parserStatement grammar in P4 parser#5638
jaehyun1ee wants to merge 1 commit into
p4lang:mainfrom
jaehyun1ee:parser-statement-grammar

Conversation

@jaehyun1ee

@jaehyun1ee jaehyun1ee commented May 27, 2026

Copy link
Copy Markdown

This is a follow-up from a p4-spec issue in p4lang/p4-spec#1375.

Previously, parserStatment grammar in the specification was defined as:

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

conditionalStatement
    : IF "(" expression ")" statement
    | IF "(" expression ")" statement ELSE statement
    ;

where the conditionalStatement actually led to ordinary statements (which allow more production than parserStatements) being syntactically included within parserStatement.

A p4-spec PR (p4lang/p4-spec#1415) amends the parserStatement grammar such that it is closed under itself, without a path to statement. This PR is a mirror of it in p4c. In short, the P4 parser is refined as follows:

 parserState
     : optAnnotations STATE name { driver.structure->pushContainerType($3, false); }
-      "{" parserStatements transitionStatement "}" {
+      "{" parserStatOrDeclList transitionStatement "}" {
                   driver.structure->pop();
                   $$ = new IR::ParserState(@3, std::move($3), std::move($1), std::move($6), $7); }
     ;

-parserStatements
-    : %empty                           { $$ = {}; }
-    | parserStatements parserStatement { ($$ = std::move($1)).push_back($2); $$.srcInfo = @1 + @2; }
-    ;
-
 parserStatement
     : assignmentOrMethodCallStatement { $$ = $1; }
     | emptyStatement                  { $$ = $1; }
-    | variableDeclaration             { $$ = $1; }
-    | constantDeclaration             { $$ = $1; }
     | parserBlockStatement            { $$ = $1; }
-    | conditionalStatement            { $$ = $1; }
+    | parserConditionalStatement      { $$ = $1; }
+    ;
+
+parserStatementOrDeclaration
+    : variableDeclaration             { $$ = $1; }
+    | constantDeclaration             { $$ = $1; }
+    | parserStatement                 { $$ = $1; }
+    ;
+
+parserStatOrDeclList
+    : %empty                                            { $$ = {}; }
+    | parserStatOrDeclList parserStatementOrDeclaration { ($$ = std::move($1)).push_back($2);
+                                                          $$.srcInfo = @1 + @2; }
     ;

 parserBlockStatement
-    : optAnnotations "{"    { driver.structure->pushNamespace(@2, false); }
-      parserStatements "}"  { driver.structure->pop();
-                              $$ = new IR::BlockStatement(@1+@5, std::move($1), std::move($4)); }
+    : optAnnotations "{"        { driver.structure->pushNamespace(@2, false); }
+      parserStatOrDeclList "}"  { driver.structure->pop();
+                                  $$ = new IR::BlockStatement(@1+@5, std::move($1), std::move($4)); }
+    ;
+
+parserConditionalStatement
+    : IF "(" expression ")" parserStatement                       %prec THEN
+        { $$ = new IR::IfStatement(@1, $3, $5, nullptr); }
+    | IF "(" expression ")" parserStatement ELSE parserStatement  %prec THEN
+        { $$ = new IR::IfStatement(@1, $3, $5, $7); }
     ;

Now, parserStatement is similar to how statement is defined:

  • parserStatementOrDeclaration and parserStatOrDeclList correspond to statementOrDeclaration and statOrDeclList
  • parserState and parserBlockStatement now has parserStatOrDeclList as its field instead of parserStatements, and parserStatements production is now dropped
  • parserStatement has a new parserConditionalStatement production that is closed under parserStatement
  • parserStatement has a new directApplication production, which was already in the P4 spec grammar, but was omitted in the p4c parser

I've tested it with cmake --build build --target check, where it seems to fail on:

The following tests FAILED:
	255 - bmv2/testdata/p4_16_samples/extern-funcs-bmv2.p4 (Failed)
	551 - bmv2/bmv2_emit_externs (Failed)
	578 - bmv2-ptf/testdata/p4_16_samples/ternary2-bmv2.p4 (Failed)
	944 - ebpf-kernel/testdata/p4_16_samples/action_call_ebpf.p4 (Failed)
	945 - ebpf-kernel/testdata/p4_16_samples/action_call_table_ebpf.p4 (Failed)
	946 - ebpf-kernel/testdata/p4_16_samples/advance_ebpf.p4 (Failed)
	947 - ebpf-kernel/testdata/p4_16_samples/bool_ebpf.p4 (Failed)
	948 - ebpf-kernel/testdata/p4_16_samples/count_add_ebpf.p4 (Failed)
	949 - ebpf-kernel/testdata/p4_16_samples/count_ebpf.p4 (Failed)
	950 - ebpf-kernel/testdata/p4_16_samples/hit_ebpf.p4 (Failed)
	951 - ebpf-kernel/testdata/p4_16_samples/init_ebpf.p4 (Failed)
	952 - ebpf-kernel/testdata/p4_16_samples/issue2791_ebpf.p4 (Failed)
	953 - ebpf-kernel/testdata/p4_16_samples/issue2793_ebpf.p4 (Failed)
	954 - ebpf-kernel/testdata/p4_16_samples/issue2797_ebpf.p4 (Failed)
	955 - ebpf-kernel/testdata/p4_16_samples/issue2816-1_ebpf.p4 (Failed)
	956 - ebpf-kernel/testdata/p4_16_samples/issue2816_ebpf.p4 (Failed)
	957 - ebpf-kernel/testdata/p4_16_samples/issue870_ebpf.p4 (Failed)
	958 - ebpf-kernel/testdata/p4_16_samples/key-issue-1020_ebpf.p4 (Failed)
	959 - ebpf-kernel/testdata/p4_16_samples/key_ebpf.p4 (Failed)
	960 - ebpf-kernel/testdata/p4_16_samples/length_ebpf.p4 (Failed)
	961 - ebpf-kernel/testdata/p4_16_samples/lpm_ebpf.p4 (Failed)
	962 - ebpf-kernel/testdata/p4_16_samples/stack_ebpf.p4 (Failed)
	963 - ebpf-kernel/testdata/p4_16_samples/switch_ebpf.p4 (Failed)
	964 - ebpf-kernel/testdata/p4_16_samples/ternary_ebpf.p4 (Failed)
	965 - ebpf-kernel/testdata/p4_16_samples/test_ebpf.p4 (Failed)
	966 - ebpf-kernel/testdata/p4_16_samples/two_ebpf.p4 (Failed)
	967 - ebpf-kernel/testdata/p4_16_samples/valid_ebpf.p4 (Failed)
	968 - ebpf-kernel/testdata/p4_16_samples/value_set_ebpf.p4 (Failed)
	969 - ebpf-kernel/testdata/p4_16_samples/verify_ebpf.p4 (Failed)
	970 - ebpf-kernel/testdata/p4_16_samples/xdp_dec_ttl_ebpf-kernel.p4 (Failed)
	971 - ebpf-kernel/testdata/p4_16_samples/xdp_vlan_push_pop_ebpf-kernel.p4 (Failed)
	972 - ebpf-kernel/testdata/p4_16_samples/ebpf_conntrack_extern.p4 (Failed)
	973 - ebpf-kernel/testdata/p4_16_samples/ebpf_checksum_extern.p4 (Failed)

However, these appear to be environmental issues unrelated to this change: the bmv2 failures seem to stem from local linking issues/PTF version mismatches, and the ebpf-kernel failures are likely due to bpftool execution issues inside my local Docker container.

As I am still familiarizing myself with the p4c development environment, please let me know if there are specific testing workflows, target-specific checks, or CI behaviors I should look out for. Any guidance or feedback would be highly appreciated!

Signed-off-by: jaehyun1ee <99jaehyunlee@kaist.ac.kr>
@jafingerhut

Copy link
Copy Markdown
Contributor

It is perfectly acceptable to use Github CI checks for such PRs. I see all of them passing, so that is good. Setting up a local development environment so that it passes tests for all P4 targets can be painstaking and error-prone.

@jafingerhut jafingerhut left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These grammar changes look consistent with the related p4-spec issue. LGTM

@ChrisDodd

Copy link
Copy Markdown
Contributor

IMO it is better to make the parser more permissive (and simpler) allowing all constructs orthogonally in all contexts, and then in the ValidateParsedProgram pass have checks for statements in a context where they are not allowed.

That both makes the parser simpler and easier to maintain, AND give better error messages (something like "switch statements not allowed in parser states" rather than a generic "syntax error" with only an indication of which token triggered the error).

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

Successfully merging this pull request may close these issues.

3 participants