5.2 Precedence rules

Precedence rules are used to disambiguate ambiguous parses in the grammar. They can be used to disambiguate an otherwise ambiguous grammar. There are two precedence mechanisms. The first is to assign precedences and associativities to terminals. This is done with a precedence rule which specifies an associativity followed by a list of non-terminals followed by a semicolon. The associativity may be one of %left, %right or %nonassoc. An example of a precedence rule is:

%left TOK_MUL TOK_ADD ;

All tokens specified in this way are given priorities from highest (most prefered) to lowest (lest prefered) in the order they are encountered in the spec file. The tokens are also assigned the designated associativity. Any production making use of these terminals inherits their associativity and precedence.

It is also possible to directly assign a precedence and an associativity to a production. This is done by prefixing a right hand side of a production with a %prec operator. For example, the following grammar has a well known ambiguity:

Expr -> e
    ;
Stmt -> IF Expr THEN Stmt ELSE Stmt
    | IF Expr THEN Stmt 
    | s
    ;

For example IF e THEN s ELSE IF e THEN s ELSE s can be parsed either as IF e THEN s ELSE [IF e THEN s ELSE s]} or IF e THEN s ELSE [IF e THEN s] ELSE s. We can specify that the first Stmt production has higher precedence than the second by specifying two dummy precedences and referencing them from the right hand sides:

%nonassoc LONG SHORT ;

Stmt -> %prec(LONG) IF Expr THEN Stmt ELSE Stmt
    | %prec(SHORT) IF Expr THEN Stmt 
    | s
    ;

Expr -> e
    ;

The resulting parser has no ambiguities and prefers matching the longer statement whenever possible (binding the else statement to the nearest if statement). See exampmles/test3.py for a complete example.

See the PyGgy Home Page.