Programming Utilities Guide

A Simple Example

The following code sample shows the complete yacc applications for a small desk calculator. The calculator has 26 registers labeled a through z and accepts arithmetic expressions made up of the operators +, -, *, /, %, &, |, and the assignment operators.

If an expression at the top level is an assignment, only the assignment is made; otherwise, the expression is printed. As in the C language, an integer that begins with 0 is assumed to be octal; otherwise, it is assumed to be decimal.

As an example of a yacc specification, the desk calculator shows how precedence and ambiguities are used and demonstrates simple recovery. The major oversimplifications are that the lexical analyzer is much simpler than for most applications, and the output is produced immediately, line by line.

Note the way that decimal and octal integers are read by grammar rules. This job can also be performed by the lexical analyzer.

%{ 
# include <stdio.h> 
# include <ctype.h> 

int regs[26]; 
int base; 
%} 

%start list 
%token DIGIT LETTER 
%left '|' 
%left '&' 
%left '+' '-' 
%left '*' '/' %' 
%left UMINUS		      /* supplies precedence for unary minus */ 

%%			         		/* beginning of rules section */ 

list	    	:		     	/* empty */ 
        		| list stat '\n' 
        		| list error '\n' 
        		{ 
           			yyerrok; 
        		}
        		; 
stat	    	: expr 
        		{ 
           			(void) printf( "%d\n", $1 ); 
        		} 
         	| LETTER '=' expr 
        		{ 
           			regs[$1] = $3; 
        		} 
        		; 
expr	    	: '(' expr ')' 
         	{ 
            		$$ = $2; 
        		} 
        		| expr '+' expr 
        		{ 
           			$$ = $1 + $3; 
        		} 
        		| expr '-' expr 
        		{ 
           			$$ = $1 - $3; 
        		{ 
        		| expr '*' expr 
        		{ 
           			$$ = $1 * $3; 
        		} 
         	| expr '/' expr 
        		{ 
           			$$ = $1 / $3; 
      		} 
         	| exp '%' expr 
         	{
           			$$ = $1 % $3; 
      		} 
         	| expr '&' expr 
         	{ 
            		$$ = $1 & $3; 
      		} 
         	| expr '|' expr 
         	{ 
            		$$ = $1 | $3; 
       	 	} 
         	| '-' expr %prec UMINUS 
         	{
           			$$ = -$2; 
         	} 
         	| LETTER 
       	 	{ 
             	$$ = reg[$1]; 
        		} 
       	 	| number 
       	 	; 
number   	: DIGIT 
       	 	{ 
             	$$ = $1; base = ($1= =0) ? 8 ; 10; 
       	 	} 
       	 	| number DIGIT 
       	 	{ 
           			$$ = base * $1 + $2; 
       	 	} 
       	 	; 

%% 		      	/* beginning of subroutines section */ 
int yylex( )		/* lexical analysis routine */ 
{				      /* return LETTER for lowercase letter, */ 
            		/* yylval = 0 through 25 returns DIGIT */ 
             		/* for digit, yylval = 0 through 9 */ 
        			   /* all other characters are returned immediately */ 
   int c;             					/*skip blanks*/ 
   while ((c = getchar()) = = ' ') 
     		; 
           					/* c is now nonblank */ 

   if (islower(c)) {
    		yylval = c - 'a'; 
    		return (LETTER); 
  	} 
   if (isdigit(c)) {
    		yylval = c - '0'; 
    		return (DIGIT); 
   } 
   return (c);  
}