1 /* Output the generated parsing program for Bison. 
   3    Copyright (C) 1984, 1986, 1989, 1992, 2000-2012 Free Software 
   6    This file is part of Bison, the GNU Compiler Compiler. 
   8    This program is free software: you can redistribute it and/or modify 
   9    it under the terms of the GNU General Public License as published by 
  10    the Free Software Foundation, either version 3 of the License, or 
  11    (at your option) any later version. 
  13    This program is distributed in the hope that it will be useful, 
  14    but WITHOUT ANY WARRANTY; without even the implied warranty of 
  15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
  16    GNU General Public License for more details. 
  18    You should have received a copy of the GNU General Public License 
  19    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ 
  24 #include <concat-filename.h> 
  25 #include <configmake.h> 
  27 #include <get-errno.h> 
  29 #include <spawn-pipe.h> 
  31 #include <wait-process.h> 
  37 #include "muscle-tab.h" 
  40 #include "scan-code.h"    /* max_left_semantic_context */ 
  41 #include "scan-skel.h" 
  45 static struct obstack format_obstack
; 
  48 /*-------------------------------------------------------------------. 
  49 | Create a function NAME which associates to the muscle NAME the     | 
  50 | result of formatting the FIRST and then TABLE_DATA[BEGIN..END[ (of | 
  51 | TYPE), and to the muscle NAME_max, the max value of the            | 
  53 `-------------------------------------------------------------------*/ 
  56 #define GENERATE_MUSCLE_INSERT_TABLE(Name, Type)                        \ 
  59 Name (char const *name,                                                 \ 
  72   obstack_fgrow1 (&format_obstack, "%6d", first);                       \ 
  73   for (i = begin; i < end; ++i)                                         \ 
  75       obstack_1grow (&format_obstack, ',');                             \ 
  78           obstack_sgrow (&format_obstack, "\n  ");                      \ 
  83       obstack_fgrow1 (&format_obstack, "%6d", table_data[i]);           \ 
  84       if (table_data[i] < min)                                          \ 
  85         min = table_data[i];                                            \ 
  86       if (max < table_data[i])                                          \ 
  87         max = table_data[i];                                            \ 
  89   obstack_1grow (&format_obstack, 0);                                   \ 
  90   muscle_insert (name, obstack_finish (&format_obstack));               \ 
  94   /* Build `NAME_min' and `NAME_max' in the obstack. */                 \ 
  95   obstack_fgrow1 (&format_obstack, "%s_min", name);                     \ 
  96   obstack_1grow (&format_obstack, 0);                                   \ 
  97   MUSCLE_INSERT_LONG_INT (obstack_finish (&format_obstack), lmin);      \ 
  98   obstack_fgrow1 (&format_obstack, "%s_max", name);                     \ 
  99   obstack_1grow (&format_obstack, 0);                                   \ 
 100   MUSCLE_INSERT_LONG_INT (obstack_finish (&format_obstack), lmax);      \ 
 103 GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_unsigned_int_table
, unsigned int) 
 104 GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_int_table
, int) 
 105 GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_base_table
, base_number
) 
 106 GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_rule_number_table
, rule_number
) 
 107 GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_symbol_number_table
, symbol_number
) 
 108 GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_state_number_table
, state_number
) 
 111 /*--------------------------------------------------------------------. 
 112 | Print to OUT a representation of STRING escaped both for C and M4.  | 
 113 `--------------------------------------------------------------------*/ 
 116 escaped_output (FILE *out
, char const *string
) 
 121   for (p 
= quotearg_style (c_quoting_style
, string
); *p
; p
++) 
 124       case '$': fputs ("$][", out
); break; 
 125       case '@': fputs ("@@",  out
); break; 
 126       case '[': fputs ("@{",  out
); break; 
 127       case ']': fputs ("@}",  out
); break; 
 128       default: fputc (*p
, out
); break; 
 135 /*------------------------------------------------------------------. 
 136 | Prepare the muscles related to the symbols: translate, tname, and | 
 138 `------------------------------------------------------------------*/ 
 141 prepare_symbols (void) 
 143   MUSCLE_INSERT_INT ("tokens_number", ntokens
); 
 144   MUSCLE_INSERT_INT ("nterms_number", nvars
); 
 145   MUSCLE_INSERT_INT ("symbols_number", nsyms
); 
 146   MUSCLE_INSERT_INT ("undef_token_number", undeftoken
->number
); 
 147   MUSCLE_INSERT_INT ("user_token_number_max", max_user_token_number
); 
 149   muscle_insert_symbol_number_table ("translate", 
 151                                      token_translations
[0], 
 152                                      1, max_user_token_number 
+ 1); 
 154   /* tname -- token names.  */ 
 157     /* We assume that the table will be output starting at column 2. */ 
 159     struct quoting_options 
*qo 
= clone_quoting_options (0); 
 160     set_quoting_style (qo
, c_quoting_style
); 
 161     set_quoting_flags (qo
, QA_SPLIT_TRIGRAPHS
); 
 162     for (i 
= 0; i 
< nsyms
; i
++) 
 164         char *cp 
= quotearg_alloc (symbols
[i
]->tag
, -1, qo
); 
 165         /* Width of the next token, including the two quotes, the 
 166            comma and the space.  */ 
 167         int width 
= strlen (cp
) + 2; 
 171             obstack_sgrow (&format_obstack
, "\n "); 
 176           obstack_1grow (&format_obstack
, ' '); 
 177         MUSCLE_OBSTACK_SGROW (&format_obstack
, cp
); 
 179         obstack_1grow (&format_obstack
, ','); 
 183     obstack_sgrow (&format_obstack
, " ]b4_null["); 
 185     /* Finish table and store. */ 
 186     obstack_1grow (&format_obstack
, 0); 
 187     muscle_insert ("tname", obstack_finish (&format_obstack
)); 
 190   /* Output YYTOKNUM. */ 
 193     int *values 
= xnmalloc (ntokens
, sizeof *values
); 
 194     for (i 
= 0; i 
< ntokens
; ++i
) 
 195       values
[i
] = symbols
[i
]->user_token_number
; 
 196     muscle_insert_int_table ("toknum", values
, 
 197                              values
[0], 1, ntokens
); 
 203 /*----------------------------------------------------------------. 
 204 | Prepare the muscles related to the rules: r1, r2, rline, dprec, | 
 205 | merger, immediate.                                              | 
 206 `----------------------------------------------------------------*/ 
 211   unsigned int *rline 
= xnmalloc (nrules
, sizeof *rline
); 
 212   symbol_number 
*r1 
= xnmalloc (nrules
, sizeof *r1
); 
 213   unsigned int *r2 
= xnmalloc (nrules
, sizeof *r2
); 
 214   int *dprec 
= xnmalloc (nrules
, sizeof *dprec
); 
 215   int *merger 
= xnmalloc (nrules
, sizeof *merger
); 
 216   int *immediate 
= xnmalloc (nrules
, sizeof *immediate
); 
 219   for (r 
= 0; r 
< nrules
; ++r
) 
 221       /* LHS of the rule R. */ 
 222       r1
[r
] = rules
[r
].lhs
->number
; 
 223       /* Length of rule R's RHS. */ 
 224       r2
[r
] = rule_rhs_length(&rules
[r
]); 
 225       /* Line where rule was defined. */ 
 226       rline
[r
] = rules
[r
].location
.start
.line
; 
 227       /* Dynamic precedence (GLR).  */ 
 228       dprec
[r
] = rules
[r
].dprec
; 
 229       /* Merger-function index (GLR).  */ 
 230       merger
[r
] = rules
[r
].merger
; 
 231       /* Immediate reduction flags (GLR).  */ 
 232       immediate
[r
] = rules
[r
].is_predicate
; 
 235   muscle_insert_unsigned_int_table ("rline", rline
, 0, 0, nrules
); 
 236   muscle_insert_symbol_number_table ("r1", r1
, 0, 0, nrules
); 
 237   muscle_insert_unsigned_int_table ("r2", r2
, 0, 0, nrules
); 
 238   muscle_insert_int_table ("dprec", dprec
, 0, 0, nrules
); 
 239   muscle_insert_int_table ("merger", merger
, 0, 0, nrules
); 
 240   muscle_insert_int_table ("immediate", immediate
, 0, 0, nrules
); 
 242   MUSCLE_INSERT_INT ("rules_number", nrules
); 
 243   MUSCLE_INSERT_INT ("max_left_semantic_context", max_left_semantic_context
); 
 253 /*--------------------------------------------. 
 254 | Prepare the muscles related to the states.  | 
 255 `--------------------------------------------*/ 
 258 prepare_states (void) 
 261   symbol_number 
*values 
= xnmalloc (nstates
, sizeof *values
); 
 262   for (i 
= 0; i 
< nstates
; ++i
) 
 263     values
[i
] = states
[i
]->accessing_symbol
; 
 264   muscle_insert_symbol_number_table ("stos", values
, 
 268   MUSCLE_INSERT_INT ("last", high
); 
 269   MUSCLE_INSERT_INT ("final_state_number", final_state
->number
); 
 270   MUSCLE_INSERT_INT ("states_number", nstates
); 
 274 /*-------------------------------------------------------. 
 275 | Compare two symbols by type-name, and then by number.  | 
 276 `-------------------------------------------------------*/ 
 279 symbol_type_name_cmp (const symbol 
**lhs
, const symbol 
**rhs
) 
 281   int res 
= UNIQSTR_CMP((*lhs
)->type_name
, (*rhs
)->type_name
); 
 284   return (*lhs
)->number 
- (*rhs
)->number
; 
 288 /*----------------------------------------------------------------. 
 289 | Return a (malloc'ed) table of the symbols sorted by type-name.  | 
 290 `----------------------------------------------------------------*/ 
 293 symbols_by_type_name (void) 
 295   typedef int (*qcmp_type
) (const void *, const void *); 
 296   symbol 
**res 
= xmemdup (symbols
, nsyms 
* sizeof *res
); 
 297   qsort (res
, nsyms
, sizeof *res
, (qcmp_type
) &symbol_type_name_cmp
); 
 302 /*------------------------------------------------------------------. 
 303 | Define b4_type_names, which is a list of (lists of the numbers of | 
 304 | symbols with same type-name).                                     | 
 305 `------------------------------------------------------------------*/ 
 308 type_names_output (FILE *out
) 
 311   symbol 
**syms 
= symbols_by_type_name (); 
 312   fputs ("m4_define([b4_type_names],\n[", out
); 
 313   for (i 
= 0; i 
< nsyms
; /* nothing */) 
 315       // The index of the first symbol of the current type-name. 
 317       fputs (i 
? ",\n[" : "[", out
); 
 318       for (; i 
< nsyms 
&& syms
[i
]->type_name 
== syms
[i0
]->type_name
; ++i
) 
 319         fprintf (out
, "%s%d", i 
!= i0 
? ", " : "", syms
[i
]->number
); 
 322   fputs ("])\n\n", out
); 
 327 /*-------------------------------------. 
 328 | The list of all the symbol numbers.  | 
 329 `-------------------------------------*/ 
 332 symbol_numbers_output (FILE *out
) 
 335   fputs ("m4_define([b4_symbol_numbers],\n[", out
); 
 336   for (i 
= 0; i 
< nsyms
; ++i
) 
 337     fprintf (out
, "%s[%d]", i 
? ", " : "", i
); 
 338   fputs ("])\n\n", out
); 
 342 /*---------------------------------. 
 343 | Output the user actions to OUT.  | 
 344 `---------------------------------*/ 
 347 user_actions_output (FILE *out
) 
 351   fputs ("m4_define([b4_actions], \n[", out
); 
 352   for (r 
= 0; r 
< nrules
; ++r
) 
 355         fprintf (out
, "b4_%scase(%d, [b4_syncline(%d, ", 
 356                  rules
[r
].is_predicate 
? "predicate_" : "", 
 357                  r 
+ 1, rules
[r
].action_location
.start
.line
); 
 358         escaped_output (out
, rules
[r
].action_location
.start
.file
); 
 359         fprintf (out
, ")\n[    %s]])\n\n", rules
[r
].action
); 
 361   fputs ("])\n\n", out
); 
 364 /*------------------------------------. 
 365 | Output the merge functions to OUT.  | 
 366 `------------------------------------*/ 
 369 merger_output (FILE *out
) 
 374   fputs ("m4_define([b4_mergers], \n[[", out
); 
 375   for (n 
= 1, p 
= merge_functions
; p 
!= NULL
; n 
+= 1, p 
= p
->next
) 
 377       if (p
->type
[0] == '\0') 
 378         fprintf (out
, "  case %d: *yy0 = %s (*yy0, *yy1); break;\n", 
 381         fprintf (out
, "  case %d: yy0->%s = %s (*yy0, *yy1); break;\n", 
 382                  n
, p
->type
, p
->name
); 
 384   fputs ("]])\n\n", out
); 
 388 /*---------------------------------------------. 
 389 | Prepare the muscles for symbol definitions.  | 
 390 `---------------------------------------------*/ 
 393 prepare_symbol_definitions (void) 
 396   for (i 
= 0; i 
< nsyms
; ++i
) 
 398       symbol 
*sym 
= symbols
[i
]; 
 402 #define SET_KEY(Entry)                                          \ 
 403       obstack_fgrow2 (&format_obstack, "symbol(%d, %s)",        \ 
 405       obstack_1grow (&format_obstack, 0);                       \ 
 406       key = obstack_finish (&format_obstack); 
 408 #define SET_KEY2(Entry, Suffix)                                 \ 
 409       obstack_fgrow3 (&format_obstack, "symbol(%d, %s_%s)",     \ 
 411       obstack_1grow (&format_obstack, 0);                       \ 
 412       key = obstack_finish (&format_obstack); 
 414       // Whether the symbol has an identifier. 
 415       value 
= symbol_id_get (sym
); 
 417       MUSCLE_INSERT_INT (key
, !!value
); 
 421       MUSCLE_INSERT_STRING (key
, value 
? value 
: ""); 
 423       // Its tag.  Typically for documentation purpose. 
 425       MUSCLE_INSERT_STRING (key
, sym
->tag
); 
 427       SET_KEY("user_number"); 
 428       MUSCLE_INSERT_INT (key
, sym
->user_token_number
); 
 431       MUSCLE_INSERT_INT (key
, 
 432                          i 
< ntokens 
&& sym 
!= errtoken 
&& sym 
!= undeftoken
); 
 435       MUSCLE_INSERT_INT (key
, sym
->number
); 
 438       MUSCLE_INSERT_INT (key
, !!sym
->type_name
); 
 441       MUSCLE_INSERT_STRING (key
, sym
->type_name 
? sym
->type_name 
: ""); 
 445         for (j 
= 0; j 
< CODE_PROPS_SIZE
; ++j
) 
 447             /* "printer", not "%printer".  */ 
 448             char const *pname 
= code_props_type_string (j
) + 1; 
 449             code_props 
const *p 
= symbol_code_props_get (sym
, j
); 
 450             SET_KEY2("has", pname
); 
 451             MUSCLE_INSERT_INT (key
, !!p
->code
); 
 455                 SET_KEY2(pname
, "file"); 
 456                 MUSCLE_INSERT_STRING (key
, p
->location
.start
.file
); 
 458                 SET_KEY2(pname
, "line"); 
 459                 MUSCLE_INSERT_INT (key
, p
->location
.start
.line
); 
 462                 MUSCLE_INSERT_STRING_RAW (key
, p
->code
); 
 472 /*--------------------------------------. 
 473 | Output the tokens definition to OUT.  | 
 474 `--------------------------------------*/ 
 477 token_definitions_output (FILE *out
) 
 480   char const *sep 
= ""; 
 482   fputs ("m4_define([b4_tokens], \n[", out
); 
 483   for (i 
= 0; i 
< ntokens
; ++i
) 
 485       symbol 
*sym 
= symbols
[i
]; 
 486       int number 
= sym
->user_token_number
; 
 487       uniqstr id 
= symbol_id_get (sym
); 
 489       /* At this stage, if there are literal string aliases, they are 
 490          part of SYMBOLS, so we should not find their aliased symbols 
 492       aver (number 
!= USER_NUMBER_HAS_STRING_ALIAS
); 
 494       /* Skip error token and tokens without identifier.  */ 
 495       if (sym 
!= errtoken 
&& id
) 
 497           fprintf (out
, "%s[[[%s]], %d]", 
 502   fputs ("])\n\n", out
); 
 507 prepare_actions (void) 
 509   /* Figure out the actions for the specified state, indexed by 
 510      lookahead token type.  */ 
 512   muscle_insert_rule_number_table ("defact", yydefact
, 
 513                                    yydefact
[0], 1, nstates
); 
 515   /* Figure out what to do after reducing with each rule, depending on 
 516      the saved state from before the beginning of parsing the data 
 517      that matched this rule.  */ 
 518   muscle_insert_state_number_table ("defgoto", yydefgoto
, 
 519                                     yydefgoto
[0], 1, nsyms 
- ntokens
); 
 523   muscle_insert_base_table ("pact", base
, 
 524                              base
[0], 1, nstates
); 
 525   MUSCLE_INSERT_INT ("pact_ninf", base_ninf
); 
 528   muscle_insert_base_table ("pgoto", base
, 
 529                              base
[nstates
], nstates 
+ 1, nvectors
); 
 531   muscle_insert_base_table ("table", table
, 
 532                             table
[0], 1, high 
+ 1); 
 533   MUSCLE_INSERT_INT ("table_ninf", table_ninf
); 
 535   muscle_insert_base_table ("check", check
, 
 536                             check
[0], 1, high 
+ 1); 
 538   /* GLR parsing slightly modifies YYTABLE and YYCHECK (and thus 
 539      YYPACT) so that in states with unresolved conflicts, the default 
 540      reduction is not used in the conflicted entries, so that there is 
 541      a place to put a conflict pointer. 
 543      This means that YYCONFLP and YYCONFL are nonsense for a non-GLR 
 544      parser, so we could avoid accidents by not writing them out in 
 545      that case.  Nevertheless, it seems even better to be able to use 
 546      the GLR skeletons even without the non-deterministic tables.  */ 
 547   muscle_insert_unsigned_int_table ("conflict_list_heads", conflict_table
, 
 548                                     conflict_table
[0], 1, high 
+ 1); 
 549   muscle_insert_unsigned_int_table ("conflicting_rules", conflict_list
, 
 550                                     0, 1, conflict_list_cnt
); 
 554 /*--------------------------------------------. 
 555 | Output the definitions of all the muscles.  | 
 556 `--------------------------------------------*/ 
 559 muscles_output (FILE *out
) 
 561   fputs ("m4_init()\n", out
); 
 563   symbol_numbers_output (out
); 
 564   token_definitions_output (out
); 
 565   type_names_output (out
); 
 566   user_actions_output (out
); 
 568   muscles_m4_output (out
); 
 571 /*---------------------------. 
 572 | Call the skeleton parser.  | 
 573 `---------------------------*/ 
 576 output_skeleton (void) 
 581   /* Compute the names of the package data dir and skeleton files.  */ 
 582   char const *m4 
= (m4 
= getenv ("M4")) ? m4 
: M4
; 
 583   char const *datadir 
= pkgdatadir (); 
 584   char *m4sugar 
= xconcatenated_filename (datadir
, "m4sugar/m4sugar.m4", NULL
); 
 585   char *m4bison 
= xconcatenated_filename (datadir
, "bison.m4", NULL
); 
 586   char *skel 
= (IS_PATH_WITH_DIR (skeleton
) 
 588                 : xconcatenated_filename (datadir
, skeleton
, NULL
)); 
 590   /* Test whether m4sugar.m4 is readable, to check for proper 
 591      installation.  A faulty installation can cause deadlock, so a 
 592      cheap sanity check is worthwhile.  */ 
 593   xfclose (xfopen (m4sugar
, "r")); 
 595   /* Create an m4 subprocess connected to us via two pipes.  */ 
 597   if (trace_flag 
& trace_tools
) 
 598     fprintf (stderr
, "running: %s %s - %s %s\n", 
 599              m4
, m4sugar
, m4bison
, skel
); 
 601   /* Some future version of GNU M4 (most likely 1.6) may treat the -dV in a 
 602      position-dependent manner.  Keep it as the first argument so that all 
 605      See the thread starting at 
 606      <http://lists.gnu.org/archive/html/bug-bison/2008-07/msg00000.html> 
 609     char const *argv
[10]; 
 613     /* When POSIXLY_CORRECT is set, GNU M4 1.6 and later disable GNU 
 614        extensions, which Bison's skeletons depend on.  With older M4, 
 615        it has no effect.  M4 1.4.12 added a -g/--gnu command-line 
 616        option to make it explicit that a program wants GNU M4 
 617        extensions even when POSIXLY_CORRECT is set. 
 619        See the thread starting at 
 620        <http://lists.gnu.org/archive/html/bug-bison/2008-07/msg00000.html> 
 623       argv
[i
++] = M4_GNU_OPTION
; 
 627     if (trace_flag 
& trace_m4
) 
 634     aver (i 
<= ARRAY_CARDINALITY (argv
)); 
 636     /* The ugly cast is because gnulib gets the const-ness wrong.  */ 
 637     pid 
= create_pipe_bidi ("m4", m4
, (char **)(void*)argv
, false, true, 
 645   if (trace_flag 
& trace_muscles
) 
 646     muscles_output (stderr
); 
 648     FILE *out 
= xfdopen (filter_fd
[1], "w"); 
 649     muscles_output (out
); 
 653   /* Read and process m4's output.  */ 
 654   timevar_push (TV_M4
); 
 656     FILE *in 
= xfdopen (filter_fd
[0], "r"); 
 658     /* scan_skel should have read all of M4's output.  Otherwise, when we 
 659        close the pipe, we risk letting M4 report a broken-pipe to the 
 664   wait_subprocess (pid
, "m4", false, false, true, true, NULL
); 
 671   /* BISON_USE_PUSH_FOR_PULL is for the test suite and should not be 
 672      documented for the user.  */ 
 673   char const *cp 
= getenv ("BISON_USE_PUSH_FOR_PULL"); 
 674   bool use_push_for_pull_flag 
= cp 
&& *cp 
&& strtol (cp
, 0, 10); 
 677   MUSCLE_INSERT_BOOL ("defines_flag", defines_flag
); 
 678   MUSCLE_INSERT_BOOL ("glr_flag", glr_parser
); 
 679   MUSCLE_INSERT_BOOL ("nondeterministic_flag", nondeterministic_parser
); 
 680   MUSCLE_INSERT_BOOL ("synclines_flag", !no_lines_flag
); 
 681   MUSCLE_INSERT_BOOL ("tag_seen_flag", tag_seen
); 
 682   MUSCLE_INSERT_BOOL ("token_table_flag", token_table_flag
); 
 683   MUSCLE_INSERT_BOOL ("use_push_for_pull_flag", use_push_for_pull_flag
); 
 684   MUSCLE_INSERT_BOOL ("yacc_flag", yacc_flag
); 
 687   if (spec_name_prefix
) 
 688     MUSCLE_INSERT_STRING ("prefix", spec_name_prefix
); 
 690   MUSCLE_INSERT_STRING ("file_name_all_but_ext", all_but_ext
); 
 692 #define DEFINE(Name) MUSCLE_INSERT_STRING (#Name, Name ? Name : "") 
 694   DEFINE (parser_file_name
); 
 695   DEFINE (spec_defines_file
); 
 696   DEFINE (spec_file_prefix
); 
 697   DEFINE (spec_graph_file
); 
 698   DEFINE (spec_name_prefix
); 
 699   DEFINE (spec_outfile
); 
 700   DEFINE (spec_verbose_file
); 
 703   /* Find the right skeleton file, and add muscles about the skeletons.  */ 
 705     MUSCLE_INSERT_C_STRING ("skeleton", skeleton
); 
 707     skeleton 
= language
->skeleton
; 
 709   /* About the skeletons.  */ 
 711     /* b4_pkgdatadir is used inside m4_include in the skeletons, so digraphs 
 712        would never be expanded.  Hopefully no one has M4-special characters in 
 713        his Bison installation path.  */ 
 714     MUSCLE_INSERT_STRING_RAW ("pkgdatadir", pkgdatadir ()); 
 719 /*----------------------------------------------------------. 
 720 | Output the parsing tables and the parser code to ftable.  | 
 721 `----------------------------------------------------------*/ 
 726   obstack_init (&format_obstack
); 
 732   prepare_symbol_definitions (); 
 736   /* Process the selected skeleton file.  */ 
 739   obstack_free (&format_obstack
, NULL
); 
 745   char const *cp 
= getenv ("BISON_PKGDATADIR"); 
 746   return cp 
? cp 
: PKGDATADIR
;