11.2. Attributes in Bison


Getting ready for attributes

If a particular nonterminal will have an attribute, you tell bison about that in the same section where you declare tokens. Line

%type <intval> expr

tells Bison that nonterminal expr has an attribute, and that the attribute uses the intval field of union type YYSTYPE.

You will need to write a %type line for each nonterminal that has an attribute.


Defining the attribute of a nonterminal

Consider production N → α.

The action written after N → α defines the attribute of N in terms of the attributes of the tokens and nonterminals in α, by setting $$ equal to the attribute.

To illustrate, let's write a simple calculator in Bison using the simple expression grammar. It reads an expression and writes the value of the expression.

%token <intval> TOK_NUMBER

%type <intval> expr
%type <intval> term
%type <intval> fact
%%
program : expr
           {
             printf("%d", $1);
           }
        ;

expr : term
         {
           $$ = $1;
         }

     | expr  '+'  term
         {
           $$ = $1 + $3;
         }
     ;

term : fact
         {
           $$ = $1;
         }

     | term  '*'  fact
         {
           $$ = $1 * $3;
         }
     ;

fact : TOK_NUMBER
         {
            $$ = $1;
         }

     | '('  expr  ')'
         {
           $$ = $2;
         }
     ;
%%  

Creating abstract syntax trees.

Imagine that

  1. AST is the type of an abstract syntax tree (that is, a pointer to an ASTNODE),

  2. Field ast of YYSTYPE has type AST,

  3. newLeaf(n) returns a pointer to a leaf node holding integer n,

  4. newOpNode(sym, A, B) returns a pointer to a node labeled by character sym, with subtrees A and B, and

  5. printAST(T) writes tree T.

The following Bison program builds an abstract syntax tree for an expression and prints it.

%token <intval> TOK_NUMBER

%type <ast> expr
%type <ast> term
%type <ast> fact
%%
program : expr
           {
             printAST($1);
           }
        ;

expr : term
         {
           $$ = $1;
         }

     | expr  '+'  term
         {
           $$ = newNode('+', $1, $3);
         }
     ;

term : fact
         {
           $$ = $1;
         }

     | term  '*'  fact
         {
           $$ = newNode('*', $1, $3);
         }
     ;

fact : TOK_NUMBER
         {
            $$ = newLeaf($1);
         }

     | '('  expr  ')'
         {
           $$ = $2;
         }
     ;
%%