OSDN Git Service

* cpplib.c (dtable): Update.
authorneil <neil@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 18 Jun 2002 06:27:40 +0000 (06:27 +0000)
committerneil <neil@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 18 Jun 2002 06:27:40 +0000 (06:27 +0000)
(end_directive): Decrement expansion prevention count.
Clear state.in_expression.
(prepare_directive_trad): Set state.in_expression.
Increment expansion prevention count.
* cpptrad.c (enum ls): New.
(_cpp_overlay_buffer): Set overlaid_buffer.
(_cpp_remove_overlay): Use overlaid_buffer.
(_cpp_read_logcial_line_trad): Update buffer when it might
have changed.
(scan_out_logical_line): Handle state transitions for assertions
and defined() in #if, and for funlike invocations including the
directive case.  Handle '<' and '>' as a quote mechanism in
#include.  Warn about unterminated macro invocations.
* cpphash.h (struct lexer_state): New member in_expression.
(struct cpp_reader): New member overlaid buffer.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@54732 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/cpphash.h
gcc/cpplib.c
gcc/cpptrad.c

index 6247025..4f1c3de 100644 (file)
@@ -1,3 +1,22 @@
+2002-06-18  Neil Booth  <neil@daikokuya.demon.co.uk>
+
+       * cpplib.c (dtable): Update.
+       (end_directive): Decrement expansion prevention count.
+       Clear state.in_expression.
+       (prepare_directive_trad): Set state.in_expression.
+       Increment expansion prevention count.
+       * cpptrad.c (enum ls): New.
+       (_cpp_overlay_buffer): Set overlaid_buffer.
+       (_cpp_remove_overlay): Use overlaid_buffer.
+       (_cpp_read_logcial_line_trad): Update buffer when it might
+       have changed.
+       (scan_out_logical_line): Handle state transitions for assertions
+       and defined() in #if, and for funlike invocations including the
+       directive case.  Handle '<' and '>' as a quote mechanism in
+       #include.  Warn about unterminated macro invocations.
+       * cpphash.h (struct lexer_state): New member in_expression.
+       (struct cpp_reader): New member overlaid buffer.
+
 2002-06-18  Hans-Peter Nilsson  <hp@axis.com>
 
        * config/cris/arit.c (do_31div, __Udiv, __Umod): Mark prototype
index 60340d9..98dfb49 100644 (file)
@@ -211,6 +211,9 @@ struct lexer_state
   /* Nonzero if in a directive that takes angle-bracketed headers.  */
   unsigned char angled_headers;
 
+  /* Nonzero if in a #if or #elif directive.  */
+  unsigned char in_expression;
+
   /* Nonzero to save comments.  Turned off if discard_comments, and in
      all directives apart from #define.  */
   unsigned char save_comments;
@@ -309,6 +312,9 @@ struct cpp_reader
   /* Top of buffer stack.  */
   cpp_buffer *buffer;
 
+  /* Overlaid buffer (can be different after processing #include).  */
+  cpp_buffer *overlaid_buffer;
+
   /* Lexer state.  */
   struct lexer_state state;
 
index aecfbaf..4ee97e8 100644 (file)
@@ -72,9 +72,7 @@ struct pragma_entry
    means this directive should be handled even if -fpreprocessed is in
    effect (these are the directives with callback hooks).
 
-   EXPAND is set on directives that are always macro-expanded.  If
-   INCL is set, macro expansion is special-cased and EXPAND should not
-   be set.  */
+   EXPAND is set on directives that are always macro-expanded.  */
 #define COND           (1 << 0)
 #define IF_COND                (1 << 1)
 #define INCL           (1 << 2)
@@ -147,7 +145,7 @@ static void handle_assertion        PARAMS ((cpp_reader *, const char *, int));
 
 #define DIRECTIVE_TABLE                                                        \
 D(define,      T_DEFINE = 0,   KANDR,     IN_I)           /* 270554 */ \
-D(include,     T_INCLUDE,      KANDR,     INCL)           /*  52262 */ \
+D(include,     T_INCLUDE,      KANDR,     INCL | EXPAND)  /*  52262 */ \
 D(endif,       T_ENDIF,        KANDR,     COND)           /*  45855 */ \
 D(ifdef,       T_IFDEF,        KANDR,     COND | IF_COND) /*  22000 */ \
 D(if,          T_IF,           KANDR, COND | IF_COND | EXPAND) /*  18162 */ \
@@ -159,9 +157,9 @@ D(elif,             T_ELIF,         STDC89,    COND | EXPAND)  /*    610 */ \
 D(error,       T_ERROR,        STDC89,    0)              /*    475 */ \
 D(pragma,      T_PRAGMA,       STDC89,    IN_I)           /*    195 */ \
 D(warning,     T_WARNING,      EXTENSION, 0)              /*     22 */ \
-D(include_next,        T_INCLUDE_NEXT, EXTENSION, INCL)           /*     19 */ \
+D(include_next,        T_INCLUDE_NEXT, EXTENSION, INCL | EXPAND)  /*     19 */ \
 D(ident,       T_IDENT,        EXTENSION, IN_I)           /*     11 */ \
-D(import,      T_IMPORT,       EXTENSION, INCL)           /* 0 ObjC */ \
+D(import,      T_IMPORT,       EXTENSION, INCL | EXPAND)  /* 0 ObjC */ \
 D(assert,      T_ASSERT,       EXTENSION, 0)              /* 0 SVR4 */ \
 D(unassert,    T_UNASSERT,     EXTENSION, 0)              /* 0 SVR4 */ \
 SCCS_ENTRY                                                /* 0 SVR4? */
@@ -256,6 +254,9 @@ end_directive (pfile, skip_line)
 {
   if (CPP_OPTION (pfile, traditional))
     {
+      /* Revert change of prepare_directive_trad.  */
+      pfile->state.prevent_expansion--;
+
       if (pfile->directive != &dtable[T_DEFINE])
        _cpp_remove_overlay (pfile);
     }
@@ -273,6 +274,7 @@ end_directive (pfile, skip_line)
   /* Restore state.  */
   pfile->state.save_comments = ! CPP_OPTION (pfile, discard_comments);
   pfile->state.in_directive = 0;
+  pfile->state.in_expression = 0;
   pfile->state.angled_headers = 0;
   pfile->directive = 0;
 }
@@ -291,6 +293,8 @@ prepare_directive_trad (pfile)
       bool was_skipping = pfile->state.skipping;
 
       pfile->state.skipping = false;
+      pfile->state.in_expression = (pfile->directive == &dtable[T_IF]
+                                   || pfile->directive == &dtable[T_ELIF]);
       if (no_expand)
        pfile->state.prevent_expansion++;
       _cpp_read_logical_line_trad (pfile);
@@ -300,6 +304,9 @@ prepare_directive_trad (pfile)
       _cpp_overlay_buffer (pfile, pfile->out.base,
                           pfile->out.cur - pfile->out.base);
     }
+
+  /* Stop ISO C from expanding anything.  */
+  pfile->state.prevent_expansion++;
 }
 
 /* Output diagnostics for a directive DIR.  INDENTED is non-zero if
index 69b7e17..b29750d 100644 (file)
@@ -63,6 +63,15 @@ struct fun_macro
   unsigned int argc;
 };
 
+/* Lexing state.  It is mostly used to prevent macro expansion.  */
+enum ls {ls_none = 0,          /* Normal state.  */
+        ls_fun_macro,          /* When looking for '('.  */
+        ls_defined,            /* After defined.  */
+        ls_defined_close,      /* Looking for ')' of defined().  */
+        ls_hash,               /* After # in preprocessor conditional.  */
+        ls_predicate,          /* After the predicate, maybe paren?  */
+        ls_answer};            /* In answer to predicate.  */
+
 /* Lexing TODO: Maybe handle space in escaped newlines.  Stop cpplex.c
    from recognizing comments and directives during its lexing pass.  */
 
@@ -322,6 +331,7 @@ _cpp_overlay_buffer (pfile, start, len)
 {
   cpp_buffer *buffer = pfile->buffer;
 
+  pfile->overlaid_buffer = buffer;
   buffer->saved_cur = buffer->cur;
   buffer->saved_rlimit = buffer->rlimit;
 
@@ -336,7 +346,7 @@ void
 _cpp_remove_overlay (pfile)
      cpp_reader *pfile;
 {
-  cpp_buffer *buffer = pfile->buffer;
+  cpp_buffer *buffer = pfile->overlaid_buffer;
 
   buffer->cur = buffer->saved_cur;
   buffer->rlimit = buffer->saved_rlimit;
@@ -363,6 +373,7 @@ _cpp_read_logical_line_trad (pfile)
            {
              stop = buffer->return_at_eof;
              _cpp_pop_buffer (pfile);
+             buffer = pfile->buffer;
            }
 
          if (stop)
@@ -372,6 +383,7 @@ _cpp_read_logical_line_trad (pfile)
       CUR (pfile->context) = buffer->cur;
       RLIMIT (pfile->context) = buffer->rlimit;
       scan_out_logical_line (pfile, NULL);
+      buffer = pfile->buffer;
       buffer->cur = CUR (pfile->context);
     }
   while (pfile->state.skipping);
@@ -426,9 +438,10 @@ scan_out_logical_line (pfile, macro)
 {
   cpp_context *context;
   const uchar *cur;
-  unsigned int c, paren_depth = 0, quote = 0;
   uchar *out;
   struct fun_macro fmacro;
+  unsigned int c, paren_depth = 0, quote = 0;
+  enum ls lex_state = ls_none;
 
   fmacro.buff = NULL;
 
@@ -446,13 +459,19 @@ scan_out_logical_line (pfile, macro)
       c = *cur++;
       *out++ = c;
 
-      /* There are only a few entities we need to catch: comments,
-        identifiers, newlines, escaped newlines, # and '\0'.  */
+      /* Whitespace should "continue" out of the switch,
+        non-whitespace should "break" out of it.  */
       switch (c)
        {
+       case ' ':
+       case '\t':
+       case '\f':
+       case '\v':
+         continue;
+
        case '\0':
          if (cur - 1 != RLIMIT (context))
-           break;
+           continue;
 
          /* If this is a macro's expansion, pop it.  */
          if (context->prev)
@@ -475,7 +494,7 @@ scan_out_logical_line (pfile, macro)
 
        case '\r': case '\n':
          cur = handle_newline (pfile, cur - 1);
-         if (pfile->state.parsing_args == 2)
+         if (pfile->state.parsing_args == 2 && !pfile->state.in_directive)
            {
              /* Newlines in arguments become a space.  */
              out[-1] = ' ';
@@ -483,6 +502,18 @@ scan_out_logical_line (pfile, macro)
            }
          goto done;
 
+       case '<':
+         if (pfile->state.angled_headers && !quote)
+           quote = '>';
+         break;
+       case '>':
+         if (pfile->state.angled_headers && c == quote)
+           {
+             pfile->state.angled_headers = false;
+             quote = 0;
+           }
+         break;
+
        case '"':
        case '\'':
          if (c == quote)
@@ -493,7 +524,11 @@ scan_out_logical_line (pfile, macro)
 
        case '\\':
          if (is_vspace (*cur))
-           out--, cur = skip_escaped_newlines (pfile, cur - 1);
+           {
+             out--;
+             cur = skip_escaped_newlines (pfile, cur - 1);
+             continue;
+           }
          else
            {
              /* Skip escaped quotes here, it's easier than above, but
@@ -515,6 +550,7 @@ scan_out_logical_line (pfile, macro)
                  pfile->out.cur = out;
                  cur = copy_comment (pfile, cur, macro != 0);
                  out = pfile->out.cur;
+                 continue;
                }
            }
          break;
@@ -530,26 +566,33 @@ scan_out_logical_line (pfile, macro)
        case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
        case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
        case 'Y': case 'Z':
-         if (quote == 0 || macro)
+         if (!pfile->state.skipping && (quote == 0 || macro))
            {
              cpp_hashnode *node;
+             uchar *out_start = out - 1;
 
-             pfile->out.cur = --out;
+             pfile->out.cur = out_start;
              node = lex_identifier (pfile, cur - 1);
+             out = pfile->out.cur;
+             cur = CUR (context);
 
              if (node->type == NT_MACRO
-                 && !pfile->state.skipping
-                 && pfile->state.parsing_args != 2
+                 /* Should we expand for ls_answer?  */
+                 && lex_state == ls_none
                  && !pfile->state.prevent_expansion
                  && !recursive_macro (pfile, node))
                {
                  if (node->value.macro->fun_like)
-                   maybe_start_funlike (pfile, node, out, &fmacro);
+                   {
+                     maybe_start_funlike (pfile, node, out_start, &fmacro);
+                     lex_state = ls_fun_macro;
+                     continue;
+                   }
                  else
                    {
                      /* Remove the object-like macro's name from the
                         output, and push its replacement text.  */
-                     pfile->out.cur = out;
+                     pfile->out.cur = out_start;
                      push_replacement_text (pfile, node);
                      goto new_context;
                    }
@@ -558,12 +601,20 @@ scan_out_logical_line (pfile, macro)
                {
                  /* Found a parameter in the replacement text of a
                     #define.  Remove its name from the output.  */
-                 pfile->out.cur = out;
+                 out = pfile->out.cur = out_start;
                  save_replacement_text (pfile, macro, node->arg_index);
                }
-
-             out = pfile->out.cur;
-             cur = CUR (context);
+             else if (lex_state == ls_hash)
+               {
+                 lex_state = ls_predicate;
+                 continue;
+               }
+             else if (pfile->state.in_expression
+                      && node == pfile->spec_nodes.n_defined)
+               {
+                 lex_state = ls_defined;
+                 continue;
+               }
            }
          break;
 
@@ -571,27 +622,18 @@ scan_out_logical_line (pfile, macro)
          if (quote == 0)
            {
              paren_depth++;
-             if (pfile->state.parsing_args == 1)
+             if (lex_state == ls_fun_macro)
                {
-                 const uchar *p = pfile->out.base + fmacro.offset;
-
-                 /* Invoke a prior function-like macro if there is only
-                    white space in-between.  */
-                 while (is_numchar (*p))
-                   p++;
-                 while (is_space (*p))
-                   p++;
-
-                 if (p == out - 1)
-                   {
-                     pfile->state.parsing_args = 2;
-                     paren_depth = 1;
-                     out = pfile->out.base + fmacro.offset;
-                     fmacro.args[0] = fmacro.offset;
-                   }
-                 else
-                   pfile->state.parsing_args = 0;
+                 lex_state = ls_none;
+                 pfile->state.parsing_args = 2;
+                 paren_depth = 1;
+                 out = pfile->out.base + fmacro.offset;
+                 fmacro.args[0] = fmacro.offset;
                }
+             else if (lex_state == ls_predicate)
+               lex_state = ls_answer;
+             else if (lex_state == ls_defined)
+               lex_state = ls_defined_close;
            }
          break;
 
@@ -614,7 +656,7 @@ scan_out_logical_line (pfile, macro)
                  /* A single zero-length argument is no argument.  */
                  if (fmacro.argc == 1
                      && m->paramc == 0
-                     && out == pfile->out.base + 1)
+                     && out == pfile->out.base + fmacro.offset + 1)
                    fmacro.argc = 0;
 
                  if (_cpp_arguments_ok (pfile, m, fmacro.node, fmacro.argc))
@@ -628,6 +670,8 @@ scan_out_logical_line (pfile, macro)
                      goto new_context;
                    }
                }
+             else if (lex_state == ls_answer || lex_state == ls_defined_close)
+               lex_state = ls_none;
            }
          break;
 
@@ -641,11 +685,34 @@ scan_out_logical_line (pfile, macro)
              if (_cpp_handle_directive (pfile, false /* indented */))
                goto start_logical_line;
            }
+         if (pfile->state.in_expression)
+           {
+             lex_state = ls_hash;
+             continue;
+           }
          break;
 
        default:
          break;
        }
+
+      if (lex_state == ls_none)
+       continue;
+
+      /* Some of these transitions of state are syntax errors.  The
+        ISO preprocessor will issue errors later.  */
+      if (lex_state == ls_fun_macro)
+       {
+         /* Missing '('.  */
+         lex_state = ls_none;
+         pfile->state.parsing_args = 0;
+       }
+      else if (lex_state == ls_hash
+              || lex_state == ls_predicate
+              || lex_state == ls_defined)
+       lex_state = ls_none;
+
+      /* ls_answer and ls_defined_close keep going until ')'.  */
     }
 
  done:
@@ -654,6 +721,12 @@ scan_out_logical_line (pfile, macro)
   pfile->out.cur = out - 1;
   if (fmacro.buff)
     _cpp_release_buff (pfile, fmacro.buff);
+
+  if (pfile->state.parsing_args == 2)
+    cpp_error (pfile, DL_ERROR,
+              "unterminated argument list invoking macro \"%s\"",
+              NODE_NAME (fmacro.node));
+  pfile->state.parsing_args = 0;
 }
 
 /* Push a context holding the replacement text of the macro NODE on