1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
.\" This module is believed to contain source code proprietary to AT&T.
.\" Use and redistribution is subject to the Berkeley Software License
.\" Agreement and your Software Agreement with AT&T (Western Electric).
.\"
.\" @(#)ssa 8.1 (Berkeley) 6/8/93
.\"
.\" $FreeBSD$
.SH
Appendix A: A Simple Example
.PP
This example gives the complete Yacc specification for a small desk calculator;
the desk calculator has 26 registers, labeled ``a'' through ``z'', and accepts
arithmetic expressions made up of the operators +, \-, *, /,
% (mod operator), & (bitwise and), | (bitwise or), and assignment.
If an expression at the top level is an assignment, the value is not
printed; otherwise it is.
As in C, an integer that begins with 0 (zero) is assumed to be octal;
otherwise, it is assumed to be decimal.
.PP
As an example of a Yacc specification, the desk calculator
does a reasonable job of showing how precedences and ambiguities
are used, and demonstrating simple error recovery.
The major oversimplifications are that the
lexical analysis phase 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 in by the grammar rules;
This job is probably better done by the lexical analyzer.
.sp
.nf
.ta .5i 1i 1.5i 2i 2.5i
%{
# 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 \'\en\'
| list error \'\en\'
{ yyerrok; }
;
stat : expr
{ printf( "%d\en", $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; }
| expr \'%\' expr
{ $$ = $1 % $3; }
| expr \'&\' expr
{ $$ = $1 & $3; }
| expr \'|\' expr
{ $$ = $1 | $3; }
| \'\-\' expr %prec UMINUS
{ $$ = \- $2; }
| LETTER
{ $$ = regs[$1]; }
| number
;
number : DIGIT
{ $$ = $1; base = ($1==0) ? 8 : 10; }
| number DIGIT
{ $$ = base * $1 + $2; }
;
%% /* start of programs */
yylex() { /* lexical analysis routine */
/* returns LETTER for a lower case letter, yylval = 0 through 25 */
/* return DIGIT for a digit, yylval = 0 through 9 */
/* all other characters are returned immediately */
int c;
while( (c=getchar()) == \' \' ) { /* skip blanks */ }
/* c is now nonblank */
if( islower( c ) ) {
yylval = c \- \'a\';
return ( LETTER );
}
if( isdigit( c ) ) {
yylval = c \- \'0\';
return( DIGIT );
}
return( c );
}
.fi
.bp
|