OSDN Git Service

PR fortran/15586
[pf3gnuchains/gcc-fork.git] / gcc / fortran / parse.c
index 3983db7..6945925 100644 (file)
@@ -1,5 +1,6 @@
 /* Main parser.
-   Copyright (C) 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, 
+   Inc.
    Contributed by Andy Vaught
 
 This file is part of GCC.
@@ -16,14 +17,13 @@ for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 
 #include "config.h"
-#include <string.h>
+#include "system.h"
 #include <setjmp.h>
-
 #include "gfortran.h"
 #include "match.h"
 #include "parse.h"
@@ -35,7 +35,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 gfc_st_label *gfc_statement_label;
 
 static locus label_locus;
-static jmp_buf eof;
+static jmp_buf eof_buf;
 
 gfc_state_data *gfc_state_stack;
 
@@ -75,13 +75,16 @@ match_word (const char *str, match (*subr) (void), locus * old_locus)
 
 
 /* Figure out what the next statement is, (mostly) regardless of
-   proper ordering.  */
+   proper ordering.  The do...while(0) is there to prevent if/else
+   ambiguity.  */
 
 #define match(keyword, subr, st)                               \
-    if (match_word(keyword, subr, &old_locus) == MATCH_YES)    \
-      return st;                                               \
-    else                                                       \
-      undo_new_statement ();
+    do {                                                        \
+      if (match_word(keyword, subr, &old_locus) == MATCH_YES)  \
+        return st;                                             \
+      else                                                     \
+        undo_new_statement ();                                  \
+    } while (0);
 
 static gfc_statement
 decode_statement (void)
@@ -177,7 +180,7 @@ decode_statement (void)
 
     case 'b':
       match ("backspace", gfc_match_backspace, ST_BACKSPACE);
-      match ("block data", gfc_match_block_data, ST_BLOCK_DATA);
+      match ("block data", gfc_match_block_data, ST_BLOCK_DATA);
       break;
 
     case 'c':
@@ -212,6 +215,7 @@ decode_statement (void)
       break;
 
     case 'f':
+      match ("flush", gfc_match_flush, ST_FLUSH);
       match ("format", gfc_match_format, ST_FORMAT);
       break;
 
@@ -399,7 +403,7 @@ next_fixed (void)
          break;
 
           /* Comments have already been skipped by the time we get
-            here so don't bother checking for them. */
+            here so don't bother checking for them.  */
 
        default:
          gfc_buffer_error (0);
@@ -479,7 +483,13 @@ next_statement (void)
       gfc_buffer_error (1);
 
       if (gfc_at_eol ())
-       gfc_advance_line ();
+       {
+         if (gfc_option.warn_line_truncation
+             && gfc_current_locus.lb->truncated)
+           gfc_warning_now ("Line truncated at %C");
+
+         gfc_advance_line ();
+       }
 
       gfc_skip_comments ();
 
@@ -520,7 +530,8 @@ next_statement (void)
   case ST_READ: case ST_RETURN: case ST_REWIND: case ST_SIMPLE_IF: \
   case ST_PAUSE: case ST_STOP: case ST_WRITE: case ST_ASSIGNMENT: \
   case ST_POINTER_ASSIGNMENT: case ST_EXIT: case ST_CYCLE: \
-  case ST_ARITHMETIC_IF: case ST_WHERE: case ST_FORALL: case ST_LABEL_ASSIGNMENT
+  case ST_ARITHMETIC_IF: case ST_WHERE: case ST_FORALL: \
+  case ST_LABEL_ASSIGNMENT: case ST_FLUSH
 
 /* Statements that mark other executable statements.  */
 
@@ -550,6 +561,7 @@ push_state (gfc_state_data * p, gfc_compile_state new_state, gfc_symbol * sym)
   p->previous = gfc_state_stack;
   p->sym = sym;
   p->head = p->tail = NULL;
+  p->do_variable = NULL;
 
   gfc_state_stack = p;
 }
@@ -719,13 +731,13 @@ gfc_ascii_statement (gfc_statement st)
   switch (st)
     {
     case ST_ARITHMETIC_IF:
-      p = "arithmetic IF";
+      p = _("arithmetic IF");
       break;
     case ST_ALLOCATE:
       p = "ALLOCATE";
       break;
     case ST_ATTR_DECL:
-      p = "attribute declaration";
+      p = _("attribute declaration");
       break;
     case ST_BACKSPACE:
       p = "BACKSPACE";
@@ -755,7 +767,7 @@ gfc_ascii_statement (gfc_statement st)
       p = "CYCLE";
       break;
     case ST_DATA_DECL:
-      p = "data declaration";
+      p = _("data declaration");
       break;
     case ST_DATA:
       p = "DATA";
@@ -764,7 +776,7 @@ gfc_ascii_statement (gfc_statement st)
       p = "DEALLOCATE";
       break;
     case ST_DERIVED_DECL:
-      p = "Derived type declaration";
+      p = _("derived type declaration");
       break;
     case ST_DO:
       p = "DO";
@@ -826,6 +838,9 @@ gfc_ascii_statement (gfc_statement st)
     case ST_EXIT:
       p = "EXIT";
       break;
+    case ST_FLUSH:
+      p = "FLUSH";
+      break;
     case ST_FORALL_BLOCK:      /* Fall through */
     case ST_FORALL:
       p = "FORALL";
@@ -840,7 +855,7 @@ gfc_ascii_statement (gfc_statement st)
       p = "GOTO";
       break;
     case ST_IF_BLOCK:
-      p = "block IF";
+      p = _("block IF");
       break;
     case ST_IMPLICIT:
       p = "IMPLICIT";
@@ -849,7 +864,7 @@ gfc_ascii_statement (gfc_statement st)
       p = "IMPLICIT NONE";
       break;
     case ST_IMPLIED_ENDDO:
-      p = "implied END DO";
+      p = _("implied END DO");
       break;
     case ST_INQUIRE:
       p = "INQUIRE";
@@ -916,10 +931,10 @@ gfc_ascii_statement (gfc_statement st)
       p = "WRITE";
       break;
     case ST_ASSIGNMENT:
-      p = "assignment";
+      p = _("assignment");
       break;
     case ST_POINTER_ASSIGNMENT:
-      p = "pointer assignment";
+      p = _("pointer assignment");
       break;
     case ST_SELECT_CASE:
       p = "SELECT CASE";
@@ -928,7 +943,7 @@ gfc_ascii_statement (gfc_statement st)
       p = "SEQUENCE";
       break;
     case ST_SIMPLE_IF:
-      p = "Simple IF";
+      p = _("simple IF");
       break;
     case ST_STATEMENT_FUNCTION:
       p = "STATEMENT FUNCTION";
@@ -944,63 +959,6 @@ gfc_ascii_statement (gfc_statement st)
 }
 
 
-/* Return the name of a compile state.  */
-
-const char *
-gfc_state_name (gfc_compile_state state)
-{
-  const char *p;
-
-  switch (state)
-    {
-    case COMP_PROGRAM:
-      p = "a PROGRAM";
-      break;
-    case COMP_MODULE:
-      p = "a MODULE";
-      break;
-    case COMP_SUBROUTINE:
-      p = "a SUBROUTINE";
-      break;
-    case COMP_FUNCTION:
-      p = "a FUNCTION";
-      break;
-    case COMP_BLOCK_DATA:
-      p = "a BLOCK DATA";
-      break;
-    case COMP_INTERFACE:
-      p = "an INTERFACE";
-      break;
-    case COMP_DERIVED:
-      p = "a DERIVED TYPE block";
-      break;
-    case COMP_IF:
-      p = "an IF-THEN block";
-      break;
-    case COMP_DO:
-      p = "a DO block";
-      break;
-    case COMP_SELECT:
-      p = "a SELECT block";
-      break;
-    case COMP_FORALL:
-      p = "a FORALL block";
-      break;
-    case COMP_WHERE:
-      p = "a WHERE block";
-      break;
-    case COMP_CONTAINS:
-      p = "a contained subprogram";
-      break;
-
-    default:
-      gfc_internal_error ("gfc_state_name(): Bad state");
-    }
-
-  return p;
-}
-
-
 /* Do whatever is necessary to accept the last statement.  */
 
 static void
@@ -1018,7 +976,6 @@ accept_statement (gfc_statement st)
       break;
 
     case ST_IMPLICIT:
-      gfc_set_implicit ();
       break;
 
     case ST_FUNCTION:
@@ -1032,7 +989,6 @@ accept_statement (gfc_statement st)
          construct.  */
 
     case ST_ENDIF:
-    case ST_ENDDO:
     case ST_END_SELECT:
       if (gfc_statement_label != NULL)
        {
@@ -1057,24 +1013,7 @@ accept_statement (gfc_statement st)
 
       break;
 
-    case ST_BLOCK_DATA:
-      {
-        gfc_symbol *block_data = NULL;
-        symbol_attribute attr;
-
-        gfc_get_symbol ("_BLOCK_DATA__", gfc_current_ns, &block_data);
-        gfc_clear_attr (&attr);
-        attr.flavor = FL_PROCEDURE;
-        attr.proc = PROC_UNKNOWN;
-        attr.subroutine = 1;
-        attr.access = ACCESS_PUBLIC;
-        block_data->attr = attr;
-        gfc_current_ns->proc_name = block_data;
-        gfc_commit_symbols ();
-      }
-
-      break;
-
+    case ST_ENTRY:
     case_executable:
     case_exec_markers:
       add_statement ();
@@ -1268,7 +1207,7 @@ unexpected_eof (void)
   gfc_current_ns->code = (p && p->previous) ? p->head : NULL;
   gfc_done_2 ();
 
-  longjmp (eof, 1);
+  longjmp (eof_buf, 1);
 }
 
 
@@ -1367,7 +1306,8 @@ parse_derived (void)
            }
 
          seen_sequence = 1;
-         gfc_add_sequence (&gfc_current_block ()->attr, NULL);
+         gfc_add_sequence (&gfc_current_block ()->attr, 
+                           gfc_current_block ()->name, NULL);
          break;
 
        default:
@@ -1422,7 +1362,7 @@ parse_interface (void)
   current_state = COMP_NONE;
 
 loop:
-  gfc_current_ns = gfc_get_namespace (current_interface.ns);
+  gfc_current_ns = gfc_get_namespace (current_interface.ns, 0);
 
   st = next_statement ();
   switch (st)
@@ -1469,9 +1409,9 @@ loop:
       if (current_state == COMP_NONE)
        {
          if (new_state == COMP_FUNCTION)
-           gfc_add_function (&sym->attr, NULL);
-         if (new_state == COMP_SUBROUTINE)
-           gfc_add_subroutine (&sym->attr, NULL);
+           gfc_add_function (&sym->attr, sym->name, NULL);
+         else if (new_state == COMP_SUBROUTINE)
+           gfc_add_subroutine (&sym->attr, sym->name, NULL);
 
          current_state = new_state;
        }
@@ -1911,6 +1851,28 @@ parse_select_block (void)
 }
 
 
+/* Given a symbol, make sure it is not an iteration variable for a DO
+   statement.  This subroutine is called when the symbol is seen in a
+   context that causes it to become redefined.  If the symbol is an
+   iterator, we generate an error message and return nonzero.  */
+
+int 
+gfc_check_do_variable (gfc_symtree *st)
+{
+  gfc_state_data *s;
+
+  for (s=gfc_state_stack; s; s = s->previous)
+    if (s->do_variable == st)
+      {
+       gfc_error_now("Variable '%s' at %C cannot be redefined inside "
+                     "loop beginning at %L", st->name, &s->head->loc);
+       return 1;
+      }
+
+  return 0;
+}
+  
+
 /* Checks to see if the current statement label closes an enddo.
    Returns 0 if not, 1 if closes an ENDDO correctly, or 2 (and issues
    an error) if it incorrectly closes an ENDDO.  */
@@ -1965,14 +1927,22 @@ parse_do_block (void)
   gfc_statement st;
   gfc_code *top;
   gfc_state_data s;
+  gfc_symtree *stree;
 
   s.ext.end_do_label = new_st.label;
 
+  if (new_st.ext.iterator != NULL)
+    stree = new_st.ext.iterator->var->symtree;
+  else
+    stree = NULL;
+
   accept_statement (ST_DO);
 
   top = gfc_state_stack->tail;
   push_state (&s, COMP_DO, gfc_new_block);
 
+  s.do_variable = stree;
+
   top->block = new_level (top);
   top->block->op = EXEC_DO;
 
@@ -1989,7 +1959,13 @@ loop:
          && s.ext.end_do_label != gfc_statement_label)
        gfc_error_now
          ("Statement label in ENDDO at %C doesn't match DO label");
-      /* Fall through */
+
+      if (gfc_statement_label != NULL)
+       {
+         new_st.op = EXEC_NOP;
+         add_statement ();
+       }
+      break;
 
     case ST_IMPLIED_ENDDO:
       break;
@@ -2109,6 +2085,7 @@ gfc_fixup_sibling_symbols (gfc_symbol * sym, gfc_namespace * siblings)
   gfc_symtree *st;
   gfc_symbol *old_sym;
 
+  sym->attr.referenced = 1;
   for (ns = siblings; ns; ns = ns->sibling)
     {
       gfc_find_sym_tree (sym->name, ns, 0, &st);
@@ -2116,7 +2093,9 @@ gfc_fixup_sibling_symbols (gfc_symbol * sym, gfc_namespace * siblings)
         continue;
 
       old_sym = st->n.sym;
-      if (old_sym->attr.flavor == FL_PROCEDURE && old_sym->ns == ns
+      if ((old_sym->attr.flavor == FL_PROCEDURE
+          || old_sym->ts.type == BT_UNKNOWN)
+         && old_sym->ns == ns
           && ! old_sym->attr.contained)
         {
           /* Replace it with the symbol from the parent namespace.  */
@@ -2129,7 +2108,7 @@ gfc_fixup_sibling_symbols (gfc_symbol * sym, gfc_namespace * siblings)
             gfc_free_symbol (old_sym);
         }
 
-      /* Do the same for any contined procedures.  */
+      /* Do the same for any contained procedures.  */
       gfc_fixup_sibling_symbols (sym, ns->contained);
     }
 }
@@ -2141,13 +2120,14 @@ parse_contained (int module)
   gfc_state_data s1, s2;
   gfc_statement st;
   gfc_symbol *sym;
+  gfc_entry_list *el;
 
   push_state (&s1, COMP_CONTAINS, NULL);
   parent_ns = gfc_current_ns;
 
   do
     {
-      gfc_current_ns = gfc_get_namespace (parent_ns);
+      gfc_current_ns = gfc_get_namespace (parent_ns, 1);
 
       gfc_current_ns->sibling = parent_ns->contained;
       parent_ns->contained = gfc_current_ns;
@@ -2168,7 +2148,7 @@ parse_contained (int module)
                      gfc_new_block);
 
          /* For internal procedures, create/update the symbol in the
-          * parent namespace */
+            parent namespace.  */
 
          if (!module)
            {
@@ -2178,15 +2158,15 @@ parse_contained (int module)
                   gfc_new_block->name);
              else
                {
-                 if (gfc_add_procedure (&sym->attr, PROC_INTERNAL,
+                 if (gfc_add_procedure (&sym->attr, PROC_INTERNAL, sym->name,
                                         &gfc_new_block->declared_at) ==
                      SUCCESS)
                    {
                      if (st == ST_FUNCTION)
-                       gfc_add_function (&sym->attr,
+                       gfc_add_function (&sym->attr, sym->name,
                                          &gfc_new_block->declared_at);
                      else
-                       gfc_add_subroutine (&sym->attr,
+                       gfc_add_subroutine (&sym->attr, sym->name,
                                            &gfc_new_block->declared_at);
                    }
                }
@@ -2199,11 +2179,15 @@ parse_contained (int module)
           /* Mark this as a contained function, so it isn't replaced
              by other module functions.  */
           sym->attr.contained = 1;
+         sym->attr.referenced = 1;
+
+         parse_progunit (ST_NONE);
 
           /* Fix up any sibling functions that refer to this one.  */
           gfc_fixup_sibling_symbols (sym, gfc_current_ns);
-
-         parse_progunit (ST_NONE);
+         /* Or refer to any of its alternate entry points.  */
+         for (el = gfc_current_ns->entries; el; el = el->next)
+           gfc_fixup_sibling_symbols (el->sym, gfc_current_ns);
 
          gfc_current_ns->code = s2.head;
          gfc_current_ns = parent_ns;
@@ -2319,12 +2303,82 @@ done:
 }
 
 
+/* Come here to complain about a global symbol already in use as
+   something else.  */
+
+static void
+global_used (gfc_gsymbol *sym, locus *where)
+{
+  const char *name;
+
+  if (where == NULL)
+    where = &gfc_current_locus;
+
+  switch(sym->type)
+    {
+    case GSYM_PROGRAM:
+      name = "PROGRAM";
+      break;
+    case GSYM_FUNCTION:
+      name = "FUNCTION";
+      break;
+    case GSYM_SUBROUTINE:
+      name = "SUBROUTINE";
+      break;
+    case GSYM_COMMON:
+      name = "COMMON";
+      break;
+    case GSYM_BLOCK_DATA:
+      name = "BLOCK DATA";
+      break;
+    case GSYM_MODULE:
+      name = "MODULE";
+      break;
+    default:
+      gfc_internal_error ("gfc_gsymbol_type(): Bad type");
+      name = NULL;
+    }
+
+  gfc_error("Global name '%s' at %L is already being used as a %s at %L",
+           gfc_new_block->name, where, name, &sym->where);
+}
+
+
 /* Parse a block data program unit.  */
 
 static void
 parse_block_data (void)
 {
   gfc_statement st;
+  static locus blank_locus;
+  static int blank_block=0;
+  gfc_gsymbol *s;
+
+  gfc_current_ns->proc_name = gfc_new_block;
+  gfc_current_ns->is_block_data = 1;
+
+  if (gfc_new_block == NULL)
+    {
+      if (blank_block)
+       gfc_error ("Blank BLOCK DATA at %C conflicts with "
+                  "prior BLOCK DATA at %L", &blank_locus);
+      else
+       {
+         blank_block = 1;
+         blank_locus = gfc_current_locus;
+       }
+    }
+  else
+    {
+      s = gfc_get_gsymbol (gfc_new_block->name);
+      if (s->type != GSYM_UNKNOWN)
+       global_used(s, NULL);
+      else
+       {
+         s->type = GSYM_BLOCK_DATA;
+         s->where = gfc_current_locus;
+       }
+    }
 
   st = parse_spec (ST_NONE);
 
@@ -2344,6 +2398,16 @@ static void
 parse_module (void)
 {
   gfc_statement st;
+  gfc_gsymbol *s;
+
+  s = gfc_get_gsymbol (gfc_new_block->name);
+  if (s->type != GSYM_UNKNOWN)
+    global_used(s, NULL);
+  else
+    {
+      s->type = GSYM_MODULE;
+      s->where = gfc_current_locus;
+    }
 
   st = parse_spec (ST_NONE);
 
@@ -2372,6 +2436,46 @@ loop:
 }
 
 
+/* Add a procedure name to the global symbol table.  */
+
+static void
+add_global_procedure (int sub)
+{
+  gfc_gsymbol *s;
+
+  s = gfc_get_gsymbol(gfc_new_block->name);
+
+  if (s->type != GSYM_UNKNOWN)
+    global_used(s, NULL);
+  else
+    {
+      s->type = sub ? GSYM_SUBROUTINE : GSYM_FUNCTION;
+      s->where = gfc_current_locus;
+    }
+}
+
+
+/* Add a program to the global symbol table.  */
+
+static void
+add_global_program (void)
+{
+  gfc_gsymbol *s;
+
+  if (gfc_new_block == NULL)
+    return;
+  s = gfc_get_gsymbol (gfc_new_block->name);
+
+  if (s->type != GSYM_UNKNOWN)
+    global_used(s, NULL);
+  else
+    {
+      s->type = GSYM_PROGRAM;
+      s->where = gfc_current_locus;
+    }
+}
+
+
 /* Top level parser.  */
 
 try
@@ -2386,6 +2490,7 @@ gfc_parse_file (void)
   top.sym = NULL;
   top.previous = NULL;
   top.head = top.tail = NULL;
+  top.do_variable = NULL;
 
   gfc_state_stack = &top;
 
@@ -2393,11 +2498,15 @@ gfc_parse_file (void)
 
   gfc_statement_label = NULL;
 
-  if (setjmp (eof))
+  if (setjmp (eof_buf))
     return FAILURE;    /* Come here on unexpected EOF */
 
   seen_program = 0;
 
+  /* Exit early for empty files.  */
+  if (gfc_at_eof ())
+    goto done;
+
 loop:
   gfc_init_2 ();
   st = next_statement ();
@@ -2415,16 +2524,19 @@ loop:
 
       push_state (&s, COMP_PROGRAM, gfc_new_block);
       accept_statement (st);
+      add_global_program ();
       parse_progunit (ST_NONE);
       break;
 
     case ST_SUBROUTINE:
+      add_global_procedure (1);
       push_state (&s, COMP_SUBROUTINE, gfc_new_block);
       accept_statement (st);
       parse_progunit (ST_NONE);
       break;
 
     case ST_FUNCTION:
+      add_global_procedure (0);
       push_state (&s, COMP_FUNCTION, gfc_new_block);
       accept_statement (st);
       parse_progunit (ST_NONE);