Tokens and Precedence
Token Declaration
All terminals must be declared:
%token NUMBER IDENTIFIER STRING_LITERAL
%token PLUS MINUS TIMES DIVIDE
%token IF ELSE WHILE FOR
Token Values
By default, tokens are assigned sequential integer values starting from 256. To specify values:
%token NUMBER 258
%token PLUS 259
%token MINUS 260
Literal Tokens
Single-character tokens can be used directly in rules:
expr: expr '+' expr
| expr '-' expr
| NUMBER
;
The character's ASCII value is the token value.
Precedence and Associativity
Associativity
%left PLUS MINUS /* left-to-right */
%left TIMES DIVIDE /* higher precedence than + - */
%right POWER /* right-to-left */
%nonassoc LT GT EQ /* a < b < c is an error */
Precedence Levels
Declarations later in the file have higher precedence:
%left OR /* lowest */
%left AND
%left EQ NE
%left LT GT LE GE
%left PLUS MINUS
%left TIMES DIVIDE
%right POWER /* highest binary */
%right UMINUS /* unary minus */
Context-Dependent Precedence
Use %prec to override a rule's precedence:
expr: MINUS expr %prec UMINUS { $$ = -$2; }
;
This uses UMINUS precedence instead of MINUS.
Conflict Resolution
Shift/Reduce Conflicts
When the parser can either shift or reduce:
- If the lookahead token has higher precedence than the rule, shift.
- If the rule has higher precedence, reduce.
- If equal precedence, use associativity:
- Left: reduce
- Right: shift
- Nonassoc: error
Example: Dangling Else
%nonassoc LOWER_THAN_ELSE
%nonassoc ELSE
stmt: IF expr stmt %prec LOWER_THAN_ELSE
| IF expr stmt ELSE stmt
;
Reduce/Reduce Conflicts
When two rules can reduce the same input, the first rule in the file wins. This usually indicates a grammar problem.
Token Types
With %union, assign types to tokens:
%union {
int ival;
double dval;
char *str;
}
%token <ival> INTEGER
%token <dval> FLOAT
%token <str> IDENTIFIER STRING