/[bison]/bison/src/reader.c
ViewVC logotype

Diff of /bison/src/reader.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.189 by akim, Tue Jun 11 08:08:36 2002 UTC revision 1.190 by akim, Tue Jun 11 20:16:05 2002 UTC
# Line 27  Line 27 
27  #include "files.h"  #include "files.h"
28  #include "symtab.h"  #include "symtab.h"
29  #include "options.h"  #include "options.h"
 #include "lex.h"  
30  #include "gram.h"  #include "gram.h"
31  #include "complain.h"  #include "complain.h"
32  #include "output.h"  #include "output.h"
# Line 35  Line 34 
34  #include "conflicts.h"  #include "conflicts.h"
35  #include "muscle_tab.h"  #include "muscle_tab.h"
36    
 typedef struct symbol_list  
 {  
   struct symbol_list *next;  
   symbol_t *sym;  
   int line;  
   
   /* The action is attached to the LHS of a rule. */  
   const char *action;  
   int action_line;  
   
   symbol_t *ruleprec;  
 } symbol_list;  
   
37  int lineno;  int lineno;
38  static symbol_list *grammar = NULL;  static symbol_list *grammar = NULL;
39  static int start_flag = 0;  static int start_flag = 0;
40    
41  /* Nonzero if %union has been seen.  */  /* Nonzero if %union has been seen.  */
42  static int typed = 0;  int typed = 0;
   
 /* Incremented for each %left, %right or %nonassoc seen */  
 static int lastprec = 0;  
43    
44  static symbol_list *  static symbol_list *
45  symbol_list_new (symbol_t *sym)  symbol_list_new (symbol_t *sym)
# Line 71  symbol_list_new (symbol_t *sym) Line 54  symbol_list_new (symbol_t *sym)
54    return res;    return res;
55  }  }
56    
 /*===================\  
 | Low level lexing.  |  
 \===================*/  
   
 static void  
 skip_to_char (int target)  
 {  
   int c;  
   if (target == '\n')  
     complain (_("   Skipping to next \\n"));  
   else  
     complain (_("   Skipping to next %c"), target);  
   
   do  
     c = skip_white_space ();  
   while (c != target && c != EOF);  
   if (c != EOF)  
     ungetc (c, finput);  
 }  
   
   
 /*---------------------------------------------------------.  
 | Read a signed integer from STREAM and return its value.  |  
 `---------------------------------------------------------*/  
   
 static inline int  
 read_signed_integer (FILE *stream)  
 {  
   int c = getc (stream);  
   int sign = 1;  
   int n = 0;  
   
   if (c == '-')  
     {  
       c = getc (stream);  
       sign = -1;  
     }  
   
   while (isdigit (c))  
     {  
       n = 10 * n + (c - '0');  
       c = getc (stream);  
     }  
   
   ungetc (c, stream);  
   
   return sign * n;  
 }  
57    
58  /*--------------------------------------------------------------.  /*--------------------------------------------------------------.
59  | Get the data type (alternative in the union) of the value for |  | Get the data type (alternative in the union) of the value for |
60  | symbol N in rule RULE.                                        |  | symbol N in rule RULE.                                        |
61  `--------------------------------------------------------------*/  `--------------------------------------------------------------*/
62    
63  static char *  char *
64  get_type_name (int n, symbol_list *rule)  get_type_name (int n, symbol_list *rule)
65  {  {
66    int i;    int i;
# Line 153  get_type_name (int n, symbol_list *rule) Line 88  get_type_name (int n, symbol_list *rule)
88    
89    return rp->sym->type_name;    return rp->sym->type_name;
90  }  }
   
 /*------------------------------------------------------------------.  
 | Copy the character C to OOUT, and insert quadigraphs when needed. |  
 `------------------------------------------------------------------*/  
   
 static inline void  
 copy_character (struct obstack *oout, int c)  
 {  
   switch (c)  
     {  
     case '[':  
       obstack_sgrow (oout, "@<:@");  
       break;  
   
     case ']':  
       obstack_sgrow (oout, "@:>@");  
       break;  
   
     default:  
       obstack_1grow (oout, c);  
     }  
 }  
   
 /*------------------------------------------------------------.  
 | Dump the string from FIN to OOUT if non null.  MATCH is the |  
 | delimiter of the string (either ' or ").                    |  
 `------------------------------------------------------------*/  
   
 static inline void  
 copy_string2 (FILE *fin, struct obstack *oout, int match, int store)  
 {  
   int c;  
   
   if (store)  
     obstack_1grow (oout, match);  
   
   c = getc (fin);  
   
   while (c != match)  
     {  
       if (c == EOF)  
         fatal (_("unterminated string at end of file"));  
       if (c == '\n')  
         {  
           complain (_("unterminated string"));  
           ungetc (c, fin);  
           c = match;            /* invent terminator */  
           continue;  
         }  
   
       copy_character (oout, c);  
   
       if (c == '\\')  
         {  
           c = getc (fin);  
           if (c == EOF)  
             fatal (_("unterminated string at end of file"));  
           copy_character (oout, c);  
   
           if (c == '\n')  
             ++lineno;  
         }  
   
       c = getc (fin);  
     }  
   
   if (store)  
     obstack_1grow (oout, c);  
 }  
   
 /* FIXME. */  
   
 static inline void  
 copy_string (FILE *fin, struct obstack *oout, int match)  
 {  
   copy_string2 (fin, oout, match, 1);  
 }  
   
 /* FIXME. */  
   
 static inline void  
 copy_identifier (FILE *fin, struct obstack *oout)  
 {  
   int c;  
   
   while (isalnum (c = getc (fin)) || c == '_')  
     obstack_1grow (oout, c);  
   
   ungetc (c, fin);  
 }  
   
   
 /*------------------------------------------------------------------.  
 | Dump the wannabee comment from IN to OOUT.  In fact we just saw a |  
 | `/', which might or might not be a comment.  In any case, copy    |  
 | what we saw.                                                      |  
 `------------------------------------------------------------------*/  
   
 static inline void  
 copy_comment (FILE *fin, struct obstack *oout)  
 {  
   int cplus_comment;  
   int ended;  
   int c;  
   
   /* We read a `/', output it. */  
   obstack_1grow (oout, '/');  
   
   switch ((c = getc (fin)))  
     {  
     case '/':  
       cplus_comment = 1;  
       break;  
     case '*':  
       cplus_comment = 0;  
       break;  
     default:  
       ungetc (c, fin);  
       return;  
     }  
   
   obstack_1grow (oout, c);  
   c = getc (fin);  
   
   ended = 0;  
   while (!ended)  
     {  
       if (!cplus_comment && c == '*')  
         {  
           while (c == '*')  
             {  
               obstack_1grow (oout, c);  
               c = getc (fin);  
             }  
   
           if (c == '/')  
             {  
               obstack_1grow (oout, c);  
               ended = 1;  
             }  
         }  
       else if (c == '\n')  
         {  
           ++lineno;  
           obstack_1grow (oout, c);  
           if (cplus_comment)  
             ended = 1;  
           else  
             c = getc (fin);  
         }  
       else if (c == EOF)  
         fatal (_("unterminated comment"));  
       else  
         {  
           copy_character (oout, c);  
           c = getc (fin);  
         }  
     }  
 }  
   
   
 /*-------------------------------------------------------------------.  
 | FIN is pointing to a location (i.e., a `@').  Output to OOUT a     |  
 | reference to this location. RULE_LENGTH 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 inline void  
 copy_at (FILE *fin, struct obstack *oout, int rule_length)  
 {  
   int c = getc (fin);  
   locations_flag = 1;  
   
   if (c == '$')  
     {  
       obstack_sgrow (oout, "]b4_lhs_location[");  
     }  
   else if (isdigit (c) || c == '-')  
     {  
       int n;  
   
       ungetc (c, fin);  
       n = read_signed_integer (fin);  
       if (n > rule_length)  
         complain (_("invalid value: %s%d"), "@", n);  
       else  
         obstack_fgrow2 (oout, "]b4_rhs_location([%d], [%d])[",  
                         rule_length, n);  
     }  
   else  
     {  
       char buf[] = "@c";  
       buf[1] = c;  
       complain (_("%s is invalid"), quote (buf));  
     }  
 }  
   
   
 /*------------------------------------------------------------------.  
 | FIN is pointing to a wannabee semantic value (i.e., a `$').       |  
 |                                                                   |  
 | Possible inputs: $[<TYPENAME>]($|integer)                         |  
 |                                                                   |  
 | Output to OOUT a reference to this semantic value. RULE_LENGTH 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 inline void  
 copy_dollar (FILE *fin, struct obstack *oout,  
              symbol_list *rule, int rule_length)  
 {  
   int c = getc (fin);  
   const char *type_name = NULL;  
   
   /* Get the type name if explicit. */  
   if (c == '<')  
     {  
       read_type_name (fin);  
       type_name = token_buffer;  
       c = getc (fin);  
     }  
   
   if (c == '$')  
     {  
       if (!type_name)  
         type_name = get_type_name (0, rule);  
       if (!type_name && typed)  
         complain (_("$$ of `%s' has no declared type"),  
                   rule->sym->tag);  
       if (!type_name)  
         type_name = "";  
       obstack_fgrow1 (oout,  
                       "]b4_lhs_value([%s])[", type_name);  
     }  
   else if (isdigit (c) || c == '-')  
     {  
       int n;  
       ungetc (c, fin);  
       n = read_signed_integer (fin);  
   
       if (n > rule_length)  
         complain (_("invalid value: %s%d"), "$", n);  
       else  
         {  
           if (!type_name && n > 0)  
             type_name = get_type_name (n, rule);  
           if (!type_name && typed)  
             complain (_("$%d of `%s' has no declared type"),  
                       n, rule->sym->tag);  
           if (!type_name)  
             type_name = "";  
           obstack_fgrow3 (oout, "]b4_rhs_value([%d], [%d], [%s])[",  
                           rule_length, n, type_name);  
         }  
     }  
   else  
     {  
       char buf[] = "$c";  
       buf[1] = c;  
       complain (_("%s is invalid"), quote (buf));  
     }  
 }  
   
 /*-------------------------------------------------------------------.  
 | Copy the contents of a `%{ ... %}' into the definitions file.  The |  
 | `%{' has already been read.  Return after reading the `%}'.        |  
 `-------------------------------------------------------------------*/  
   
 static void  
 copy_definition (struct obstack *oout)  
 {  
   int c;  
   /* -1 while reading a character if prev char was %. */  
   int after_percent;  
   
   if (!no_lines_flag)  
     {  
       obstack_fgrow2 (oout, muscle_find ("linef"),  
                       lineno, quotearg_style (c_quoting_style,  
                                               muscle_find ("filename")));  
     }  
91    
   after_percent = 0;  
   
   c = getc (finput);  
   
   for (;;)  
     {  
       switch (c)  
         {  
         case '\n':  
           obstack_1grow (oout, c);  
           ++lineno;  
           break;  
   
         case '%':  
           after_percent = -1;  
           break;  
   
         case '\'':  
         case '"':  
           copy_string (finput, oout, c);  
           break;  
   
         case '/':  
           copy_comment (finput, oout);  
           break;  
   
         case EOF:  
           fatal ("%s", _("unterminated `%{' definition"));  
   
         default:  
           copy_character (oout, c);  
         }  
92    
93        c = getc (finput);  /*-----------------------.
94    | Set the start symbol.  |
95    `-----------------------*/
96    
97        if (after_percent)  void
98          {  grammar_start_symbol_set (symbol_t *s)
           if (c == '}')  
             return;  
           obstack_1grow (oout, '%');  
         }  
       after_percent = 0;  
     }  
 }  
   
   
 /*------------------------------------------.  
 | Parse what comes after %token or %nterm.  |  
 `------------------------------------------*/  
   
 static void  
 parse_token_decl (symbol_class class)  
 {  
   token_t token = tok_undef;  
   char *typename = NULL;  
   
   /* The symbol being defined.  */  
   symbol_t *symbol = NULL;  
   
   /* After `%token' and `%nterm', any number of symbols maybe be  
      defined.  */  
   for (;;)  
     {  
       int tmp_char = ungetc (skip_white_space (), finput);  
   
       /* `%' (for instance from `%token', or from `%%' etc.) is the  
          only valid means to end this declaration.  */  
       if (tmp_char == '%')  
         return;  
       if (tmp_char == EOF)  
         fatal (_("Premature EOF after %s"), token_buffer);  
   
       token = lex ();  
       switch (token)  
         {  
         case tok_comma:  
           symbol = NULL;  
           break;  
   
         case tok_typename:  
           typename = xstrdup (token_buffer);  
           symbol = NULL;  
           break;  
   
         case tok_identifier:  
           if (*symval->tag == '\"' && symbol)  
             {  
               symbol_make_alias (symbol, symval, typename);  
               symbol = NULL;  
             }  
           else  
             {  
               symbol = symval;  
               symbol_class_set (symbol, class);  
               if (typename)  
                 symbol_type_set (symbol, typename);  
             }  
           break;  
   
         case tok_number:  
           symbol_user_token_number_set (symbol, numval);  
           break;  
   
         default:  
           complain (_("`%s' is invalid in %s"),  
                     token_buffer,  
                     (class == token_sym) ? "%token" : "%nterm");  
           skip_to_char ('%');  
         }  
     }  
   
 }  
   
   
 /*------------------------------.  
 | Parse what comes after %start |  
 `------------------------------*/  
   
 static void  
 parse_start_decl (void)  
99  {  {
100    if (start_flag)    if (start_flag)
101      complain (_("multiple %s declarations"), "%start");      complain (_("multiple %s declarations"), "%start");
   if (lex () != tok_identifier)  
     complain (_("invalid %s declaration"), "%start");  
102    else    else
103      {      {
104        start_flag = 1;        start_flag = 1;
105        startsymbol = symval;        startsymbol = s;
106      }      }
107  }  }
108    
 /*-----------------------------------------------------------.  
 | read in a %type declaration and record its information for |  
 | get_type_name to access                                    |  
 `-----------------------------------------------------------*/  
   
 static void  
 parse_type_decl (void)  
 {  
   char *name;  
   
   if (lex () != tok_typename)  
     {  
       complain ("%s", _("%type declaration has no <typename>"));  
       skip_to_char ('%');  
       return;  
     }  
   
   name = xstrdup (token_buffer);  
   
   for (;;)  
     {  
       token_t t;  
       int tmp_char = ungetc (skip_white_space (), finput);  
   
       if (tmp_char == '%')  
         return;  
       if (tmp_char == EOF)  
         fatal (_("Premature EOF after %s"), token_buffer);  
   
       t = lex ();  
   
       switch (t)  
         {  
         case tok_comma:  
         case tok_semicolon:  
           break;  
   
         case tok_identifier:  
           symbol_type_set (symval, name);  
           break;  
   
         default:  
           complain (_("invalid %%type declaration due to item: %s"),  
                     token_buffer);  
           skip_to_char ('%');  
         }  
     }  
 }  
   
   
109    
110  /*----------------------------------------------------------------.  /*----------------------------------------------------------------.
111  | Read in a %left, %right or %nonassoc declaration and record its |  | There are two prologues: one before %union, one after.  Augment |
112  | information.                                                    |  | the current one.                                                |
113  `----------------------------------------------------------------*/  `----------------------------------------------------------------*/
114    
115  static void  void
116  parse_assoc_decl (associativity assoc)  prologue_augment (const char *prologue, int location)
 {  
   char *name = NULL;  
   int prev = 0;  
   
   /* Assign a new precedence level, never 0.  */  
   ++lastprec;  
   
   for (;;)  
     {  
       token_t t;  
       int tmp_char = ungetc (skip_white_space (), finput);  
   
       if (tmp_char == '%')  
         return;  
       if (tmp_char == EOF)  
         fatal (_("Premature EOF after %s"), token_buffer);  
   
       t = lex ();  
   
       switch (t)  
         {  
         case tok_typename:  
           name = xstrdup (token_buffer);  
           break;  
   
         case tok_comma:  
           break;  
   
         case tok_identifier:  
           symbol_class_set (symval, token_sym);  
           symbol_precedence_set (symval, lastprec, assoc);  
           if (name)  
             symbol_type_set (symval, name);  
           break;  
   
         case tok_number:  
           if (prev == tok_identifier)  
             {  
               symbol_user_token_number_set (symval, numval);  
             }  
           else  
             {  
               complain  
                 (_("invalid text (%s) - number should be after identifier"),  
                  token_buffer);  
               skip_to_char ('%');  
             }  
           break;  
   
         case tok_semicolon:  
           return;  
   
         default:  
           complain (_("unexpected item: %s"), token_buffer);  
           skip_to_char ('%');  
         }  
   
       prev = t;  
     }  
 }  
   
   
   
 /*--------------------------------------------------------------.  
 | Copy the union declaration into the stype muscle              |  
 | (and fdefines),  where it is made into the definition of      |  
 | YYSTYPE, the type of elements of the parser value stack.      |  
 `--------------------------------------------------------------*/  
   
 static void  
 parse_union_decl (void)  
 {  
   int c;  
   int count = 0;  
   bool done = FALSE;  
   struct obstack union_obstack;  
   if (typed)  
     complain (_("multiple %s declarations"), "%union");  
   
   typed = 1;  
   
   MUSCLE_INSERT_INT ("stype_line", lineno);  
   obstack_init (&union_obstack);  
   obstack_sgrow (&union_obstack, "union");  
   
   while (!done)  
     {  
       c = xgetc (finput);  
   
       /* If C contains '/', it is output by copy_comment ().  */  
       if (c != '/')  
         obstack_1grow (&union_obstack, c);  
   
       switch (c)  
         {  
         case '\n':  
           ++lineno;  
           break;  
   
         case '/':  
           copy_comment (finput, &union_obstack);  
           break;  
   
         case '{':  
           ++count;  
           break;  
   
         case '}':  
           /* FIXME: Errr.  How could this happen???. --akim */  
           if (count == 0)  
             complain (_("unmatched %s"), "`}'");  
           count--;  
           if (!count)  
             done = TRUE;  
           break;  
         }  
     }  
   
   /* JF don't choke on trailing semi */  
   c = skip_white_space ();  
   if (c != ';')  
     ungetc (c, finput);  
   obstack_1grow (&union_obstack, 0);  
   muscle_insert ("stype", obstack_finish (&union_obstack));  
 }  
   
   
 /*-------------------------------------------------------.  
 | Parse the declaration %expect N which says to expect N |  
 | shift-reduce conflicts.                                |  
 `-------------------------------------------------------*/  
   
 static void  
 parse_expect_decl (void)  
 {  
   int c = skip_white_space ();  
   ungetc (c, finput);  
   
   if (!isdigit (c))  
     complain (_("argument of %%expect is not an integer"));  
   else  
     expected_conflicts = read_signed_integer (finput);  
 }  
   
   
 static void  
 parse_muscle_decl (void)  
117  {  {
118    int ch = ungetc (skip_white_space (), finput);    struct obstack *oout =
119    char *muscle_key;      !typed ? &pre_prologue_obstack : &post_prologue_obstack;
   char *muscle_value;  
120    
121    /* Read key. */    if (!no_lines_flag)
   if (!isalpha (ch) && ch != '_')  
     {  
       complain (_("invalid %s declaration"), "%define");  
       skip_to_char ('%');  
       return;  
     }  
   copy_identifier (finput, &muscle_obstack);  
   obstack_1grow (&muscle_obstack, 0);  
   muscle_key = obstack_finish (&muscle_obstack);  
   
   /* Read value. */  
   ch = skip_white_space ();  
   if (ch != '"')  
122      {      {
123        ungetc (ch, finput);        obstack_fgrow2 (oout, muscle_find ("linef"),
124        if (ch != EOF)                        location, quotearg_style (c_quoting_style,
125          {                                                  muscle_find ("filename")));
           complain (_("invalid %s declaration"), "%define");  
           skip_to_char ('%');  
           return;  
         }  
       else  
         fatal (_("Premature EOF after %s"), "\"");  
126      }      }
127    copy_string2 (finput, &muscle_obstack, '"', 0);    obstack_sgrow (oout, prologue);
   obstack_1grow (&muscle_obstack, 0);  
   muscle_value = obstack_finish (&muscle_obstack);  
   
   /* Store the (key, value) pair in the environment. */  
   muscle_insert (muscle_key, muscle_value);  
128  }  }
129    
130    
131    
 /*---------------------------------.  
 | Parse a double quoted parameter. |  
 `---------------------------------*/  
   
 static const char *  
 parse_dquoted_param (const char *from)  
 {  
   struct obstack param_obstack;  
   const char *param = NULL;  
   int c;  
   
   obstack_init (&param_obstack);  
   c = skip_white_space ();  
   
   if (c != '"')  
     {  
       complain (_("invalid %s declaration"), from);  
       ungetc (c, finput);  
       skip_to_char ('%');  
       return NULL;  
     }  
   
   while ((c = literalchar ()) != '"')  
     obstack_1grow (&param_obstack, c);  
   
   obstack_1grow (&param_obstack, '\0');  
   param = obstack_finish (&param_obstack);  
   
   if (c != '"' || strlen (param) == 0)  
     {  
       complain (_("invalid %s declaration"), from);  
       if (c != '"')  
         ungetc (c, finput);  
       skip_to_char ('%');  
       return NULL;  
     }  
   
   return param;  
 }  
132    
133  /*----------------------------------.  /*----------------------.
134  | Parse what comes after %skeleton. |  | Handle the epilogue.  |
135  `----------------------------------*/  `----------------------*/
136    
137  static void  void
138  parse_skel_decl (void)  epilogue_set (const char *epilogue, int location)
139  {  {
140    skeleton = parse_dquoted_param ("%skeleton");    struct obstack el_obstack;
141  }    obstack_init (&el_obstack);
   
 /*----------------------------------------------------------------.  
 | Read from finput until `%%' is seen.  Discard the `%%'.  Handle |  
 | any `%' declarations, and copy the contents of any `%{ ... %}'  |  
 | groups to PRE_PROLOGUE_OBSTACK or POST_PROLOGUE_OBSTACK.        |  
 `----------------------------------------------------------------*/  
142    
143  static void    if (!no_lines_flag)
 read_declarations (void)  
 {  
   for (;;)  
144      {      {
145        int c = skip_white_space ();        obstack_fgrow2 (&el_obstack, muscle_find ("linef"),
146                          location, quotearg_style (c_quoting_style,
147        if (c == '%')                                                  muscle_find ("filename")));
         {  
           token_t tok = parse_percent_token ();  
   
           switch (tok)  
             {  
             case tok_two_percents:  
               return;  
   
             case tok_percent_left_curly:  
               if (!typed)  
                 copy_definition (&pre_prologue_obstack);  
               else  
                 copy_definition (&post_prologue_obstack);  
               break;  
   
             case tok_token:  
               parse_token_decl (token_sym);  
               break;  
   
             case tok_nterm:  
               parse_token_decl (nterm_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_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_define:  
               parse_muscle_decl ();  
               break;  
   
             case tok_skel:  
               parse_skel_decl ();  
               break;  
   
             case tok_noop:  
               break;  
   
             case tok_stropt:  
             case tok_intopt:  
             case tok_obsolete:  
               assert (0);  
               break;  
   
             case tok_illegal:  
             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 ('%');  
         }  
148      }      }
149      obstack_sgrow (&el_obstack, epilogue);
150      obstack_1grow (&el_obstack, 0);
151      muscle_insert ("epilogue", obstack_finish (&el_obstack));
152  }  }
   
 /*------------------------------------------------------------------.  
 | Assuming that a `{' has just been seen, copy everything up to the |  
 | matching `}' into ACTION_OBSTACK, and return a pointer to this    |  
 | action.                                                           |  
 `------------------------------------------------------------------*/  
153    
 static char *  
 parse_action (symbol_list *rule)  
 {  
   int count = 1;  
   
   /* RULE_LENGTH 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.  It is not the same as the rule->length in the case of mid  
      rule actions.  */  
   int rule_length = 0;  
   symbol_list *rhs;  
   for (rhs = rule->next; rhs; rhs = rhs->next)  
     ++rule_length;  
   
   while (count > 0)  
     {  
       int c;  
       while ((c = getc (finput)) != '}')  
         switch (c)  
           {  
           case '\n':  
             copy_character (&action_obstack, c);  
             ++lineno;  
             break;  
   
           case '{':  
             copy_character (&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, rule_length);  
             break;  
   
           case '@':  
             copy_at (finput, &action_obstack, rule_length);  
             break;  
   
           case EOF:  
             fatal (_("unmatched %s"), "`{'");  
   
           default:  
             copy_character (&action_obstack, c);  
           }  
   
       /* Above loop exits when C is '}'.  */  
       if (--count)  
         copy_character (&action_obstack, c);  
     }  
   
   obstack_1grow (&action_obstack, '\0');  
   return obstack_finish (&action_obstack);  
 }  
154    
155    
156    
# Line 1050  gensym (void) Line 169  gensym (void)
169    symbol_t *sym;    symbol_t *sym;
170    
171    sprintf (buf, "@%d", ++gensym_count);    sprintf (buf, "@%d", ++gensym_count);
172    token_buffer = buf;    sym = getsym (buf);
   sym = getsym (token_buffer);  
173    sym->class = nterm_sym;    sym->class = nterm_sym;
174    sym->number = nvars++;    sym->number = nvars++;
175    return sym;    return sym;
# Line 1079  gensym (void) Line 197  gensym (void)
197  symbol_list *grammar_end = NULL;  symbol_list *grammar_end = NULL;
198    
199  /* Append S to the GRAMMAR. */  /* Append S to the GRAMMAR. */
200  static void  void
201  grammar_symbol_append (symbol_t *s)  grammar_symbol_append (symbol_t *s)
202  {  {
203    symbol_list *p = symbol_list_new (s);    symbol_list *p = symbol_list_new (s);
# Line 1100  symbol_list *previous_rule = NULL; Line 218  symbol_list *previous_rule = NULL;
218    
219  /* Create a new rule for LHS in to the GRAMMAR. */  /* Create a new rule for LHS in to the GRAMMAR. */
220    
221  static void  void
222  grammar_rule_begin (symbol_t *lhs)  grammar_rule_begin (symbol_t *lhs)
223  {  {
224    if (!start_flag)    if (!start_flag)
# Line 1129  grammar_rule_begin (symbol_t *lhs) Line 247  grammar_rule_begin (symbol_t *lhs)
247      complain (_("rule given for %s, which is a token"), lhs->tag);      complain (_("rule given for %s, which is a token"), lhs->tag);
248  }  }
249    
250    /* Check that the last rule (CURRENT_RULE) is properly defined.  For
251       instance, there should be no type clash on the default action.  */
252    
253    static void
254    grammar_current_rule_check (void)
255    {
256      symbol_t *lhs = current_rule->sym;
257      symbol_t *first_rhs = current_rule->next->sym;
258    
259      /* If there is an action, then there is nothing we can do: the user
260         is allowed to shoot in her foot.  */
261      if (current_rule->action)
262        return;
263    
264      /* If $$ is being set in default way, report if any type mismatch.
265         */
266      if (first_rhs)
267        {
268          const char *lhs_type = lhs->type_name       ? lhs->type_name       : "";
269          const char *rhs_type = first_rhs->type_name ? first_rhs->type_name : "";
270          if (strcmp (lhs_type, rhs_type))
271            complain (_("type clash (`%s' `%s') on default action"),
272                      lhs_type, rhs_type);
273        }
274      /* Warn if there is no default for $$ but we need one.  */
275      else
276        {
277          if (lhs->type_name)
278            complain (_("empty rule for typed nonterminal, and no action"));
279        }
280    }
281    
282    
283    /* End the currently being grown rule. */
284    
285    void
286    grammar_rule_end (void)
287    {
288      /* Put an empty link in the list to mark the end of this rule  */
289      grammar_symbol_append (NULL);
290      grammar_current_rule_check ();
291    }
292    
293    
294  /* The previous action turns out the be a mid-rule action.  Attach it  /* The previous action turns out the be a mid-rule action.  Attach it
295     to the current rule, i.e., create a dummy symbol, attach it this     to the current rule, i.e., create a dummy symbol, attach it this
296     mid-rule action, and append this dummy nonterminal to the current     mid-rule action, and append this dummy nonterminal to the current
297     rule.  */     rule.  */
298    
299  static void  void
300  grammar_midrule_action (void)  grammar_midrule_action (void)
301  {  {
302    /* Since the action was written out with this rule's number, we must    /* Since the action was written out with this rule's number, we must
# Line 1174  grammar_midrule_action (void) Line 336  grammar_midrule_action (void)
336    
337  /* Set the precedence symbol of the current rule to PRECSYM. */  /* Set the precedence symbol of the current rule to PRECSYM. */
338    
339  static void  void
340  grammar_current_rule_prec_set (symbol_t *precsym)  grammar_current_rule_prec_set (symbol_t *precsym)
341  {  {
342    if (current_rule->ruleprec)    if (current_rule->ruleprec)
# Line 1182  grammar_current_rule_prec_set (symbol_t Line 344  grammar_current_rule_prec_set (symbol_t
344    current_rule->ruleprec = precsym;    current_rule->ruleprec = precsym;
345  }  }
346    
 /* Check that the last rule (CURRENT_RULE) is properly defined.  For  
    instance, there should be no type clash on the default action.  */  
   
 static void  
 grammar_current_rule_check (void)  
 {  
   symbol_t *lhs = current_rule->sym;  
   symbol_t *first_rhs = current_rule->next->sym;  
   
   /* If there is an action, then there is nothing we can do: the user  
      is allowed to shoot in her foot.  */  
   if (current_rule->action)  
     return;  
   
   /* If $$ is being set in default way, report if any type mismatch.  
      */  
   if (first_rhs)  
     {  
       const char *lhs_type = lhs->type_name       ? lhs->type_name       : "";  
       const char *rhs_type = first_rhs->type_name ? first_rhs->type_name : "";  
       if (strcmp (lhs_type, rhs_type))  
         complain (_("type clash (`%s' `%s') on default action"),  
                   lhs_type, rhs_type);  
     }  
   /* Warn if there is no default for $$ but we need one.  */  
   else  
     {  
       if (lhs->type_name)  
         complain (_("empty rule for typed nonterminal, and no action"));  
     }  
 }  
   
   
347  /* Attach a SYMBOL to the current rule.  If needed, move the previous  /* Attach a SYMBOL to the current rule.  If needed, move the previous
348     action as a mid-rule action.  */     action as a mid-rule action.  */
349    
350  static void  void
351  grammar_current_rule_symbol_append (symbol_t *symbol)  grammar_current_rule_symbol_append (symbol_t *symbol)
352  {  {
353    if (current_rule->action)    if (current_rule->action)
# Line 1231  grammar_current_rule_symbol_append (symb Line 360  grammar_current_rule_symbol_append (symb
360  /* Attach an ACTION to the current rule.  If needed, move the previous  /* Attach an ACTION to the current rule.  If needed, move the previous
361     action as a mid-rule action.  */     action as a mid-rule action.  */
362    
363  static void  void
364  grammar_current_rule_action_append (char *action, int action_line)  grammar_current_rule_action_append (const char *action, int action_line)
365  {  {
366    if (current_rule->action)    if (current_rule->action)
367      grammar_midrule_action ();      grammar_midrule_action ();
# Line 1240  grammar_current_rule_action_append (char Line 369  grammar_current_rule_action_append (char
369    current_rule->action_line = action_line;    current_rule->action_line = action_line;
370  }  }
371    
   
   
 static void  
 readgram (void)  
 {  
   token_t t;  
   symbol_t *lhs = NULL;  
   
   t = lex ();  
   
   while (t != tok_two_percents && t != tok_eof)  
     if (t == tok_identifier || t == tok_bar)  
       {  
         if (t == tok_identifier)  
           {  
             lhs = symval;  
   
             t = lex ();  
             if (t != tok_colon)  
               {  
                 complain (_("ill-formed rule: initial symbol not followed by colon"));  
                 unlex (t);  
               }  
           }  
         if (nrules == 0 && t == tok_bar)  
           {  
             complain (_("grammar starts with vertical bar"));  
             lhs = symval;       /* BOGUS: use a random symval */  
           }  
   
         grammar_rule_begin (lhs);  
         /* read the rhs of the rule.  */  
   
         for (;;)  
           {  
             t = lex ();  
             if (t == tok_prec)  
               {  
                 t = lex ();  
                 grammar_current_rule_prec_set (symval);  
                 t = lex ();  
               }  
   
             if (!(t == tok_identifier || t == tok_left_curly))  
               break;  
   
             /* If next token is an identifier, see if a colon follows it.  
                If one does, exit this rule now.  */  
             if (t == tok_identifier)  
               {  
                 symbol_t *ssave;  
                 token_t t1;  
   
                 ssave = symval;  
                 t1 = lex ();  
                 unlex (t1);  
                 symval = ssave;  
                 if (t1 == tok_colon)  
                   {  
                     warn (_("previous rule lacks an ending `;'"));  
                     break;  
                   }  
                 /* Not followed by colon => process as part of this  
                    rule's rhs.  */  
               }  
   
             if (t == tok_identifier)  
               {  
                 grammar_current_rule_symbol_append (symval);  
               }  
             else                /* handle an action.  */  
               {  
                 int action_line = lineno;  
                 char *action = parse_action (current_rule);  
                 grammar_current_rule_action_append (action, action_line);  
               }  
           }                     /* end of  read rhs of rule */  
   
         /* Put an empty link in the list to mark the end of this rule  */  
         grammar_symbol_append (NULL);  
   
         if (t == tok_prec)  
           {  
             t = lex ();  
             grammar_current_rule_prec_set (symval);  
             t = lex ();  
           }  
   
         if (t == tok_left_curly)  
           {  
             int action_line = lineno;  
             char *action = parse_action (current_rule);  
             grammar_current_rule_action_append (action, action_line);  
             t = lex ();  
           }  
   
         grammar_current_rule_check ();  
   
         if (t == tok_two_percents || t == tok_eof)  
           warn (_("previous rule lacks an ending `;'"));  
         if (t == tok_semicolon)  
           t = lex ();  
       }  
     else  
       {  
         complain (_("invalid input: %s"), quote (token_buffer));  
         t = lex ();  
       }  
   
   /* grammar has been read.  Do some checking */  
   
   if (nrules == 0)  
     fatal (_("no rules in the input grammar"));  
   
   /* Report any undefined symbols and consider them nonterminals.  */  
   symbols_check_defined ();  
   
   /* Insert the initial rule, which line is that of the first rule  
      (not that of the start symbol):  
   
      axiom: %start EOF.  */  
   {  
     symbol_list *p = symbol_list_new (axiom);  
     p->line = grammar->line;  
     p->next = symbol_list_new (startsymbol);  
     p->next->next = symbol_list_new (eoftoken);  
     p->next->next->next = symbol_list_new (NULL);  
     p->next->next->next->next = grammar;  
     nrules += 1;  
     nritems += 3;  
     grammar = p;  
   }  
   
   if (nsyms > SHRT_MAX)  
     fatal (_("too many symbols (tokens plus nonterminals); maximum %d"),  
            SHRT_MAX);  
   
   assert (nsyms == ntokens + nvars);  
 }  
   
 /* At the end of the grammar file, some C source code must  
    be stored. It is going to be associated to the epilogue  
    directive.  */  
 static void  
 read_additionnal_code (void)  
 {  
   int c;  
   struct obstack el_obstack;  
   
   obstack_init (&el_obstack);  
   
   if (!no_lines_flag)  
     {  
       obstack_fgrow2 (&el_obstack, muscle_find ("linef"),  
                       lineno, quotearg_style (c_quoting_style,  
                                               muscle_find ("filename")));  
     }  
   
   while ((c = getc (finput)) != EOF)  
     copy_character (&el_obstack, c);  
   
   obstack_1grow (&el_obstack, 0);  
   muscle_insert ("epilogue", obstack_finish (&el_obstack));  
 }  
   
372    
373  /*---------------------------------------------------------------.  /*---------------------------------------------------------------.
374  | Convert the rules into the representation using RRHS, RLHS and |  | Convert the rules into the representation using RRHS, RLHS and |
# Line 1481  packgram (void) Line 445  packgram (void)
445  void  void
446  reader (void)  reader (void)
447  {  {
448    lex_init ();    gram_control_t gram_control;
449    lineno = 1;    lineno = 1;
450    
451    /* Initialize the muscle obstack.  */    /* Initialize the muscle obstack.  */
# Line 1513  reader (void) Line 477  reader (void)
477    obstack_init (&post_prologue_obstack);    obstack_init (&post_prologue_obstack);
478    
479    finput = xfopen (infile, "r");    finput = xfopen (infile, "r");
480      gram_in = finput;
481    
482      gram_debug = !!getenv ("parse");
483      gram__flex_debug = !!getenv ("scan");
484      gram_parse (&gram_control);
485    
486    /* Read the declaration section.  Copy %{ ... %} groups to    /* Grammar has been read.  Do some checking */
487       TABLE_OBSTACK and FDEFINES file.  Also notice any %token, %left,    if (nrules == 0)
488       etc. found there.  */      fatal (_("no rules in the input grammar"));
489    read_declarations ();  
490      /* Report any undefined symbols and consider them nonterminals.  */
491      symbols_check_defined ();
492    
493    /* If the user did not define her EOFTOKEN, do it now. */    /* If the user did not define her EOFTOKEN, do it now. */
494    if (!eoftoken)    if (!eoftoken)
# Line 1529  reader (void) Line 500  reader (void)
500        eoftoken->user_token_number = 0;        eoftoken->user_token_number = 0;
501      }      }
502    
503    /* Read in the grammar, build grammar in list form.  Write out    /* Insert the initial rule, which line is that of the first rule
504       actions.  */       (not that of the start symbol):
505    readgram ();  
506    /* Some C code is given at the end of the grammar file. */       axiom: %start EOF.  */
507    read_additionnal_code ();    {
508        symbol_list *p = symbol_list_new (axiom);
509        p->line = grammar->line;
510        p->next = symbol_list_new (startsymbol);
511        p->next->next = symbol_list_new (eoftoken);
512        p->next->next->next = symbol_list_new (NULL);
513        p->next->next->next->next = grammar;
514        nrules += 1;
515        nritems += 3;
516        grammar = p;
517      }
518    
519      if (nsyms > SHRT_MAX)
520        fatal (_("too many symbols (tokens plus nonterminals); maximum %d"),
521              SHRT_MAX);
522    
523      assert (nsyms == ntokens + nvars);
524    
   lex_free ();  
525    xfclose (finput);    xfclose (finput);
526    
527    /* Assign the symbols their symbol numbers.  Write #defines for the    /* Assign the symbols their symbol numbers.  Write #defines for the

Legend:
Removed from v.1.189  
changed lines
  Added in v.1.190

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26