From 8b2d233283859d5a6cebe1f368d790fbd13ecf13 Mon Sep 17 00:00:00 2001 From: Akim Demaille Date: Sun, 10 Feb 2019 15:14:24 +0100 Subject: [PATCH] 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)'). --- doc/bison.texi | 181 +++++++++++++++++++++++++------------------------ 1 file changed, 91 insertions(+), 90 deletions(-) diff --git a/doc/bison.texi b/doc/bison.texi index 217cbf97..8666e2ff 100644 --- a/doc/bison.texi +++ b/doc/bison.texi @@ -1543,7 +1543,8 @@ The source code for this calculator is named @file{rpcalc.y}. The @subsection Declarations for @code{rpcalc} 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 @example @@ -1618,7 +1619,7 @@ line: @group exp: - NUM @{ $$ = $1; @} + NUM | 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} 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 second handles an addition-expression, which looks like two expressions -followed by a plus-sign. The third handles subtraction, and so on. +The first rule handles the simplest expressions: those that are just +numbers. The second handles an addition-expression, which looks like two +expressions followed by a plus-sign. The third handles subtraction, and so +on. @example 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: @example -exp: NUM ; -exp: exp exp '+' @{ $$ = $1 + $2; @}; -exp: exp exp '-' @{ $$ = $1 - $2; @}; +exp: NUM; +exp: exp exp '+' @{ $$ = $1 + $2; @}; +exp: exp exp '-' @{ $$ = $1 - $2; @}; @dots{} @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 the second one. The third component, @code{'+'}, has no meaningful 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 -rule, the sum of the two subexpressions' values is produced as the value of -the entire expression. @xref{Actions}. +@code{$3}. The first rule relies on the implicit default action: @samp{@{ +$$ = $1; @}}. -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: +When @code{yyparse} recognizes a sum expression using this rule, the sum of +the two subexpressions' values is produced as the value of 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 not +require it. You can add or change white space as much as you wish. For +example, this: @example exp: NUM | exp exp '+' @{$$ = $1 + $2; @} | @dots{} ; @@ -1831,11 +1837,10 @@ Here is the code for the lexical analyzer: int yylex (void) @{ - int c; - + int c = getchar (); /* Skip white space. */ - while ((c = getchar ()) == ' ' || c == '\t') - continue; + while (c == ' ' || c == '\t') + c = getchar (); @end group @group /* Process numbers. */ @@ -1848,10 +1853,11 @@ yylex (void) @end group @group /* Return end-of-input. */ - if (c == EOF) + else if (c == EOF) return 0; /* Return a single char. */ - return c; + else + return c; @} @end group @end example @@ -2032,7 +2038,7 @@ line: @group exp: - NUM @{ $$ = $1; @} + NUM | exp '+' exp @{ $$ = $1 + $3; @} | exp '-' exp @{ $$ = $1 - $3; @} | exp '*' exp @{ $$ = $1 * $3; @} @@ -2212,7 +2218,7 @@ line: @group exp: - NUM @{ $$ = $1; @} + NUM | 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 %define api.value.type union /* Generate YYSTYPE from these types: */ -%token NUM /* Simple double precision number. */ -%token VAR FNCT /* Symbol table pointer: variable and function. */ +%token NUM /* Double precision number. */ +%token VAR FUN /* Symbol table pointer: variable/function. */ %type exp @group @@ -2441,7 +2447,7 @@ store these values. 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 -@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 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. 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 @example @@ -2479,10 +2485,10 @@ line: @group exp: - NUM @{ $$ = $1; @} + NUM | VAR @{ $$ = $1->value.var; @} | 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; @} @@ -2513,7 +2519,7 @@ provides for either functions or variables to be placed in the table. @example @group /* Function type. */ -typedef double (*func_t) (double); +typedef double (func_t) (double); @end group @group @@ -2521,11 +2527,11 @@ typedef double (*func_t) (double); struct symrec @{ char *name; /* name of symbol */ - int type; /* type of symbol: either VAR or FNCT */ + int type; /* type of symbol: either VAR or FUN */ union @{ - double var; /* value of a VAR */ - func_t fnctptr; /* value of a FNCT */ + double var; /* value of a VAR */ + func_t *fun; /* value of a FUN */ @} value; struct symrec *next; /* link field */ @}; @@ -2537,8 +2543,8 @@ typedef struct symrec symrec; /* The symbol table: a chain of 'struct symrec'. */ extern symrec *sym_table; -symrec *putsym (char const *, int); -symrec *getsym (char const *); +symrec *putsym (char const *name, int sym_type); +symrec *getsym (char const *name); @end group @end example @@ -2550,13 +2556,13 @@ the symbol table: @group struct init @{ - char const *fname; - double (*fnct) (double); + char const *name; + func_t *fun; @}; @end group @group -struct init const arith_fncts[] = +struct init const arith_funs[] = @{ @{ "atan", atan @}, @{ "cos", cos @}, @@ -2575,15 +2581,15 @@ symrec *sym_table; @group /* Put arithmetic functions in table. */ -static -void +static void init_table (void) +@end group +@group @{ - int i; - for (i = 0; arith_fncts[i].fname != 0; i++) + for (int i = 0; arith_funs[i].name; i++) @{ - symrec *ptr = putsym (arith_fncts[i].fname, FNCT); - ptr->value.fnctptr = arith_fncts[i].fnct; + symrec *ptr = putsym (arith_funs[i].name, FUN); + ptr->value.fun = arith_funs[i].fun; @} @} @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 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. 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. @@ -2606,29 +2612,26 @@ found, a pointer to that symbol is returned; otherwise zero is returned. @group symrec * -putsym (char const *sym_name, int sym_type) +putsym (char const *name, int sym_type) @{ - symrec *ptr = (symrec *) malloc (sizeof (symrec)); - ptr->name = (char *) malloc (strlen (sym_name) + 1); - strcpy (ptr->name,sym_name); - ptr->type = sym_type; - ptr->value.var = 0; /* Set value to 0 even if fctn. */ - ptr->next = (struct symrec *)sym_table; - sym_table = ptr; - return ptr; + symrec *res = (symrec *) malloc (sizeof (symrec)); + res->name = strdup (name); + res->type = sym_type; + res->value.var = 0; /* Set value to 0 even if fun. */ + res->next = sym_table; + sym_table = res; + return res; @} @end group @group symrec * -getsym (char const *sym_name) +getsym (char const *name) @{ - symrec *ptr; - for (ptr = sym_table; ptr != (symrec *) 0; - ptr = (symrec *)ptr->next) - if (strcmp (ptr->name, sym_name) == 0) - return ptr; - return 0; + for (symrec *p = sym_table; p; p = p->next) + if (strcmp (p->name, name) == 0) + return p; + return NULL; @} @end group @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 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 @code{putsym}. Again, a pointer and its type (which must be @code{VAR}) is 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. */ static size_t length = 40; static char *symbuf = 0; - symrec *s; - int i; @end group if (!symbuf) - symbuf = (char *) malloc (length + 1); + symbuf = malloc (length + 1); - i = 0; + int i = 0; do @group @{ @@ -2708,7 +2709,7 @@ Bison generated a definition of @code{YYSTYPE} with a member named if (i == length) @{ length *= 2; - symbuf = (char *) realloc (symbuf, length + 1); + symbuf = realloc (symbuf, length + 1); @} /* Add this character to the buffer. */ symbuf[i++] = c; @@ -2724,10 +2725,10 @@ Bison generated a definition of @code{YYSTYPE} with a member named @end group @group - s = getsym (symbuf); - if (s == 0) + symrec *s = getsym (symbuf); + if (!s) s = putsym (symbuf, VAR); - *((symrec**) &yylval) = s; + yylval.VAR = s; /* or yylval.FUN = s. */ return s->type; @} @@ -2748,22 +2749,22 @@ on user demand (@xref{Tracing, , Tracing Your Parser}, for details): @example @group /* Called by yyparse on error. */ -void -yyerror (char const *s) +void yyerror (char const *s) @{ fprintf (stderr, "%s\n", s); @} @end group @group -int -main (int argc, char const* argv[]) +int main (int argc, char const* argv[]) +@end group +@group @{ - int i; /* Enable parse traces on option -p. */ - for (i = 1; i < argc; ++i) - if (!strcmp(argv[i], "-p")) - yydebug = 1; + if (argc == 2 && strcmp(argv[1], "-p") == 0) + yydebug = 1; +@end group +@group init_table (); return yyparse (); @} @@ -7011,9 +7012,9 @@ assuming that the characters of the token are stored in characters like @samp{"} that require escaping. @example -for (i = 0; i < YYNTOKENS; i++) +for (int i = 0; i < YYNTOKENS; i++) @{ - if (yytname[i] != 0 + if (yytname[i] && yytname[i][0] == '"' && ! strncmp (yytname[i] + 1, token_buffer, strlen (token_buffer)) @@ -10002,7 +10003,7 @@ prologue: /* Formatting semantic values. */ %printer @{ fprintf (yyo, "%s", $$->name); @} VAR; -%printer @{ fprintf (yyo, "%s()", $$->name); @} FNCT; +%printer @{ fprintf (yyo, "%s()", $$->name); @} FUN; %printer @{ fprintf (yyo, "%g", $$); @} ; @end example @@ -10015,7 +10016,7 @@ ill-named) @code{%verbose} directive. The set of @code{%printer} directives demonstrates how to format the 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{} is the type for both @code{NUM} and @code{exp}, 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. @example -Reading a token: Next token is token FNCT (sin()) -Shifting token FNCT (sin()) +Reading a token: Next token is token FUN (sin()) +Shifting token FUN (sin()) Entering state 6 @end example @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()}. The parser stores (@code{Shifting}) that token, and others, until it can do something about it. @@ -10101,7 +10102,7 @@ Next token is token ')' () Shifting token ')' () Entering state 31 Reducing stack by rule 9 (line 47): - $1 = token FNCT (sin()) + $1 = token FUN (sin()) $2 = token '(' () $3 = nterm exp (0.000000) $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: 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: symrec val tptr FNCT fnctptr func struct sym enum IEC syntaxes -@c LocalWords: fnct putsym getsym fname arith fncts atan ptr malloc sizeof Lex +@c LocalWords: symrec val tptr FUN func struct sym enum IEC syntaxes +@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: ptypes itype YYPRINT trigraphs yytname expseq vindex dtype Unary @c LocalWords: Rhs YYRHSLOC LE nonassoc op deffn typeless yynerrs nonterminal