+ if (src_extension)
+ complain (_("multiple %%source_extension declarations"));
+ fscanf (finput, "%s", buff);
+ src_extension = xstrdup (buff);
+}
+
+/*----------------------------------------------------------------.
+| Read from finput until `%%' is seen. Discard the `%%'. Handle |
+| any `%' declarations, and copy the contents of any `%{ ... %}' |
+| groups to ATTRS_OBSTACK. |
+`----------------------------------------------------------------*/
+
+static void
+read_declarations (void)
+{
+ int c;
+ int tok;
+
+ for (;;)
+ {
+ c = skip_white_space ();
+
+ if (c == '%')
+ {
+ tok = parse_percent_token ();
+
+ switch (tok)
+ {
+ case tok_two_percents:
+ return;
+
+ case tok_percent_left_curly:
+ copy_definition ();
+ break;
+
+ case tok_token:
+ parse_token_decl (token_sym, nterm_sym);
+ break;
+
+ case tok_nterm:
+ parse_token_decl (nterm_sym, token_sym);
+ break;
+
+ case tok_type:
+ parse_type_decl ();
+ break;
+
+ case tok_start:
+ parse_start_decl ();
+ break;
+
+ case tok_union:
+ parse_union_decl ();
+ break;
+
+ case tok_expect:
+ parse_expect_decl ();
+ break;
+
+ case tok_thong:
+ parse_thong_decl ();
+ break;
+
+ case tok_left:
+ parse_assoc_decl (left_assoc);
+ break;
+
+ case tok_right:
+ parse_assoc_decl (right_assoc);
+ break;
+
+ case tok_nonassoc:
+ parse_assoc_decl (non_assoc);
+ break;
+
+ case tok_hdrext:
+ parse_header_extension_decl ();
+ break;
+
+ case tok_srcext:
+ parse_source_extension_decl ();
+ break;
+
+ case tok_define:
+ parse_macro_decl ();
+ break;
+
+ case tok_skel:
+ parse_skel_decl ();
+ break;
+
+ case tok_noop:
+ break;
+
+ default:
+ complain (_("unrecognized: %s"), token_buffer);
+ skip_to_char ('%');
+ }
+ }
+ else if (c == EOF)
+ fatal (_("no input grammar"));
+ else
+ {
+ char buf[] = "c";
+ buf[0] = c;
+ complain (_("unknown character: %s"), quote (buf));
+ skip_to_char ('%');
+ }
+ }
+}
+\f
+/*-------------------------------------------------------------------.
+| Assuming that a `{' has just been seen, copy everything up to the |
+| matching `}' into the actions file. STACK_OFFSET is the number of |
+| values in the current rule so far, which says where to find `$0' |
+| with respect to the top of the stack. |
+`-------------------------------------------------------------------*/
+
+static void
+copy_action (symbol_list *rule, int stack_offset)
+{
+ int c;
+ int count;
+ char buf[4096];
+
+ /* offset is always 0 if parser has already popped the stack pointer */
+ if (semantic_parser)
+ stack_offset = 0;
+
+ sprintf (buf, "\ncase %d:\n", nrules);
+ obstack_grow (&action_obstack, buf, strlen (buf));
+
+ if (!no_lines_flag)
+ {
+ sprintf (buf, "#line %d %s\n",
+ lineno, quotearg_style (c_quoting_style,
+ macro_find ("filename")));
+ obstack_grow (&action_obstack, buf, strlen (buf));
+ }
+ obstack_1grow (&action_obstack, '{');
+
+ count = 1;
+ c = getc (finput);
+
+ while (count > 0)
+ {
+ while (c != '}')
+ {
+ switch (c)
+ {
+ case '\n':
+ obstack_1grow (&action_obstack, c);
+ lineno++;
+ break;
+
+ case '{':
+ obstack_1grow (&action_obstack, c);
+ count++;
+ break;
+
+ case '\'':
+ case '"':
+ copy_string (finput, &action_obstack, c);
+ break;
+
+ case '/':
+ copy_comment (finput, &action_obstack);
+ break;
+
+ case '$':
+ copy_dollar (finput, &action_obstack,
+ rule, stack_offset);
+ break;
+
+ case '@':
+ copy_at (finput, &action_obstack,
+ stack_offset);
+ break;
+
+ case EOF:
+ fatal (_("unmatched %s"), "`{'");
+
+ default:
+ obstack_1grow (&action_obstack, c);
+ }