doc: modernize the examples

* doc/bison.texi: Prefer 'fun' to 'fnct'.
Reduce local variable scopes.
Prefer strdup to malloc + strcpy.
Avoid gratuitous casts.
Use simpler names (e.g., 'name' instead of 'fname').
Avoid uses of 0 for NULL.
Avoid using NULL when possible (e.g., 'p' instead of 'p != NULL').
Prefer union names to casts (e.g. 'yylval.VAR = s' instead of
'*((symrec**) &yylval) = s').
Give arguments a name in fun declarations.
Use our typedefs instead of duplicating them (func_t).
Stop promoting an explicit $$ = $1;, it should be implicit (Bison
might be able to eliminate useless chain rules).
Help a bit Texinfo by making smaller groups.
Rely on the C compiler to call function pointers (prefer
'$1->value.fun ($3)' to (*($1->value.fnctptr))($3)').
This commit is contained in:
Akim Demaille
2019-02-10 15:14:24 +01:00
parent 40fc688765
commit 8b2d233283

View File

@@ -1543,7 +1543,8 @@ The source code for this calculator is named @file{rpcalc.y}. The
@subsection Declarations for @code{rpcalc} @subsection Declarations for @code{rpcalc}
Here are the C and Bison declarations for the Reverse Polish Notation Here are the C and Bison declarations for the Reverse Polish Notation
calculator. As in C, comments are placed between @samp{/*@dots{}*/}. calculator. As in C, comments are placed between @samp{/*@dots{}*/} or
after @samp{//}.
@comment file: rpcalc.y @comment file: rpcalc.y
@example @example
@@ -1618,7 +1619,7 @@ line:
@group @group
exp: exp:
NUM @{ $$ = $1; @} NUM
| exp exp '+' @{ $$ = $1 + $2; @} | exp exp '+' @{ $$ = $1 + $2; @}
| exp exp '-' @{ $$ = $1 - $2; @} | exp exp '-' @{ $$ = $1 - $2; @}
| exp exp '*' @{ $$ = $1 * $2; @} | exp exp '*' @{ $$ = $1 * $2; @}
@@ -1720,9 +1721,10 @@ value of the user's input line, that value is no longer needed.
@subsubsection Explanation of @code{expr} @subsubsection Explanation of @code{expr}
The @code{exp} grouping has several rules, one for each kind of expression. The @code{exp} grouping has several rules, one for each kind of expression.
The first rule handles the simplest expressions: those that are just numbers. The first rule handles the simplest expressions: those that are just
The second handles an addition-expression, which looks like two expressions numbers. The second handles an addition-expression, which looks like two
followed by a plus-sign. The third handles subtraction, and so on. expressions followed by a plus-sign. The third handles subtraction, and so
on.
@example @example
exp: exp:
@@ -1737,9 +1739,9 @@ We have used @samp{|} to join all the rules for @code{exp}, but we could
equally well have written them separately: equally well have written them separately:
@example @example
exp: NUM ; exp: NUM;
exp: exp exp '+' @{ $$ = $1 + $2; @}; exp: exp exp '+' @{ $$ = $1 + $2; @};
exp: exp exp '-' @{ $$ = $1 - $2; @}; exp: exp exp '-' @{ $$ = $1 - $2; @};
@dots{} @dots{}
@end example @end example
@@ -1748,17 +1750,21 @@ terms of the value of its parts. For example, in the rule for addition,
@code{$1} refers to the first component @code{exp} and @code{$2} refers to @code{$1} refers to the first component @code{exp} and @code{$2} refers to
the second one. The third component, @code{'+'}, has no meaningful the second one. The third component, @code{'+'}, has no meaningful
associated semantic value, but if it had one you could refer to it as associated semantic value, but if it had one you could refer to it as
@code{$3}. When @code{yyparse} recognizes a sum expression using this @code{$3}. The first rule relies on the implicit default action: @samp{@{
rule, the sum of the two subexpressions' values is produced as the value of $$ = $1; @}}.
the entire expression. @xref{Actions}.
You don't have to give an action for every rule. When a rule has no
action, Bison by default copies the value of @code{$1} into @code{$$}.
This is what happens in the first rule (the one that uses @code{NUM}).
The formatting shown here is the recommended convention, but Bison does When @code{yyparse} recognizes a sum expression using this rule, the sum of
not require it. You can add or change white space as much as you wish. the two subexpressions' values is produced as the value of the entire
For example, this: expression. @xref{Actions}.
You don't have to give an action for every rule. When a rule has no action,
Bison by default copies the value of @code{$1} into @code{$$}. This is what
happens in the first rule (the one that uses @code{NUM}).
The formatting shown here is the recommended convention, but Bison does not
require it. You can add or change white space as much as you wish. For
example, this:
@example @example
exp: NUM | exp exp '+' @{$$ = $1 + $2; @} | @dots{} ; exp: NUM | exp exp '+' @{$$ = $1 + $2; @} | @dots{} ;
@@ -1831,11 +1837,10 @@ Here is the code for the lexical analyzer:
int int
yylex (void) yylex (void)
@{ @{
int c; int c = getchar ();
/* Skip white space. */ /* Skip white space. */
while ((c = getchar ()) == ' ' || c == '\t') while (c == ' ' || c == '\t')
continue; c = getchar ();
@end group @end group
@group @group
/* Process numbers. */ /* Process numbers. */
@@ -1848,10 +1853,11 @@ yylex (void)
@end group @end group
@group @group
/* Return end-of-input. */ /* Return end-of-input. */
if (c == EOF) else if (c == EOF)
return 0; return 0;
/* Return a single char. */ /* Return a single char. */
return c; else
return c;
@} @}
@end group @end group
@end example @end example
@@ -2032,7 +2038,7 @@ line:
@group @group
exp: exp:
NUM @{ $$ = $1; @} NUM
| exp '+' exp @{ $$ = $1 + $3; @} | exp '+' exp @{ $$ = $1 + $3; @}
| exp '-' exp @{ $$ = $1 - $3; @} | exp '-' exp @{ $$ = $1 - $3; @}
| exp '*' exp @{ $$ = $1 * $3; @} | exp '*' exp @{ $$ = $1 * $3; @}
@@ -2212,7 +2218,7 @@ line:
@group @group
exp: exp:
NUM @{ $$ = $1; @} NUM
| exp '+' exp @{ $$ = $1 + $3; @} | exp '+' exp @{ $$ = $1 + $3; @}
| exp '-' exp @{ $$ = $1 - $3; @} | exp '-' exp @{ $$ = $1 - $3; @}
| exp '*' exp @{ $$ = $1 * $3; @} | exp '*' exp @{ $$ = $1 * $3; @}
@@ -2417,8 +2423,8 @@ Here are the C and Bison declarations for the multi-function calculator.
@end group @end group
%define api.value.type union /* Generate YYSTYPE from these types: */ %define api.value.type union /* Generate YYSTYPE from these types: */
%token <double> NUM /* Simple double precision number. */ %token <double> NUM /* Double precision number. */
%token <symrec*> VAR FNCT /* Symbol table pointer: variable and function. */ %token <symrec*> VAR FUN /* Symbol table pointer: variable/function. */
%type <double> exp %type <double> exp
@group @group
@@ -2441,7 +2447,7 @@ store these values.
Since values can now have various types, it is necessary to associate a type Since values can now have various types, it is necessary to associate a type
with each grammar symbol whose semantic value is used. These symbols are with each grammar symbol whose semantic value is used. These symbols are
@code{NUM}, @code{VAR}, @code{FNCT}, and @code{exp}. Their declarations are @code{NUM}, @code{VAR}, @code{FUN}, and @code{exp}. Their declarations are
augmented with their data type (placed between angle brackets). For augmented with their data type (placed between angle brackets). For
instance, values of @code{NUM} are stored in @code{double}. instance, values of @code{NUM} are stored in @code{double}.
@@ -2457,7 +2463,7 @@ declared explicitly so we can specify its value type. @xref{Type Decl,
Here are the grammar rules for the multi-function calculator. Here are the grammar rules for the multi-function calculator.
Most of them are copied directly from @code{calc}; three rules, Most of them are copied directly from @code{calc}; three rules,
those which mention @code{VAR} or @code{FNCT}, are new. those which mention @code{VAR} or @code{FUN}, are new.
@comment file: mfcalc.y: 3 @comment file: mfcalc.y: 3
@example @example
@@ -2479,10 +2485,10 @@ line:
@group @group
exp: exp:
NUM @{ $$ = $1; @} NUM
| VAR @{ $$ = $1->value.var; @} | VAR @{ $$ = $1->value.var; @}
| VAR '=' exp @{ $$ = $3; $1->value.var = $3; @} | VAR '=' exp @{ $$ = $3; $1->value.var = $3; @}
| FNCT '(' exp ')' @{ $$ = (*($1->value.fnctptr))($3); @} | FUN '(' exp ')' @{ $$ = $1->value.fun ($3); @}
| exp '+' exp @{ $$ = $1 + $3; @} | exp '+' exp @{ $$ = $1 + $3; @}
| exp '-' exp @{ $$ = $1 - $3; @} | exp '-' exp @{ $$ = $1 - $3; @}
| exp '*' exp @{ $$ = $1 * $3; @} | exp '*' exp @{ $$ = $1 * $3; @}
@@ -2513,7 +2519,7 @@ provides for either functions or variables to be placed in the table.
@example @example
@group @group
/* Function type. */ /* Function type. */
typedef double (*func_t) (double); typedef double (func_t) (double);
@end group @end group
@group @group
@@ -2521,11 +2527,11 @@ typedef double (*func_t) (double);
struct symrec struct symrec
@{ @{
char *name; /* name of symbol */ char *name; /* name of symbol */
int type; /* type of symbol: either VAR or FNCT */ int type; /* type of symbol: either VAR or FUN */
union union
@{ @{
double var; /* value of a VAR */ double var; /* value of a VAR */
func_t fnctptr; /* value of a FNCT */ func_t *fun; /* value of a FUN */
@} value; @} value;
struct symrec *next; /* link field */ struct symrec *next; /* link field */
@}; @};
@@ -2537,8 +2543,8 @@ typedef struct symrec symrec;
/* The symbol table: a chain of 'struct symrec'. */ /* The symbol table: a chain of 'struct symrec'. */
extern symrec *sym_table; extern symrec *sym_table;
symrec *putsym (char const *, int); symrec *putsym (char const *name, int sym_type);
symrec *getsym (char const *); symrec *getsym (char const *name);
@end group @end group
@end example @end example
@@ -2550,13 +2556,13 @@ the symbol table:
@group @group
struct init struct init
@{ @{
char const *fname; char const *name;
double (*fnct) (double); func_t *fun;
@}; @};
@end group @end group
@group @group
struct init const arith_fncts[] = struct init const arith_funs[] =
@{ @{
@{ "atan", atan @}, @{ "atan", atan @},
@{ "cos", cos @}, @{ "cos", cos @},
@@ -2575,15 +2581,15 @@ symrec *sym_table;
@group @group
/* Put arithmetic functions in table. */ /* Put arithmetic functions in table. */
static static void
void
init_table (void) init_table (void)
@end group
@group
@{ @{
int i; for (int i = 0; arith_funs[i].name; i++)
for (i = 0; arith_fncts[i].fname != 0; i++)
@{ @{
symrec *ptr = putsym (arith_fncts[i].fname, FNCT); symrec *ptr = putsym (arith_funs[i].name, FUN);
ptr->value.fnctptr = arith_fncts[i].fnct; ptr->value.fun = arith_funs[i].fun;
@} @}
@} @}
@end group @end group
@@ -2594,7 +2600,7 @@ files, you can add additional functions to the calculator.
Two important functions allow look-up and installation of symbols in the Two important functions allow look-up and installation of symbols in the
symbol table. The function @code{putsym} is passed a name and the type symbol table. The function @code{putsym} is passed a name and the type
(@code{VAR} or @code{FNCT}) of the object to be installed. The object is (@code{VAR} or @code{FUN}) of the object to be installed. The object is
linked to the front of the list, and a pointer to the object is returned. linked to the front of the list, and a pointer to the object is returned.
The function @code{getsym} is passed the name of the symbol to look up. If The function @code{getsym} is passed the name of the symbol to look up. If
found, a pointer to that symbol is returned; otherwise zero is returned. found, a pointer to that symbol is returned; otherwise zero is returned.
@@ -2606,29 +2612,26 @@ found, a pointer to that symbol is returned; otherwise zero is returned.
@group @group
symrec * symrec *
putsym (char const *sym_name, int sym_type) putsym (char const *name, int sym_type)
@{ @{
symrec *ptr = (symrec *) malloc (sizeof (symrec)); symrec *res = (symrec *) malloc (sizeof (symrec));
ptr->name = (char *) malloc (strlen (sym_name) + 1); res->name = strdup (name);
strcpy (ptr->name,sym_name); res->type = sym_type;
ptr->type = sym_type; res->value.var = 0; /* Set value to 0 even if fun. */
ptr->value.var = 0; /* Set value to 0 even if fctn. */ res->next = sym_table;
ptr->next = (struct symrec *)sym_table; sym_table = res;
sym_table = ptr; return res;
return ptr;
@} @}
@end group @end group
@group @group
symrec * symrec *
getsym (char const *sym_name) getsym (char const *name)
@{ @{
symrec *ptr; for (symrec *p = sym_table; p; p = p->next)
for (ptr = sym_table; ptr != (symrec *) 0; if (strcmp (p->name, name) == 0)
ptr = (symrec *)ptr->next) return p;
if (strcmp (ptr->name, sym_name) == 0) return NULL;
return ptr;
return 0;
@} @}
@end group @end group
@end example @end example
@@ -2643,7 +2646,7 @@ functions depending on what the symbol table says about them.
The string is passed to @code{getsym} for look up in the symbol table. If The string is passed to @code{getsym} for look up in the symbol table. If
the name appears in the table, a pointer to its location and its type the name appears in the table, a pointer to its location and its type
(@code{VAR} or @code{FNCT}) is returned to @code{yyparse}. If it is not (@code{VAR} or @code{FUN}) is returned to @code{yyparse}. If it is not
already in the table, then it is installed as a @code{VAR} using already in the table, then it is installed as a @code{VAR} using
@code{putsym}. Again, a pointer and its type (which must be @code{VAR}) is @code{putsym}. Again, a pointer and its type (which must be @code{VAR}) is
returned to @code{yyparse}. returned to @code{yyparse}.
@@ -2694,13 +2697,11 @@ Bison generated a definition of @code{YYSTYPE} with a member named
for a 40-character symbol name. */ for a 40-character symbol name. */
static size_t length = 40; static size_t length = 40;
static char *symbuf = 0; static char *symbuf = 0;
symrec *s;
int i;
@end group @end group
if (!symbuf) if (!symbuf)
symbuf = (char *) malloc (length + 1); symbuf = malloc (length + 1);
i = 0; int i = 0;
do do
@group @group
@{ @{
@@ -2708,7 +2709,7 @@ Bison generated a definition of @code{YYSTYPE} with a member named
if (i == length) if (i == length)
@{ @{
length *= 2; length *= 2;
symbuf = (char *) realloc (symbuf, length + 1); symbuf = realloc (symbuf, length + 1);
@} @}
/* Add this character to the buffer. */ /* Add this character to the buffer. */
symbuf[i++] = c; symbuf[i++] = c;
@@ -2724,10 +2725,10 @@ Bison generated a definition of @code{YYSTYPE} with a member named
@end group @end group
@group @group
s = getsym (symbuf); symrec *s = getsym (symbuf);
if (s == 0) if (!s)
s = putsym (symbuf, VAR); s = putsym (symbuf, VAR);
*((symrec**) &yylval) = s; yylval.VAR = s; /* or yylval.FUN = s. */
return s->type; return s->type;
@} @}
@@ -2748,22 +2749,22 @@ on user demand (@xref{Tracing, , Tracing Your Parser}, for details):
@example @example
@group @group
/* Called by yyparse on error. */ /* Called by yyparse on error. */
void void yyerror (char const *s)
yyerror (char const *s)
@{ @{
fprintf (stderr, "%s\n", s); fprintf (stderr, "%s\n", s);
@} @}
@end group @end group
@group @group
int int main (int argc, char const* argv[])
main (int argc, char const* argv[]) @end group
@group
@{ @{
int i;
/* Enable parse traces on option -p. */ /* Enable parse traces on option -p. */
for (i = 1; i < argc; ++i) if (argc == 2 && strcmp(argv[1], "-p") == 0)
if (!strcmp(argv[i], "-p")) yydebug = 1;
yydebug = 1; @end group
@group
init_table (); init_table ();
return yyparse (); return yyparse ();
@} @}
@@ -7011,9 +7012,9 @@ assuming that the characters of the token are stored in
characters like @samp{"} that require escaping. characters like @samp{"} that require escaping.
@example @example
for (i = 0; i < YYNTOKENS; i++) for (int i = 0; i < YYNTOKENS; i++)
@{ @{
if (yytname[i] != 0 if (yytname[i]
&& yytname[i][0] == '"' && yytname[i][0] == '"'
&& ! strncmp (yytname[i] + 1, token_buffer, && ! strncmp (yytname[i] + 1, token_buffer,
strlen (token_buffer)) strlen (token_buffer))
@@ -10002,7 +10003,7 @@ prologue:
/* Formatting semantic values. */ /* Formatting semantic values. */
%printer @{ fprintf (yyo, "%s", $$->name); @} VAR; %printer @{ fprintf (yyo, "%s", $$->name); @} VAR;
%printer @{ fprintf (yyo, "%s()", $$->name); @} FNCT; %printer @{ fprintf (yyo, "%s()", $$->name); @} FUN;
%printer @{ fprintf (yyo, "%g", $$); @} <double>; %printer @{ fprintf (yyo, "%g", $$); @} <double>;
@end example @end example
@@ -10015,7 +10016,7 @@ ill-named) @code{%verbose} directive.
The set of @code{%printer} directives demonstrates how to format the The set of @code{%printer} directives demonstrates how to format the
semantic value in the traces. Note that the specification can be done semantic value in the traces. Note that the specification can be done
either on the symbol type (e.g., @code{VAR} or @code{FNCT}), or on the type either on the symbol type (e.g., @code{VAR} or @code{FUN}), or on the type
tag: since @code{<double>} is the type for both @code{NUM} and @code{exp}, tag: since @code{<double>} is the type for both @code{NUM} and @code{exp},
this printer will be used for them. this printer will be used for them.
@@ -10040,13 +10041,13 @@ a valueless (@samp{()}) @code{input} nonterminal (@code{nterm}).
Then the parser calls the scanner. Then the parser calls the scanner.
@example @example
Reading a token: Next token is token FNCT (sin()) Reading a token: Next token is token FUN (sin())
Shifting token FNCT (sin()) Shifting token FUN (sin())
Entering state 6 Entering state 6
@end example @end example
@noindent @noindent
That token (@code{token}) is a function (@code{FNCT}) whose value is That token (@code{token}) is a function (@code{FUN}) whose value is
@samp{sin} as formatted per our @code{%printer} specification: @samp{sin()}. @samp{sin} as formatted per our @code{%printer} specification: @samp{sin()}.
The parser stores (@code{Shifting}) that token, and others, until it can do The parser stores (@code{Shifting}) that token, and others, until it can do
something about it. something about it.
@@ -10101,7 +10102,7 @@ Next token is token ')' ()
Shifting token ')' () Shifting token ')' ()
Entering state 31 Entering state 31
Reducing stack by rule 9 (line 47): Reducing stack by rule 9 (line 47):
$1 = token FNCT (sin()) $1 = token FUN (sin())
$2 = token '(' () $2 = token '(' ()
$3 = nterm exp (0.000000) $3 = nterm exp (0.000000)
$4 = token ')' () $4 = token ')' ()
@@ -14226,8 +14227,8 @@ London, Department of Computer Science, TR-00-12 (December 2000).
@c LocalWords: NUM exp subsubsection kbd Ctrl ctype EOF getchar isdigit nonfree @c LocalWords: NUM exp subsubsection kbd Ctrl ctype EOF getchar isdigit nonfree
@c LocalWords: ungetc stdin scanf sc calc ulator ls lm cc NEG prec yyerrok rr @c LocalWords: ungetc stdin scanf sc calc ulator ls lm cc NEG prec yyerrok rr
@c LocalWords: longjmp fprintf stderr yylloc YYLTYPE cos ln Stallman Destructor @c LocalWords: longjmp fprintf stderr yylloc YYLTYPE cos ln Stallman Destructor
@c LocalWords: symrec val tptr FNCT fnctptr func struct sym enum IEC syntaxes @c LocalWords: symrec val tptr FUN func struct sym enum IEC syntaxes
@c LocalWords: fnct putsym getsym fname arith fncts atan ptr malloc sizeof Lex @c LocalWords: fun putsym getsym arith funs atan ptr malloc sizeof Lex
@c LocalWords: strlen strcpy fctn strcmp isalpha symbuf realloc isalnum DOTDOT @c LocalWords: strlen strcpy fctn strcmp isalpha symbuf realloc isalnum DOTDOT
@c LocalWords: ptypes itype YYPRINT trigraphs yytname expseq vindex dtype Unary @c LocalWords: ptypes itype YYPRINT trigraphs yytname expseq vindex dtype Unary
@c LocalWords: Rhs YYRHSLOC LE nonassoc op deffn typeless yynerrs nonterminal @c LocalWords: Rhs YYRHSLOC LE nonassoc op deffn typeless yynerrs nonterminal