]> git.saurik.com Git - bison.git/blame_incremental - src/output.c
yacc.c: initialize yylval and yylloc.
[bison.git] / src / output.c
... / ...
CommitLineData
1/* Output the generated parsing program for Bison.
2
3 Copyright (C) 1984, 1986, 1989, 1992, 2000-2012 Free Software
4 Foundation, Inc.
5
6 This file is part of Bison, the GNU Compiler Compiler.
7
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.
12
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.
17
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/>. */
20
21#include <config.h>
22#include "system.h"
23
24#include <configmake.h>
25#include <error.h>
26#include <get-errno.h>
27#include <quotearg.h>
28#include <spawn-pipe.h>
29#include <timevar.h>
30#include <wait-process.h>
31
32#include "complain.h"
33#include "files.h"
34#include "getargs.h"
35#include "gram.h"
36#include "muscle-tab.h"
37#include "output.h"
38#include "reader.h"
39#include "scan-code.h" /* max_left_semantic_context */
40#include "scan-skel.h"
41#include "symtab.h"
42#include "tables.h"
43
44# define ARRAY_CARDINALITY(Array) (sizeof (Array) / sizeof *(Array))
45
46static struct obstack format_obstack;
47
48
49/*-------------------------------------------------------------------.
50| Create a function NAME which associates to the muscle NAME the |
51| result of formatting the FIRST and then TABLE_DATA[BEGIN..END[ (of |
52| TYPE), and to the muscle NAME_max, the max value of the |
53| TABLE_DATA. |
54`-------------------------------------------------------------------*/
55
56
57#define GENERATE_MUSCLE_INSERT_TABLE(Name, Type) \
58 \
59static void \
60Name (char const *name, \
61 Type *table_data, \
62 Type first, \
63 int begin, \
64 int end) \
65{ \
66 Type min = first; \
67 Type max = first; \
68 long int lmin; \
69 long int lmax; \
70 int i; \
71 int j = 1; \
72 \
73 obstack_printf (&format_obstack, "%6d", first); \
74 for (i = begin; i < end; ++i) \
75 { \
76 obstack_1grow (&format_obstack, ','); \
77 if (j >= 10) \
78 { \
79 obstack_sgrow (&format_obstack, "\n "); \
80 j = 1; \
81 } \
82 else \
83 ++j; \
84 obstack_printf (&format_obstack, "%6d", table_data[i]); \
85 if (table_data[i] < min) \
86 min = table_data[i]; \
87 if (max < table_data[i]) \
88 max = table_data[i]; \
89 } \
90 obstack_1grow (&format_obstack, 0); \
91 muscle_insert (name, obstack_finish (&format_obstack)); \
92 \
93 lmin = min; \
94 lmax = max; \
95 /* Build `NAME_min' and `NAME_max' in the obstack. */ \
96 obstack_printf (&format_obstack, "%s_min", name); \
97 obstack_1grow (&format_obstack, 0); \
98 MUSCLE_INSERT_LONG_INT (obstack_finish (&format_obstack), lmin); \
99 obstack_printf (&format_obstack, "%s_max", name); \
100 obstack_1grow (&format_obstack, 0); \
101 MUSCLE_INSERT_LONG_INT (obstack_finish (&format_obstack), lmax); \
102}
103
104GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_unsigned_int_table, unsigned int)
105GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_int_table, int)
106GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_base_table, base_number)
107GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_rule_number_table, rule_number)
108GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_symbol_number_table, symbol_number)
109GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_item_number_table, item_number)
110GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_state_number_table, state_number)
111
112
113/*----------------------------------------------------------------.
114| Print to OUT a representation of CP quoted and escaped for M4. |
115`----------------------------------------------------------------*/
116
117static void
118quoted_output (FILE *out, char const *cp)
119{
120 fprintf (out, "[[");
121
122 for (; *cp; cp++)
123 switch (*cp)
124 {
125 case '$': fputs ("$][", out); break;
126 case '@': fputs ("@@", out); break;
127 case '[': fputs ("@{", out); break;
128 case ']': fputs ("@}", out); break;
129 default: fputc (*cp, out); break;
130 }
131
132 fprintf (out, "]]");
133}
134
135/*----------------------------------------------------------------.
136| Print to OUT a representation of STRING quoted and escaped both |
137| for C and M4. |
138`----------------------------------------------------------------*/
139
140static void
141string_output (FILE *out, char const *string)
142{
143 quoted_output (out, quotearg_style (c_quoting_style, string));
144}
145
146
147/*------------------------------------------------------------------.
148| Prepare the muscles related to the symbols: translate, tname, and |
149| toknum. |
150`------------------------------------------------------------------*/
151
152static void
153prepare_symbols (void)
154{
155 MUSCLE_INSERT_INT ("tokens_number", ntokens);
156 MUSCLE_INSERT_INT ("nterms_number", nvars);
157 MUSCLE_INSERT_INT ("undef_token_number", undeftoken->number);
158 MUSCLE_INSERT_INT ("user_token_number_max", max_user_token_number);
159
160 muscle_insert_symbol_number_table ("translate",
161 token_translations,
162 token_translations[0],
163 1, max_user_token_number + 1);
164
165 /* tname -- token names. */
166 {
167 int i;
168 /* We assume that the table will be output starting at column 2. */
169 int j = 2;
170 struct quoting_options *qo = clone_quoting_options (0);
171 set_quoting_style (qo, c_quoting_style);
172 set_quoting_flags (qo, QA_SPLIT_TRIGRAPHS);
173 for (i = 0; i < nsyms; i++)
174 {
175 char *cp = quotearg_alloc (symbols[i]->tag, -1, qo);
176 /* Width of the next token, including the two quotes, the
177 comma and the space. */
178 int width = strlen (cp) + 2;
179
180 if (j + width > 75)
181 {
182 obstack_sgrow (&format_obstack, "\n ");
183 j = 1;
184 }
185
186 if (i)
187 obstack_1grow (&format_obstack, ' ');
188 obstack_escape (&format_obstack, cp);
189 free (cp);
190 obstack_1grow (&format_obstack, ',');
191 j += width;
192 }
193 free (qo);
194 obstack_sgrow (&format_obstack, " ]b4_null[");
195
196 /* Finish table and store. */
197 obstack_1grow (&format_obstack, 0);
198 muscle_insert ("tname", obstack_finish (&format_obstack));
199 }
200
201 /* Output YYTOKNUM. */
202 {
203 int i;
204 int *values = xnmalloc (ntokens, sizeof *values);
205 for (i = 0; i < ntokens; ++i)
206 values[i] = symbols[i]->user_token_number;
207 muscle_insert_int_table ("toknum", values,
208 values[0], 1, ntokens);
209 free (values);
210 }
211}
212
213
214/*-------------------------------------------------------------.
215| Prepare the muscles related to the rules: rhs, prhs, r1, r2, |
216| rline, dprec, merger. |
217`-------------------------------------------------------------*/
218
219static void
220prepare_rules (void)
221{
222 rule_number r;
223 unsigned int i = 0;
224 item_number *rhs = xnmalloc (nritems, sizeof *rhs);
225 unsigned int *prhs = xnmalloc (nrules, sizeof *prhs);
226 unsigned int *rline = xnmalloc (nrules, sizeof *rline);
227 symbol_number *r1 = xnmalloc (nrules, sizeof *r1);
228 unsigned int *r2 = xnmalloc (nrules, sizeof *r2);
229 int *dprec = xnmalloc (nrules, sizeof *dprec);
230 int *merger = xnmalloc (nrules, sizeof *merger);
231
232 for (r = 0; r < nrules; ++r)
233 {
234 item_number *rhsp = NULL;
235 /* Index of rule R in RHS. */
236 prhs[r] = i;
237 /* RHS of the rule R. */
238 for (rhsp = rules[r].rhs; *rhsp >= 0; ++rhsp)
239 rhs[i++] = *rhsp;
240 /* LHS of the rule R. */
241 r1[r] = rules[r].lhs->number;
242 /* Length of rule R's RHS. */
243 r2[r] = i - prhs[r];
244 /* Separator in RHS. */
245 rhs[i++] = -1;
246 /* Line where rule was defined. */
247 rline[r] = rules[r].location.start.line;
248 /* Dynamic precedence (GLR). */
249 dprec[r] = rules[r].dprec;
250 /* Merger-function index (GLR). */
251 merger[r] = rules[r].merger;
252 }
253 aver (i == nritems);
254
255 muscle_insert_item_number_table ("rhs", rhs, ritem[0], 1, nritems);
256 muscle_insert_unsigned_int_table ("prhs", prhs, 0, 0, nrules);
257 muscle_insert_unsigned_int_table ("rline", rline, 0, 0, nrules);
258 muscle_insert_symbol_number_table ("r1", r1, 0, 0, nrules);
259 muscle_insert_unsigned_int_table ("r2", r2, 0, 0, nrules);
260 muscle_insert_int_table ("dprec", dprec, 0, 0, nrules);
261 muscle_insert_int_table ("merger", merger, 0, 0, nrules);
262
263 MUSCLE_INSERT_INT ("rules_number", nrules);
264 MUSCLE_INSERT_INT ("max_left_semantic_context", max_left_semantic_context);
265
266 free (rhs);
267 free (prhs);
268 free (rline);
269 free (r1);
270 free (r2);
271 free (dprec);
272 free (merger);
273}
274
275/*--------------------------------------------.
276| Prepare the muscles related to the states. |
277`--------------------------------------------*/
278
279static void
280prepare_states (void)
281{
282 state_number i;
283 symbol_number *values = xnmalloc (nstates, sizeof *values);
284 for (i = 0; i < nstates; ++i)
285 values[i] = states[i]->accessing_symbol;
286 muscle_insert_symbol_number_table ("stos", values,
287 0, 1, nstates);
288 free (values);
289
290 MUSCLE_INSERT_INT ("last", high);
291 MUSCLE_INSERT_INT ("final_state_number", final_state->number);
292 MUSCLE_INSERT_INT ("states_number", nstates);
293}
294
295
296
297/*---------------------------------.
298| Output the user actions to OUT. |
299`---------------------------------*/
300
301static void
302user_actions_output (FILE *out)
303{
304 rule_number r;
305
306 fputs ("m4_define([b4_actions], \n[", out);
307 for (r = 0; r < nrules; ++r)
308 if (rules[r].action)
309 {
310 fprintf (out, "b4_case(%d, [b4_syncline(%d, ", r + 1,
311 rules[r].action_location.start.line);
312 string_output (out, rules[r].action_location.start.file);
313 fprintf (out, ")\n[ %s]])\n\n", rules[r].action);
314 }
315 fputs ("])\n\n", out);
316}
317
318/*--------------------------------------.
319| Output the merge functions to OUT. |
320`--------------------------------------*/
321
322static void
323merger_output (FILE *out)
324{
325 int n;
326 merger_list* p;
327
328 fputs ("m4_define([b4_mergers], \n[[", out);
329 for (n = 1, p = merge_functions; p != NULL; n += 1, p = p->next)
330 {
331 if (p->type[0] == '\0')
332 fprintf (out, " case %d: *yy0 = %s (*yy0, *yy1); break;\n",
333 n, p->name);
334 else
335 fprintf (out, " case %d: yy0->%s = %s (*yy0, *yy1); break;\n",
336 n, p->type, p->name);
337 }
338 fputs ("]])\n\n", out);
339}
340
341/*--------------------------------------.
342| Output the tokens definition to OUT. |
343`--------------------------------------*/
344
345static void
346token_definitions_output (FILE *out)
347{
348 int i;
349 char const *sep = "";
350
351 fputs ("m4_define([b4_tokens], \n[", out);
352 for (i = 0; i < ntokens; ++i)
353 {
354 symbol *sym = symbols[i];
355 int number = sym->user_token_number;
356
357 /* At this stage, if there are literal string aliases, they are
358 part of SYMBOLS, so we should not find their aliased symbols
359 here. */
360 aver (number != USER_NUMBER_HAS_STRING_ALIAS);
361
362 /* Skip error token. */
363 if (sym == errtoken)
364 continue;
365
366 /* If this string has an alias, then it is necessarily the alias
367 which is to be output. */
368 if (sym->alias)
369 sym = sym->alias;
370
371 /* Don't output literal chars or strings (when defined only as a
372 string). Note that must be done after the alias resolution:
373 think about `%token 'f' "f"'. */
374 if (sym->tag[0] == '\'' || sym->tag[0] == '\"')
375 continue;
376
377 /* Don't #define nonliteral tokens whose names contain periods,
378 dashes or '$' (as does the default value of the EOF token). */
379 if (mbschr (sym->tag, '.')
380 || mbschr (sym->tag, '-')
381 || mbschr (sym->tag, '$'))
382 continue;
383
384 fprintf (out, "%s[[[%s]], %d]",
385 sep, sym->tag, number);
386 sep = ",\n";
387 }
388 fputs ("])\n\n", out);
389}
390
391
392/*---------------------------------------------------.
393| Output the symbol destructors or printers to OUT. |
394`---------------------------------------------------*/
395
396static void
397symbol_code_props_output (FILE *out, char const *what,
398 code_props const *(*get)(symbol const *))
399{
400 int i;
401 char const *sep = "";
402
403 fputs ("m4_define([b4_symbol_", out);
404 fputs (what, out);
405 fputs ("], \n[", out);
406 for (i = 0; i < nsyms; ++i)
407 {
408 symbol *sym = symbols[i];
409 char const *code = (*get) (sym)->code;
410 if (code)
411 {
412 location loc = (*get) (sym)->location;
413 /* Filename, lineno,
414 Symbol-name, Symbol-number,
415 code, optional typename. */
416 fprintf (out, "%s[", sep);
417 sep = ",\n";
418 string_output (out, loc.start.file);
419 fprintf (out, ", %d, ", loc.start.line);
420 quoted_output (out, sym->tag);
421 fprintf (out, ", %d, [[%s]]", sym->number, code);
422 if (sym->type_name)
423 {
424 fputs (", ", out);
425 quoted_output (out, sym->type_name);
426 }
427 fputc (']', out);
428 }
429 }
430 fputs ("])\n\n", out);
431}
432
433
434static void
435prepare_actions (void)
436{
437 /* Figure out the actions for the specified state, indexed by
438 lookahead token type. */
439
440 muscle_insert_rule_number_table ("defact", yydefact,
441 yydefact[0], 1, nstates);
442
443 /* Figure out what to do after reducing with each rule, depending on
444 the saved state from before the beginning of parsing the data
445 that matched this rule. */
446 muscle_insert_state_number_table ("defgoto", yydefgoto,
447 yydefgoto[0], 1, nsyms - ntokens);
448
449
450 /* Output PACT. */
451 muscle_insert_base_table ("pact", base,
452 base[0], 1, nstates);
453 MUSCLE_INSERT_INT ("pact_ninf", base_ninf);
454
455 /* Output PGOTO. */
456 muscle_insert_base_table ("pgoto", base,
457 base[nstates], nstates + 1, nvectors);
458
459 muscle_insert_base_table ("table", table,
460 table[0], 1, high + 1);
461 MUSCLE_INSERT_INT ("table_ninf", table_ninf);
462
463 muscle_insert_base_table ("check", check,
464 check[0], 1, high + 1);
465
466 /* GLR parsing slightly modifies YYTABLE and YYCHECK (and thus
467 YYPACT) so that in states with unresolved conflicts, the default
468 reduction is not used in the conflicted entries, so that there is
469 a place to put a conflict pointer.
470
471 This means that YYCONFLP and YYCONFL are nonsense for a non-GLR
472 parser, so we could avoid accidents by not writing them out in
473 that case. Nevertheless, it seems even better to be able to use
474 the GLR skeletons even without the non-deterministic tables. */
475 muscle_insert_unsigned_int_table ("conflict_list_heads", conflict_table,
476 conflict_table[0], 1, high + 1);
477 muscle_insert_unsigned_int_table ("conflicting_rules", conflict_list,
478 0, 1, conflict_list_cnt);
479}
480
481/*--------------------------------------------.
482| Output the definitions of all the muscles. |
483`--------------------------------------------*/
484
485static void
486muscles_output (FILE *out)
487{
488 fputs ("m4_init()\n", out);
489
490 user_actions_output (out);
491 merger_output (out);
492 token_definitions_output (out);
493 symbol_code_props_output (out, "destructors", &symbol_destructor_get);
494 symbol_code_props_output (out, "printers", &symbol_printer_get);
495
496 muscles_m4_output (out);
497}
498\f
499/*---------------------------.
500| Call the skeleton parser. |
501`---------------------------*/
502
503static void
504output_skeleton (void)
505{
506 FILE *in;
507 int filter_fd[2];
508 char const *argv[10];
509 pid_t pid;
510
511 /* Compute the names of the package data dir and skeleton files. */
512 char const m4sugar[] = "m4sugar/m4sugar.m4";
513 char const m4bison[] = "bison.m4";
514 char *full_m4sugar;
515 char *full_m4bison;
516 char *full_skeleton;
517 char const *p;
518 char const *m4 = (p = getenv ("M4")) ? p : M4;
519 char const *pkgdatadir = compute_pkgdatadir ();
520 size_t skeleton_size = strlen (skeleton) + 1;
521 size_t pkgdatadirlen = strlen (pkgdatadir);
522 while (pkgdatadirlen && pkgdatadir[pkgdatadirlen - 1] == '/')
523 pkgdatadirlen--;
524 full_skeleton = xmalloc (pkgdatadirlen + 1
525 + (skeleton_size < sizeof m4sugar
526 ? sizeof m4sugar : skeleton_size));
527 memcpy (full_skeleton, pkgdatadir, pkgdatadirlen);
528 full_skeleton[pkgdatadirlen] = '/';
529 strcpy (full_skeleton + pkgdatadirlen + 1, m4sugar);
530 full_m4sugar = xstrdup (full_skeleton);
531 strcpy (full_skeleton + pkgdatadirlen + 1, m4bison);
532 full_m4bison = xstrdup (full_skeleton);
533 if (mbschr (skeleton, '/'))
534 strcpy (full_skeleton, skeleton);
535 else
536 strcpy (full_skeleton + pkgdatadirlen + 1, skeleton);
537
538 /* Test whether m4sugar.m4 is readable, to check for proper
539 installation. A faulty installation can cause deadlock, so a
540 cheap sanity check is worthwhile. */
541 xfclose (xfopen (full_m4sugar, "r"));
542
543 /* Create an m4 subprocess connected to us via two pipes. */
544
545 if (trace_flag & trace_tools)
546 fprintf (stderr, "running: %s %s - %s %s\n",
547 m4, full_m4sugar, full_m4bison, full_skeleton);
548
549 /* Some future version of GNU M4 (most likely 1.6) may treat the -dV in a
550 position-dependent manner. Keep it as the first argument so that all
551 files are traced.
552
553 See the thread starting at
554 <http://lists.gnu.org/archive/html/bug-bison/2008-07/msg00000.html>
555 for details. */
556 {
557 int i = 0;
558 argv[i++] = m4;
559
560 /* When POSIXLY_CORRECT is set, GNU M4 1.6 and later disable GNU
561 extensions, which Bison's skeletons depend on. With older M4,
562 it has no effect. M4 1.4.12 added a -g/--gnu command-line
563 option to make it explicit that a program wants GNU M4
564 extensions even when POSIXLY_CORRECT is set.
565
566 See the thread starting at
567 <http://lists.gnu.org/archive/html/bug-bison/2008-07/msg00000.html>
568 for details. */
569 if (*M4_GNU_OPTION)
570 argv[i++] = M4_GNU_OPTION;
571
572 argv[i++] = "-I";
573 argv[i++] = pkgdatadir;
574 if (trace_flag & trace_m4)
575 argv[i++] = "-dV";
576 argv[i++] = full_m4sugar;
577 argv[i++] = "-";
578 argv[i++] = full_m4bison;
579 argv[i++] = full_skeleton;
580 argv[i++] = NULL;
581 aver (i <= ARRAY_CARDINALITY (argv));
582 }
583
584 /* The ugly cast is because gnulib gets the const-ness wrong. */
585 pid = create_pipe_bidi ("m4", m4, (char **)(void*)argv, false, true,
586 true, filter_fd);
587 free (full_m4sugar);
588 free (full_m4bison);
589 free (full_skeleton);
590
591 if (trace_flag & trace_muscles)
592 muscles_output (stderr);
593 {
594 FILE *out = fdopen (filter_fd[1], "w");
595 if (! out)
596 error (EXIT_FAILURE, get_errno (),
597 "fdopen");
598 muscles_output (out);
599 xfclose (out);
600 }
601
602 /* Read and process m4's output. */
603 timevar_push (TV_M4);
604 in = fdopen (filter_fd[0], "r");
605 if (! in)
606 error (EXIT_FAILURE, get_errno (),
607 "fdopen");
608 scan_skel (in);
609 /* scan_skel should have read all of M4's output. Otherwise, when we
610 close the pipe, we risk letting M4 report a broken-pipe to the
611 Bison user. */
612 aver (feof (in));
613 xfclose (in);
614 wait_subprocess (pid, "m4", false, false, true, true, NULL);
615 timevar_pop (TV_M4);
616}
617
618static void
619prepare (void)
620{
621 /* BISON_USE_PUSH_FOR_PULL is for the test suite and should not be documented
622 for the user. */
623 char const *use_push_for_pull_env = getenv ("BISON_USE_PUSH_FOR_PULL");
624 bool use_push_for_pull_flag = false;
625 if (use_push_for_pull_env != NULL
626 && use_push_for_pull_env[0] != '\0'
627 && 0 != strcmp (use_push_for_pull_env, "0"))
628 use_push_for_pull_flag = true;
629
630 /* Flags. */
631 MUSCLE_INSERT_BOOL ("debug_flag", debug);
632 MUSCLE_INSERT_BOOL ("defines_flag", defines_flag);
633 MUSCLE_INSERT_BOOL ("error_verbose_flag", error_verbose);
634 MUSCLE_INSERT_BOOL ("glr_flag", glr_parser);
635 MUSCLE_INSERT_BOOL ("locations_flag", locations_flag);
636 MUSCLE_INSERT_BOOL ("nondeterministic_flag", nondeterministic_parser);
637 MUSCLE_INSERT_BOOL ("synclines_flag", !no_lines_flag);
638 MUSCLE_INSERT_BOOL ("tag_seen_flag", tag_seen);
639 MUSCLE_INSERT_BOOL ("token_table_flag", token_table_flag);
640 MUSCLE_INSERT_BOOL ("use_push_for_pull_flag", use_push_for_pull_flag);
641 MUSCLE_INSERT_BOOL ("yacc_flag", yacc_flag);
642
643 /* File names. */
644 if (spec_name_prefix)
645 MUSCLE_INSERT_STRING ("prefix", spec_name_prefix);
646
647 MUSCLE_INSERT_STRING ("file_name_all_but_ext", all_but_ext);
648
649#define DEFINE(Name) MUSCLE_INSERT_STRING (#Name, Name ? Name : "")
650 DEFINE (dir_prefix);
651 DEFINE (parser_file_name);
652 DEFINE (spec_defines_file);
653 DEFINE (spec_file_prefix);
654 DEFINE (spec_graph_file);
655 DEFINE (spec_name_prefix);
656 DEFINE (spec_outfile);
657 DEFINE (spec_verbose_file);
658#undef DEFINE
659
660 /* Find the right skeleton file, and add muscles about the skeletons. */
661 if (skeleton)
662 MUSCLE_INSERT_C_STRING ("skeleton", skeleton);
663 else
664 skeleton = language->skeleton;
665
666 /* About the skeletons. */
667 {
668 /* b4_pkgdatadir is used inside m4_include in the skeletons, so digraphs
669 would never be expanded. Hopefully no one has M4-special characters in
670 his Bison installation path. */
671 MUSCLE_INSERT_STRING_RAW ("pkgdatadir", compute_pkgdatadir ());
672 }
673}
674
675
676/*----------------------------------------------------------.
677| Output the parsing tables and the parser code to ftable. |
678`----------------------------------------------------------*/
679
680void
681output (void)
682{
683 obstack_init (&format_obstack);
684
685 prepare_symbols ();
686 prepare_rules ();
687 prepare_states ();
688 prepare_actions ();
689
690 prepare ();
691
692 /* Process the selected skeleton file. */
693 output_skeleton ();
694
695 obstack_free (&format_obstack, NULL);
696}
697
698char const *
699compute_pkgdatadir (void)
700{
701 char const *pkgdatadir = getenv ("BISON_PKGDATADIR");
702 return pkgdatadir ? pkgdatadir : PKGDATADIR;
703}