This example comes from <<lex & YACC >> Second Edition
LEX is responsible for lexical analysis, parsing one token at a time.
First, the type and value of token
Token has a type, in the calculator example, including the following types:
1), number a string of numbers
2), name
3), ' + ', '-', ' * ', '/' and other symbols
At the same time token has a value, different types of tokens, the meaning of the value is not the same, for example,
' 1000 ': type is number, value is 1000
' ABC ': Type is NAME, value is ' abc '
After LEX resolves a token, it saves the token value in the Yylval variable and returns the type to YACC.
To be able to save different types of values, Yylval is defined as a union
%union {
double dval;
struct Symtab *symp;
}
Where Dval holds the value of type number, SYMP holds the value of the NAME type.
To save a value of the NAME type, a structure is defined
struct Symtab {
char *name;
Double (*funcptr) ();
Double value;
Where name records the name of the "symbol", and value is used to save the calculation result, which is described later in this article.
The NAME type of token, also known as the "symbol", is the same as the variables defined when we write the program.
Therefore, when Lex encounters a number string, it saves the value of the string to Yylval's Dval and returns the number type. When a string is encountered, a SYMTAB structure is generated based on the string name, the name is saved, and the address of the structure is saved to the symp of Yylval, and the name type is returned. When a symbol such as ' + ', '-' is encountered, the ASCII code value of the symbol is returned.
Second, the calculation in YACC
In the "production" or "Rules" section, through the way of $, $, $ $, the value of the corresponding token can be obtained, access to these variables is actually access to yylval. At this point, YACC already knows the type of token, so for the number type, the token value is Yylval.dval, and for the NAME type, the token value is Yylval.symp
For example:
Statement: NAME ' = ' expression {$1->value = $ $; printf ("(%s) = (%g) \ n", $1->name, $1->value); }<br>
expression:
| Number {$$ = $; }
| NAME
For number, it corresponds to the value
For name, $1->name is the symbol name
Types and values of non-terminating symbols
%type <dval> Expression
Third, Appendix: source Code
Symbol.h
#define NSYMS 1024x768/ * Maximum number of symbols */
struct Symtab {
char *name;
Double (*funcptr) ();
Double value;
} SYMTAB[NSYMS];
struct Symtab *symlook (char* s);
Symbol.c
#include "symbol.h"
#include <string.h>
#include <unistd.h>
#include <stdio.h>
# Include <stdlib.h>
struct Symtab *symlook (char* s)
{
char *p;
struct Symtab *sp;
for (sp = symtab; SP < &symtab[NSYMS]; sp++) {/
* is it already here *
/if (Sp->name &&!strcmp ( Sp->name, s) {
printf ("Found symbol: (%s) \ n", sp->name);
return sp;
}
/* Is it FREE * *
if (!sp->name) {
sp->name = StrDup (s);
printf ("Add Symbol: (%s) \ n", s);
return sp;
}
/* Otherwise continue to next
*
/} yyerror ("Too many Symbols");
Exit (1); /* Cannot continue */
}/* Symlook */
Calc.l
%{
#include "y.tab.h"
#include "symbol.h"
#include <math.h>
%}
percent
([0-9]+| ( [0-9]*\. [0-9]+] ([ee][-+]?[ 0-9]+)?) {
Yylval.dval = atof (yytext);
return number;
}
[\ t] ; /* Ignore white space */
[a-za-z][a-za-z0-9]* {/ * return symbol pointer */
struct Symtab *sp = Symloo K (yytext);
Yylval.symp = SP;
return NAME;
}
" $ "{return 0;}
\ n |
. return yytext[0];
%%
Calc.y
%{#include <string.h> #include <math.h> #include "symbol.h"%}%union {double dval;
struct Symtab *symp; }%token <symp> NAME%token <dval> number%left '-' + '%left ' * '/'%nonassoc uminus%type <dval> ; Expression statement_list:statement ' \ n ' |
Statement_list statement ' \ n '; Statement:name ' = ' expression {$1->value = $ $; printf ("(%s) = (%g) \ n", $1->name, $1->value); }
|
Expression {printf ("=%g\n", $ $);}
;
Expression:expression ' + ' expression {$$ = $ + $;} |
Expression '-' expression {$$ = $-$;} |
Expression ' * ' expression {$$ = $ * $;} |
Expression '/' expression {if ($ = = 0.0) Yyerror ("Divide by Zero");
else $$ = $/$; }
|
'-' expression%prec uminus {$$ =-$2;} |
' (' expression ') ' {$$ = $;} | Number {$$ = $;
} |
NAME {$$ = $1->value;} |
NAME ' (' expression ') ' {if ($1->funcptr) $$ = ($1->FUNCPTR) ($ $);
else {printf ("%s not a function\n", $1->name);
$$ = 0.0;
}
}
; %%