12 07 switch statement
The switch statement can only be used within control blocks.
switchStatement
: SWITCH "(" expression ")" "{" switchCases "}"
;
switchCases
: /* empty */
| switchCases switchCase
;
switchCase
: switchLabel ":" blockStatement
| switchLabel ":" // fall-through
;
switchLabel
: DEFAULT
| nonBraceExpression
;
nonBraceExpression
: INTEGER
| STRING_LITERAL
| TRUE
| FALSE
| THIS
| prefixedNonTypeName
| nonBraceExpression "[" expression "]"
| nonBraceExpression "[" expression ":" expression "]"
| nonBraceExpression "[" expression "+" ":" expression "]"
| "(" expression ")"
| "!" expression %prec PREFIX
| "~" expression %prec PREFIX
| "-" expression %prec PREFIX
| "+" expression %prec PREFIX
| typeName "." member
| ERROR "." member
| nonBraceExpression "." member
| nonBraceExpression "*" expression
| nonBraceExpression "/" expression
| nonBraceExpression "%" expression
| nonBraceExpression "+" expression
| nonBraceExpression "-" expression
| nonBraceExpression "|+|" expression
| nonBraceExpression "|-|" expression
| nonBraceExpression "<<" expression
| nonBraceExpression ">>" expression
| nonBraceExpression "<=" expression
| nonBraceExpression ">=" expression
| nonBraceExpression "<" expression
| nonBraceExpression ">" expression
| nonBraceExpression "!=" expression
| nonBraceExpression "==" expression
| nonBraceExpression "&" expression
| nonBraceExpression "^" expression
| nonBraceExpression "|" expression
| nonBraceExpression "++" expression
| nonBraceExpression "&&" expression
| nonBraceExpression "||" expression
| nonBraceExpression "?" expression ":" expression
| nonBraceExpression "<" realTypeArgumentList ">" "(" argumentList ")"
| nonBraceExpression "(" argumentList ")"
| namedType "(" argumentList ")"
| "(" typeRef ")" expression
;
The nonBraceExpression is the same as expression as defined in
Section Expressions, except it does not include any cases that can
begin with a left brace { character, to avoid syntactic ambiguity with
a block statement.
There are two kinds of switch expressions allowed, described
separately in the following two subsections.
Switch statement with action_run expression
For this variant of switch statement, the expression must be of the
form t.apply().action_run, where t is the name of a table (see
Section Match-action unit invocation). All switch labels must be names of
actions of the table t, or default.
switch (t.apply().action_run) {
action1: // fall-through to action2:
action2: { /* body omitted */ }
action3: { /* body omitted */ } // no fall-through from action2 to action3 labels
default: { /* body omitted */ }
}
Note that the default label of the switch statement is used to match
on the kind of action executed, no matter whether there was a table hit
or miss. The default label does not indicate that the table missed and
the default_action was executed.
Switch statement with integer or enumerated type expression
For this variant of switch statement, the expression must evaluate to
a result with one of these types:
bit<W>int<W>enum, either with or without an underlying representation specifiederror
All switch labels must be expressions with compile-time known values,
and must have a type that can be implicitly cast to the type of the
switch expression (see Section Implicit casts). Switch
labels must not begin with a left brace character {, to avoid
ambiguity with a block statement.
// Assume the expression hdr.ethernet.etherType has type bit<16>.
switch (hdr.ethernet.etherType) {
0x86dd: { /* body omitted */ }
0x0800: // fall-through to the next body
0x0802: { /* body omitted */ }
0xcafe: { /* body omitted */ }
default: { /* body omitted */ }
}
Notes common to all switch statements
It is a compile-time error if two labels of a switch statement equal
each other. The switch label values need not include all possible values
of the switch expression. It is optional to have a switch case with
the default label, but if one is present, it must be the last one in
the switch statement.
If a switch label is not followed by a block statement, it falls through
to the next label. However, if a block statement is present, it does not
fall through. Note that this is different from C-style switch
statements, where a break is needed to prevent fall-through. If the
last switch label is not followed by a block statement, the behavior is
the same as if the last switch label were followed by an empty block
statement { }.
When a switch statement is executed, first the switch expression is
evaluated, and any side effects from evaluating this expression are
visible to any switch case that is executed. Among switch labels that
are not default, at most one of them can equal the value of the switch
expression. If one is equal, that switch case is executed.
If no labels are equal to the switch expression, then:
- if there is a
defaultlabel, the case with thedefaultlabel is executed. - if there is no
defaultlabel, then no switch case is executed, and execution continues after the end of theswitchstatement, with no side effects (except any that were caused by evaluating theswitchexpression).
See “Implementing generalized P4_16 switch statements” GeneralizedSwitchStatements for possible techniques that one might use to implement generalized switch statements.