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