Role of yylval in lex and yacc

Viewed 6273

I see a lot of examples where some pass the yytext to yylval while others do not. Here is a code for a simple adder in lex and yacc

/* add.l */
digit [0-9]
%%
{digit}+ {sscanf(yytext, "%d", &yylval);
return(INT);
}
\+ return(PLUS);
\n return(NL);
. ;
%%
int yywrap() { return 1; }

and

/* add.y */
/* L = {INT PLUS INT NL} */
%token INT PLUS NL
%%
add: INT PLUS INT NL { printf("%d\n", $1 + $3);}
%%
#include "lex.yy.c"
yyerror(char *s) { printf("%s\n", s); }
main() {
 return yyparse();
}

I see no code like printf(yylval) etc. Why the code sscanf(yytext, "%d", &yylval) exist here. Is yylval used here somehow,what happens if we don't add that line? When do we need to include such a line in lex?

2 Answers

The yylval global variable is used to pass the semantic value associated with a token from the lexer to the parser. The semantic values of symbols are accessed in yacc actions as $1, $2, etc and are set for non-terminals by assigning to $$. Terminals come from the lexer which needs some way of communicating the semantic value to the parser. In a reentrant scanner, yylval generally becomes a reference argument to yylex rather than a global variable, but otherwise serves the same purpose.

In your specific example, the token INT has a semantic value which is the value of the integer read. Since there are no %type/%union declarations in the yacc code, the semantic values just get default int type, which is just fine for holding an integer value.

Taken from here (recommended reading) :

In an ordinary (nonreentrant) parser, the semantic value of the token must be stored into the global variable yylval. When you are using just one data type for semantic values, yylval has that type.

Which means, values associated with a token are stored in that particular variable.

Related