OSDN Git Service

2007-01-26 Steven Bosscher <stevenb.gcc@gmail.com>
[pf3gnuchains/gcc-fork.git] / gcc / fortran / primary.c
index d10a462..64cc5e4 100644 (file)
@@ -1,31 +1,28 @@
 /* Primary expression subroutines
-   Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006, 2007
+   Free Software Foundation, Inc.
    Contributed by Andy Vaught
 
-This file is part of GNU G95.
+This file is part of GCC.
 
-GNU G95 is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
 
-GNU G95 is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU G95; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
-
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301, USA.  */
 
 #include "config.h"
 #include "system.h"
 #include "flags.h"
-
-#include <string.h>
-#include <stdlib.h>
 #include "gfortran.h"
 #include "arith.h"
 #include "match.h"
@@ -43,7 +40,7 @@ match_kind_param (int *kind)
   const char *p;
   match m;
 
-  m = gfc_match_small_literal_int (kind);
+  m = gfc_match_small_literal_int (kind, NULL);
   if (m != MATCH_NO)
     return m;
 
@@ -117,7 +114,7 @@ check_digit (int c, int radix)
       break;
 
     case 16:
-      r = ('0' <= c && c <= '9') || ('a' <= c && c <= 'f');
+      r = ISXDIGIT (c);
       break;
 
     default:
@@ -146,6 +143,7 @@ match_digits (int signflag, int radix, char *buffer)
     {
       if (buffer != NULL)
        *buffer++ = c;
+      gfc_gobble_whitespace ();
       c = gfc_next_char ();
       length++;
     }
@@ -159,7 +157,7 @@ match_digits (int signflag, int radix, char *buffer)
 
   for (;;)
     {
-      old_loc = *gfc_current_locus ();
+      old_loc = gfc_current_locus;
       c = gfc_next_char ();
 
       if (!check_digit (c, radix))
@@ -170,7 +168,7 @@ match_digits (int signflag, int radix, char *buffer)
       length++;
     }
 
-  gfc_set_locus (&old_loc);
+  gfc_current_locus = old_loc;
 
   return length;
 }
@@ -180,18 +178,18 @@ match_digits (int signflag, int radix, char *buffer)
    A sign will be accepted if signflag is set.  */
 
 static match
-match_integer_constant (gfc_expr ** result, int signflag)
+match_integer_constant (gfc_expr **result, int signflag)
 {
   int length, kind;
   locus old_loc;
   char *buffer;
   gfc_expr *e;
 
-  old_loc = *gfc_current_locus ();
+  old_loc = gfc_current_locus;
   gfc_gobble_whitespace ();
 
   length = match_digits (signflag, 10, NULL);
-  gfc_set_locus (&old_loc);
+  gfc_current_locus = old_loc;
   if (length == -1)
     return MATCH_NO;
 
@@ -204,17 +202,17 @@ match_integer_constant (gfc_expr ** result, int signflag)
 
   kind = get_kind ();
   if (kind == -2)
-    kind = gfc_default_integer_kind ();
+    kind = gfc_default_integer_kind;
   if (kind == -1)
     return MATCH_ERROR;
 
-  if (gfc_validate_kind (BT_INTEGER, kind) == -1)
+  if (gfc_validate_kind (BT_INTEGER, kind, true) < 0)
     {
       gfc_error ("Integer kind %d at %C not available", kind);
       return MATCH_ERROR;
     }
 
-  e = gfc_convert_integer (buffer, kind, 10, gfc_current_locus ());
+  e = gfc_convert_integer (buffer, kind, 10, &gfc_current_locus);
 
   if (gfc_range_check (e) != ARITH_OK)
     {
@@ -229,39 +227,116 @@ match_integer_constant (gfc_expr ** result, int signflag)
 }
 
 
-/* Match a binary, octal or hexadecimal constant that can be found in
-   a DATA statement.  */
+/* Match a Hollerith constant.  */
 
 static match
-match_boz_constant (gfc_expr ** result)
+match_hollerith_constant (gfc_expr **result)
 {
-  int radix, delim, length;
   locus old_loc;
+  gfc_expr *e = NULL;
+  const char *msg;
+  char *buffer;
+  int num;
+  int i;  
+
+  old_loc = gfc_current_locus;
+  gfc_gobble_whitespace ();
+
+  if (match_integer_constant (&e, 0) == MATCH_YES
+      && gfc_match_char ('h') == MATCH_YES)
+    {
+      if (gfc_notify_std (GFC_STD_LEGACY, "Extension: Hollerith constant "
+                         "at %C") == FAILURE)
+       goto cleanup;
+
+      msg = gfc_extract_int (e, &num);
+      if (msg != NULL)
+       {
+         gfc_error (msg);
+         goto cleanup;
+       }
+      if (num == 0)
+       {
+         gfc_error ("Invalid Hollerith constant: %L must contain at least "
+                    "one character", &old_loc);
+         goto cleanup;
+       }
+      if (e->ts.kind != gfc_default_integer_kind)
+       {
+         gfc_error ("Invalid Hollerith constant: Integer kind at %L "
+                    "should be default", &old_loc);
+         goto cleanup;
+       }
+      else
+       {
+         buffer = (char *) gfc_getmem (sizeof(char) * num + 1);
+         for (i = 0; i < num; i++)
+           {
+             buffer[i] = gfc_next_char_literal (1);
+           }
+         gfc_free_expr (e);
+         e = gfc_constant_result (BT_HOLLERITH, gfc_default_character_kind,
+                                  &gfc_current_locus);
+         e->value.character.string = gfc_getmem (num + 1);
+         memcpy (e->value.character.string, buffer, num);
+         e->value.character.string[num] = '\0';
+         e->value.character.length = num;
+         *result = e;
+         return MATCH_YES;
+       }
+    }
+
+  gfc_free_expr (e);
+  gfc_current_locus = old_loc;
+  return MATCH_NO;
+
+cleanup:
+  gfc_free_expr (e);
+  return MATCH_ERROR;
+}
+
+
+/* Match a binary, octal or hexadecimal constant that can be found in
+   a DATA statement.  The standard permits b'010...', o'73...', and
+   z'a1...' where b, o, and z can be capital letters.  This function
+   also accepts postfixed forms of the constants: '01...'b, '73...'o,
+   and 'a1...'z.  An additional extension is the use of x for z.  */
+
+static match
+match_boz_constant (gfc_expr **result)
+{
+  int post, radix, delim, length, x_hex, kind;
+  locus old_loc, start_loc;
   char *buffer;
   gfc_expr *e;
-  const char *rname;
 
-  old_loc = *gfc_current_locus ();
+  start_loc = old_loc = gfc_current_locus;
   gfc_gobble_whitespace ();
 
-  switch (gfc_next_char ())
+  x_hex = 0;
+  switch (post = gfc_next_char ())
     {
     case 'b':
       radix = 2;
-      rname = "binary";
+      post = 0;
       break;
     case 'o':
       radix = 8;
-      rname = "octal";
+      post = 0;
       break;
     case 'x':
-      if (pedantic)
-       gfc_warning_now ("Hexadecimal constant at %C uses non-standard "
-                        "syntax. Use \"Z\" instead.");
+      x_hex = 1;
       /* Fall through.  */
     case 'z':
       radix = 16;
-      rname = "hexadecimal";
+      post = 0;
+      break;
+    case '\'':
+      /* Fall through.  */
+    case '\"':
+      delim = post;
+      post = 1;
+      radix = 16;  /* Set to accept any valid digit string.  */
       break;
     default:
       goto backup;
@@ -269,40 +344,78 @@ match_boz_constant (gfc_expr ** result)
 
   /* No whitespace allowed here.  */
 
-  delim = gfc_next_char ();
+  if (post == 0)
+    delim = gfc_next_char ();
+
   if (delim != '\'' && delim != '\"')
     goto backup;
 
-  old_loc = *gfc_current_locus ();
+  if (x_hex && pedantic
+      && (gfc_notify_std (GFC_STD_GNU, "Extension: Hexadecimal "
+                         "constant at %C uses non-standard syntax.")
+         == FAILURE))
+      return MATCH_ERROR;
+
+  old_loc = gfc_current_locus;
 
   length = match_digits (0, radix, NULL);
   if (length == -1)
     {
-      gfc_error ("Empty set of digits in %s constants at %C", rname);
+      gfc_error ("Empty set of digits in BOZ constant at %C");
       return MATCH_ERROR;
     }
 
   if (gfc_next_char () != delim)
     {
-      gfc_error ("Illegal character in %s constant at %C.", rname);
+      gfc_error ("Illegal character in BOZ constant at %C");
       return MATCH_ERROR;
     }
 
-  gfc_set_locus (&old_loc);
+  if (post == 1)
+    {
+      switch (gfc_next_char ())
+       {
+       case 'b':
+         radix = 2;
+         break;
+       case 'o':
+         radix = 8;
+         break;
+       case 'x':
+         /* Fall through.  */
+       case 'z':
+         radix = 16;
+         break;
+       default:
+         goto backup;
+       }
+       gfc_notify_std (GFC_STD_GNU, "Extension: BOZ constant "
+                       "at %C uses non-standard postfix syntax.");
+    }
+
+  gfc_current_locus = old_loc;
 
   buffer = alloca (length + 1);
   memset (buffer, '\0', length + 1);
 
   match_digits (0, radix, buffer);
-  gfc_next_char ();
+  gfc_next_char ();    /* Eat delimiter.  */
+  if (post == 1)
+    gfc_next_char ();  /* Eat postfixed b, o, z, or x.  */
+
+  /* In section 5.2.5 and following C567 in the Fortran 2003 standard, we find
+     "If a data-stmt-constant is a boz-literal-constant, the corresponding
+     variable shall be of type integer.  The boz-literal-constant is treated
+     as if it were an int-literal-constant with a kind-param that specifies
+     the representation method with the largest decimal exponent range
+     supported by the processor."  */
 
-  e = gfc_convert_integer (buffer, gfc_default_integer_kind (), radix,
-                          gfc_current_locus ());
+  kind = gfc_max_integer_kind;
+  e = gfc_convert_integer (buffer, kind, radix, &gfc_current_locus);
 
   if (gfc_range_check (e) != ARITH_OK)
     {
-      gfc_error ("Integer too big for default integer kind at %C");
-
+      gfc_error ("Integer too big for integer kind %i at %C", kind);
       gfc_free_expr (e);
       return MATCH_ERROR;
     }
@@ -311,22 +424,24 @@ match_boz_constant (gfc_expr ** result)
   return MATCH_YES;
 
 backup:
-  gfc_set_locus (&old_loc);
+  gfc_current_locus = start_loc;
   return MATCH_NO;
 }
 
 
-/* Match a real constant of some sort.  */
+/* Match a real constant of some sort.  Allow a signed constant if signflag
+   is nonzero.  Allow integer constants if allow_int is true.  */
 
 static match
-match_real_constant (gfc_expr ** result, int signflag)
+match_real_constant (gfc_expr **result, int signflag)
 {
   int kind, c, count, seen_dp, seen_digits, exp_char;
   locus old_loc, temp_loc;
   char *p, *buffer;
   gfc_expr *e;
+  bool negate;
 
-  old_loc = *gfc_current_locus ();
+  old_loc = gfc_current_locus;
   gfc_gobble_whitespace ();
 
   e = NULL;
@@ -335,12 +450,16 @@ match_real_constant (gfc_expr ** result, int signflag)
   seen_dp = 0;
   seen_digits = 0;
   exp_char = ' ';
+  negate = FALSE;
 
   c = gfc_next_char ();
   if (signflag && (c == '+' || c == '-'))
     {
+      if (c == '-')
+       negate = TRUE;
+
+      gfc_gobble_whitespace ();
       c = gfc_next_char ();
-      count++;
     }
 
   /* Scan significand.  */
@@ -351,21 +470,22 @@ match_real_constant (gfc_expr ** result, int signflag)
          if (seen_dp)
            goto done;
 
-         /* Check to see if "." goes with a following operator like ".eq.".  */
-         temp_loc = *gfc_current_locus ();
+         /* Check to see if "." goes with a following operator like 
+            ".eq.".  */
+         temp_loc = gfc_current_locus;
          c = gfc_next_char ();
 
          if (c == 'e' || c == 'd' || c == 'q')
            {
              c = gfc_next_char ();
              if (c == '.')
-               goto done;      /* Operator named .e. or .d. */
+               goto done;      /* Operator named .e. or .d.  */
            }
 
          if (ISALPHA (c))
            goto done;          /* Distinguish 1.e9 from 1.eq.2 */
 
-         gfc_set_locus (&temp_loc);
+         gfc_current_locus = temp_loc;
          seen_dp = 1;
          continue;
        }
@@ -395,13 +515,6 @@ match_real_constant (gfc_expr ** result, int signflag)
 
   if (!ISDIGIT (c))
     {
-      /* TODO: seen_digits is always true at this point */
-      if (!seen_digits)
-       {
-         gfc_set_locus (&old_loc);
-         return MATCH_NO;      /* ".e" can be something else */
-       }
-
       gfc_error ("Missing exponent in real number at %C");
       return MATCH_ERROR;
     }
@@ -413,29 +526,40 @@ match_real_constant (gfc_expr ** result, int signflag)
     }
 
 done:
-  /* See what we've got!  */
+  /* Check that we have a numeric constant.  */
   if (!seen_digits || (!seen_dp && exp_char == ' '))
     {
-      gfc_set_locus (&old_loc);
+      gfc_current_locus = old_loc;
       return MATCH_NO;
     }
 
   /* Convert the number.  */
-  gfc_set_locus (&old_loc);
+  gfc_current_locus = old_loc;
   gfc_gobble_whitespace ();
 
   buffer = alloca (count + 1);
   memset (buffer, '\0', count + 1);
 
-  /* Hack for mpf_init_set_str().  */
   p = buffer;
-  while (count > 0)
+  c = gfc_next_char ();
+  if (c == '+' || c == '-')
+    {
+      gfc_gobble_whitespace ();
+      c = gfc_next_char ();
+    }
+
+  /* Hack for mpfr_set_str().  */
+  for (;;)
     {
-      *p = gfc_next_char ();
-      if (*p == 'd' || *p == 'q')
+      if (c == 'd' || c == 'q')
        *p = 'e';
+      else
+       *p = c;
       p++;
-      count--;
+      if (--count == 0)
+       break;
+
+      c = gfc_next_char ();
     }
 
   kind = get_kind ();
@@ -447,35 +571,27 @@ done:
     case 'd':
       if (kind != -2)
        {
-         gfc_error
-           ("Real number at %C has a 'd' exponent and an explicit kind");
-         goto cleanup;
-       }
-      kind = gfc_default_double_kind ();
-      break;
-
-    case 'q':
-      if (kind != -2)
-       {
-         gfc_error
-           ("Real number at %C has a 'q' exponent and an explicit kind");
+         gfc_error ("Real number at %C has a 'd' exponent and an explicit "
+                    "kind");
          goto cleanup;
        }
-      kind = gfc_option.q_kind;
+      kind = gfc_default_double_kind;
       break;
 
     default:
       if (kind == -2)
-       kind = gfc_default_real_kind ();
+       kind = gfc_default_real_kind;
 
-      if (gfc_validate_kind (BT_REAL, kind) == -1)
+      if (gfc_validate_kind (BT_REAL, kind, true) < 0)
        {
          gfc_error ("Invalid real kind %d at %C", kind);
          goto cleanup;
        }
     }
 
-  e = gfc_convert_real (buffer, kind, gfc_current_locus ());
+  e = gfc_convert_real (buffer, kind, &gfc_current_locus);
+  if (negate)
+    mpfr_neg (e->value.real, e->value.real, GFC_RND_MODE);
 
   switch (gfc_range_check (e))
     {
@@ -486,8 +602,10 @@ done:
       goto cleanup;
 
     case ARITH_UNDERFLOW:
-      gfc_error ("Real constant underflows its kind at %C");
-      goto cleanup;
+      if (gfc_option.warn_underflow)
+       gfc_warning ("Real constant underflows its kind at %C");
+      mpfr_set_ui (e->value.real, 0, GFC_RND_MODE);
+      break;
 
     default:
       gfc_internal_error ("gfc_range_check() returned bad value");
@@ -505,7 +623,7 @@ cleanup:
 /* Match a substring reference.  */
 
 static match
-match_substring (gfc_charlen * cl, int init, gfc_ref ** result)
+match_substring (gfc_charlen *cl, int init, gfc_ref **result)
 {
   gfc_expr *start, *end;
   locus old_loc;
@@ -515,7 +633,7 @@ match_substring (gfc_charlen * cl, int init, gfc_ref ** result)
   start = NULL;
   end = NULL;
 
-  old_loc = *gfc_current_locus ();
+  old_loc = gfc_current_locus;
 
   m = gfc_match_char ('(');
   if (m != MATCH_YES)
@@ -584,7 +702,7 @@ cleanup:
   gfc_free_expr (start);
   gfc_free_expr (end);
 
-  gfc_set_locus (&old_loc);
+  gfc_current_locus = old_loc;
   return m;
 }
 
@@ -610,9 +728,9 @@ next_string_char (char delimiter)
   if (c == '\n')
     return -2;
 
-  if (c == '\\')
+  if (gfc_option.flag_backslash && c == '\\')
     {
-      old_locus = *gfc_current_locus ();
+      old_locus = gfc_current_locus;
 
       switch (gfc_next_char_literal (1))
        {
@@ -643,20 +761,23 @@ next_string_char (char delimiter)
 
        default:
          /* Unknown backslash codes are simply not expanded */
-         gfc_set_locus (&old_locus);
+         gfc_current_locus = old_locus;
          break;
        }
+
+      if (!(gfc_option.allow_std & GFC_STD_GNU) && !inhibit_warnings)
+       gfc_warning ("Extension: backslash character at %C");
     }
 
   if (c != delimiter)
     return c;
 
-  old_locus = *gfc_current_locus ();
+  old_locus = gfc_current_locus;
   c = gfc_next_char_literal (1);
 
   if (c == delimiter)
     return c;
-  gfc_set_locus (&old_locus);
+  gfc_current_locus = old_locus;
 
   return -1;
 }
@@ -664,7 +785,7 @@ next_string_char (char delimiter)
 
 /* Special case of gfc_match_name() that matches a parameter kind name
    before a string constant.  This takes case of the weird but legal
-   case of: weird case of:
+   case of:
 
      kind_____'string'
 
@@ -691,7 +812,7 @@ match_charkind_name (char *name)
 
   for (;;)
     {
-      old_loc = *gfc_current_locus ();
+      old_loc = gfc_current_locus;
       c = gfc_next_char ();
 
       if (c == '_')
@@ -700,7 +821,7 @@ match_charkind_name (char *name)
 
          if (peek == '\'' || peek == '\"')
            {
-             gfc_set_locus (&old_loc);
+             gfc_current_locus = old_loc;
              *name = '\0';
              return MATCH_YES;
            }
@@ -728,7 +849,7 @@ match_charkind_name (char *name)
    delimiter.  Using match_kind_param() generates errors too quickly.  */
 
 static match
-match_string_constant (gfc_expr ** result)
+match_string_constant (gfc_expr **result)
 {
   char *p, name[GFC_MAX_SYMBOL_LEN + 1];
   int i, c, kind, length, delimiter;
@@ -738,16 +859,16 @@ match_string_constant (gfc_expr ** result)
   const char *q;
   match m;
 
-  old_locus = *gfc_current_locus ();
+  old_locus = gfc_current_locus;
 
   gfc_gobble_whitespace ();
 
-  start_locus = *gfc_current_locus ();
+  start_locus = gfc_current_locus;
 
   c = gfc_next_char ();
   if (c == '\'' || c == '"')
     {
-      kind = gfc_default_character_kind ();
+      kind = gfc_default_character_kind;
       goto got_delim;
     }
 
@@ -766,7 +887,7 @@ match_string_constant (gfc_expr ** result)
     }
   else
     {
-      gfc_set_locus (&old_locus);
+      gfc_current_locus = old_locus;
 
       m = match_charkind_name (name);
       if (m != MATCH_YES)
@@ -791,7 +912,7 @@ match_string_constant (gfc_expr ** result)
     goto no_match;
 
   gfc_gobble_whitespace ();
-  start_locus = *gfc_current_locus ();
+  start_locus = gfc_current_locus;
 
   c = gfc_next_char ();
   if (c != '\'' && c != '"')
@@ -807,7 +928,7 @@ match_string_constant (gfc_expr ** result)
        }
     }
 
-  if (gfc_validate_kind (BT_CHARACTER, kind) == -1)
+  if (gfc_validate_kind (BT_CHARACTER, kind, true) < 0)
     {
       gfc_error ("Invalid kind %d for CHARACTER constant at %C", kind);
       return MATCH_ERROR;
@@ -829,7 +950,7 @@ got_delim:
        break;
       if (c == -2)
        {
-         gfc_set_locus (&start_locus);
+         gfc_current_locus = start_locus;
          gfc_error ("Unterminated character constant beginning at %C");
          return MATCH_ERROR;
        }
@@ -837,6 +958,13 @@ got_delim:
       length++;
     }
 
+  /* Peek at the next character to see if it is a b, o, z, or x for the
+     postfixed BOZ literal constants.  */
+  c = gfc_peek_char ();
+  if (c == 'b' || c == 'o' || c =='z' || c == 'x')
+    goto no_match;
+
+
   e = gfc_get_expr ();
 
   e->expr_type = EXPR_CONSTANT;
@@ -848,7 +976,7 @@ got_delim:
   e->value.character.string = p = gfc_getmem (length + 1);
   e->value.character.length = length;
 
-  gfc_set_locus (&start_locus);
+  gfc_current_locus = start_locus;
   gfc_next_char ();            /* Skip delimiter */
 
   for (i = 0; i < length; i++)
@@ -867,7 +995,7 @@ got_delim:
   return MATCH_YES;
 
 no_match:
-  gfc_set_locus (&old_locus);
+  gfc_current_locus = old_locus;
   return MATCH_NO;
 }
 
@@ -875,7 +1003,7 @@ no_match:
 /* Match a .true. or .false.  */
 
 static match
-match_logical_constant (gfc_expr ** result)
+match_logical_constant (gfc_expr **result)
 {
   static mstring logical_ops[] = {
     minit (".false.", 0),
@@ -894,9 +1022,9 @@ match_logical_constant (gfc_expr ** result)
   if (kind == -1)
     return MATCH_ERROR;
   if (kind == -2)
-    kind = gfc_default_logical_kind ();
+    kind = gfc_default_logical_kind;
 
-  if (gfc_validate_kind (BT_LOGICAL, kind) == -1)
+  if (gfc_validate_kind (BT_LOGICAL, kind, true) < 0)
     gfc_error ("Bad kind for logical constant at %C");
 
   e = gfc_get_expr ();
@@ -905,7 +1033,7 @@ match_logical_constant (gfc_expr ** result)
   e->value.logical = i;
   e->ts.type = BT_LOGICAL;
   e->ts.kind = kind;
-  e->where = *gfc_current_locus ();
+  e->where = gfc_current_locus;
 
   *result = e;
   return MATCH_YES;
@@ -916,7 +1044,7 @@ match_logical_constant (gfc_expr ** result)
    symbolic constant.  */
 
 static match
-match_sym_complex_part (gfc_expr ** result)
+match_sym_complex_part (gfc_expr **result)
 {
   char name[GFC_MAX_SYMBOL_LEN + 1];
   gfc_symbol *sym;
@@ -948,6 +1076,10 @@ match_sym_complex_part (gfc_expr ** result)
       return MATCH_ERROR;
     }
 
+  if (gfc_notify_std (GFC_STD_F2003, "Fortran 2003: PARAMETER symbol in "
+                     "complex constant at %C") == FAILURE)
+    return MATCH_ERROR;
+
   switch (sym->value->ts.type)
     {
     case BT_REAL:
@@ -961,7 +1093,7 @@ match_sym_complex_part (gfc_expr ** result)
       break;
 
     case BT_INTEGER:
-      e = gfc_int2real (sym->value, gfc_default_real_kind ());
+      e = gfc_int2real (sym->value, gfc_default_real_kind);
       if (e == NULL)
        goto error;
       break;
@@ -970,7 +1102,7 @@ match_sym_complex_part (gfc_expr ** result)
       gfc_internal_error ("gfc_match_sym_complex_part(): Bad type");
     }
 
-  *result = e;                 /* e is a scalar, real, constant expression */
+  *result = e;         /* e is a scalar, real, constant expression.  */
   return MATCH_YES;
 
 error:
@@ -979,156 +1111,10 @@ error:
 }
 
 
-/* Match the real and imaginary parts of a complex number.  This
-   subroutine is essentially match_real_constant() modified in a
-   couple of ways: A sign is always allowed and numbers that would
-   look like an integer to match_real_constant() are automatically
-   created as floating point numbers.  The messiness involved with
-   making sure a decimal point belongs to the number and not a
-   trailing operator is not necessary here either (Hooray!).  */
-
-static match
-match_const_complex_part (gfc_expr ** result)
-{
-  int kind, seen_digits, seen_dp, count;
-  char *p, c, exp_char, *buffer;
-  locus old_loc;
-
-  old_loc = *gfc_current_locus ();
-  gfc_gobble_whitespace ();
-
-  seen_dp = 0;
-  seen_digits = 0;
-  count = 0;
-  exp_char = ' ';
-
-  c = gfc_next_char ();
-  if (c == '-' || c == '+')
-    {
-      c = gfc_next_char ();
-      count++;
-    }
-
-  for (;; c = gfc_next_char (), count++)
-    {
-      if (c == '.')
-       {
-         if (seen_dp)
-           goto no_match;
-         seen_dp = 1;
-         continue;
-       }
-
-      if (ISDIGIT (c))
-       {
-         seen_digits = 1;
-         continue;
-       }
-
-      break;
-    }
-
-  if (!seen_digits || (c != 'd' && c != 'e'))
-    goto done;
-  exp_char = c;
-
-  /* Scan exponent.  */
-  c = gfc_next_char ();
-  count++;
-
-  if (c == '+' || c == '-')
-    {                          /* optional sign */
-      c = gfc_next_char ();
-      count++;
-    }
-
-  if (!ISDIGIT (c))
-    {
-      gfc_error ("Missing exponent in real number at %C");
-      return MATCH_ERROR;
-    }
-
-  while (ISDIGIT (c))
-    {
-      c = gfc_next_char ();
-      count++;
-    }
-
-done:
-  if (!seen_digits)
-    goto no_match;
-
-  /* Convert the number.  */
-  gfc_set_locus (&old_loc);
-  gfc_gobble_whitespace ();
-
-  buffer = alloca (count + 1);
-  memset (buffer, '\0', count + 1);
-
-  /* Hack for mpf_init_set_str().  */
-  p = buffer;
-  while (count > 0)
-    {
-      c = gfc_next_char ();
-      if (c == 'd')
-       c = 'e';
-      *p++ = c;
-      count--;
-    }
-
-  *p = '\0';
-
-  kind = get_kind ();
-  if (kind == -1)
-    return MATCH_ERROR;
-
-  /* If the number looked like an integer, forget about a kind we may
-     have seen, otherwise validate the kind against real kinds.  */
-  if (seen_dp == 0 && exp_char == ' ')
-    {
-      if (kind == -2)
-       kind = gfc_default_integer_kind ();
-
-    }
-  else
-    {
-      if (exp_char == 'd')
-       {
-         if (kind != -2)
-           {
-             gfc_error
-               ("Real number at %C has a 'd' exponent and an explicit kind");
-             return MATCH_ERROR;
-           }
-         kind = gfc_default_double_kind ();
-
-       }
-      else
-       {
-         if (kind == -2)
-           kind = gfc_default_real_kind ();
-       }
-
-      if (gfc_validate_kind (BT_REAL, kind) == -1)
-       {
-         gfc_error ("Invalid real kind %d at %C", kind);
-         return MATCH_ERROR;
-       }
-    }
-
-  *result = gfc_convert_real (buffer, kind, gfc_current_locus ());
-  return MATCH_YES;
-
-no_match:
-  gfc_set_locus (&old_loc);
-  return MATCH_NO;
-}
-
-
 /* Match a real or imaginary part of a complex number.  */
 
 static match
-match_complex_part (gfc_expr ** result)
+match_complex_part (gfc_expr **result)
 {
   match m;
 
@@ -1136,14 +1122,18 @@ match_complex_part (gfc_expr ** result)
   if (m != MATCH_NO)
     return m;
 
-  return match_const_complex_part (result);
+  m = match_real_constant (result, 1);
+  if (m != MATCH_NO)
+    return m;
+
+  return match_integer_constant (result, 1);
 }
 
 
 /* Try to match a complex constant.  */
 
 static match
-match_complex_constant (gfc_expr ** result)
+match_complex_constant (gfc_expr **result)
 {
   gfc_expr *e, *real, *imag;
   gfc_error_buf old_error;
@@ -1152,7 +1142,7 @@ match_complex_constant (gfc_expr ** result)
   int kind;
   match m;
 
-  old_loc = *gfc_current_locus ();
+  old_loc = gfc_current_locus;
   real = imag = e = NULL;
 
   m = gfc_match_char ('(');
@@ -1163,7 +1153,10 @@ match_complex_constant (gfc_expr ** result)
 
   m = match_complex_part (&real);
   if (m == MATCH_NO)
-    goto cleanup;
+    {
+      gfc_free_error (&old_error);
+      goto cleanup;
+    }
 
   if (gfc_match_char (',') == MATCH_NO)
     {
@@ -1178,7 +1171,10 @@ match_complex_constant (gfc_expr ** result)
      sort. These sort of lists are matched prior to coming here.  */
 
   if (m == MATCH_ERROR)
-    goto cleanup;
+    {
+      gfc_free_error (&old_error);
+      goto cleanup;
+    }
   gfc_pop_error (&old_error);
 
   m = match_complex_part (&imag);
@@ -1189,23 +1185,46 @@ match_complex_constant (gfc_expr ** result)
 
   m = gfc_match_char (')');
   if (m == MATCH_NO)
+    {
+      /* Give the matcher for implied do-loops a chance to run.  This
+        yields a much saner error message for (/ (i, 4=i, 6) /).  */
+      if (gfc_peek_char () == '=')
+       {
+         m = MATCH_ERROR;
+         goto cleanup;
+       }
+      else
     goto syntax;
+    }
 
   if (m == MATCH_ERROR)
     goto cleanup;
 
   /* Decide on the kind of this complex number.  */
-  kind = gfc_kind_max (real, imag);
+  if (real->ts.type == BT_REAL)
+    {
+      if (imag->ts.type == BT_REAL)
+       kind = gfc_kind_max (real, imag);
+      else
+       kind = real->ts.kind;
+    }
+  else
+    {
+      if (imag->ts.type == BT_REAL)
+       kind = imag->ts.kind;
+      else
+       kind = gfc_default_real_kind;
+    }
   target.type = BT_REAL;
   target.kind = kind;
 
-  if (kind != real->ts.kind)
+  if (real->ts.type != BT_REAL || kind != real->ts.kind)
     gfc_convert_type (real, &target, 2);
-  if (kind != imag->ts.kind)
+  if (imag->ts.type != BT_REAL || kind != imag->ts.kind)
     gfc_convert_type (imag, &target, 2);
 
   e = gfc_convert_complex (real, imag, kind);
-  e->where = *gfc_current_locus ();
+  e->where = gfc_current_locus;
 
   gfc_free_expr (real);
   gfc_free_expr (imag);
@@ -1221,7 +1240,7 @@ cleanup:
   gfc_free_expr (e);
   gfc_free_expr (real);
   gfc_free_expr (imag);
-  gfc_set_locus (&old_loc);
+  gfc_current_locus = old_loc;
 
   return m;
 }
@@ -1231,7 +1250,7 @@ cleanup:
    match, zero for no match.  */
 
 match
-gfc_match_literal_constant (gfc_expr ** result, int signflag)
+gfc_match_literal_constant (gfc_expr **result, int signflag)
 {
   match m;
 
@@ -1251,6 +1270,10 @@ gfc_match_literal_constant (gfc_expr ** result, int signflag)
   if (m != MATCH_NO)
     return m;
 
+  m = match_hollerith_constant (result);
+  if (m != MATCH_NO)
+    return m;
+
   m = match_integer_constant (result, signflag);
   if (m != MATCH_NO)
     return m;
@@ -1271,7 +1294,7 @@ gfc_match_literal_constant (gfc_expr ** result, int signflag)
    fixing things later during resolution.  */
 
 static match
-match_actual_arg (gfc_expr ** result)
+match_actual_arg (gfc_expr **result)
 {
   char name[GFC_MAX_SYMBOL_LEN + 1];
   gfc_symtree *symtree;
@@ -1279,7 +1302,7 @@ match_actual_arg (gfc_expr ** result)
   gfc_expr *e;
   int c;
 
-  where = *gfc_current_locus ();
+  where = gfc_current_locus;
 
   switch (gfc_match_name (name))
     {
@@ -1290,10 +1313,10 @@ match_actual_arg (gfc_expr ** result)
       break;
 
     case MATCH_YES:
-      w = *gfc_current_locus ();
+      w = gfc_current_locus;
       gfc_gobble_whitespace ();
       c = gfc_next_char ();
-      gfc_set_locus (&w);
+      gfc_current_locus = w;
 
       if (c != ',' && c != ')')
        break;
@@ -1303,29 +1326,45 @@ match_actual_arg (gfc_expr ** result)
       /* Handle error elsewhere.  */
 
       /* Eliminate a couple of common cases where we know we don't
-         have a function argument.  */
+        have a function argument.  */
       if (symtree == NULL)
-        {
+       {
          gfc_get_sym_tree (name, NULL, &symtree);
-          gfc_set_sym_referenced (symtree->n.sym);
-        }
+         gfc_set_sym_referenced (symtree->n.sym);
+       }
       else
        {
-          gfc_symbol *sym;
+         gfc_symbol *sym;
 
-          sym = symtree->n.sym;
-          gfc_set_sym_referenced (sym);
+         sym = symtree->n.sym;
+         gfc_set_sym_referenced (sym);
          if (sym->attr.flavor != FL_PROCEDURE
              && sym->attr.flavor != FL_UNKNOWN)
            break;
 
          /* If the symbol is a function with itself as the result and
             is being defined, then we have a variable.  */
-         if (sym->result == sym
-             && (gfc_current_ns->proc_name == sym
+         if (sym->attr.function && sym->result == sym)
+           {
+             if (gfc_current_ns->proc_name == sym
                  || (gfc_current_ns->parent != NULL
-                     && gfc_current_ns->parent->proc_name == sym)))
-           break;
+                     && gfc_current_ns->parent->proc_name == sym))
+               break;
+
+             if (sym->attr.entry
+                 && (sym->ns == gfc_current_ns
+                     || sym->ns == gfc_current_ns->parent))
+               {
+                 gfc_entry_list *el = NULL;
+
+                 for (el = sym->ns->entries; el; el = el->next)
+                   if (sym == el->sym)
+                     break;
+
+                 if (el)
+                   break;
+               }
+           }
        }
 
       e = gfc_get_expr ();     /* Leave it unknown for now */
@@ -1338,7 +1377,7 @@ match_actual_arg (gfc_expr ** result)
       return MATCH_YES;
     }
 
-  gfc_set_locus (&where);
+  gfc_current_locus = where;
   return gfc_match_expr (result);
 }
 
@@ -1346,14 +1385,14 @@ match_actual_arg (gfc_expr ** result)
 /* Match a keyword argument.  */
 
 static match
-match_keyword_arg (gfc_actual_arglist * actual, gfc_actual_arglist * base)
+match_keyword_arg (gfc_actual_arglist *actual, gfc_actual_arglist *base)
 {
   char name[GFC_MAX_SYMBOL_LEN + 1];
   gfc_actual_arglist *a;
   locus name_locus;
   match m;
 
-  name_locus = *gfc_current_locus ();
+  name_locus = gfc_current_locus;
   m = gfc_match_name (name);
 
   if (m != MATCH_YES)
@@ -1373,20 +1412,93 @@ match_keyword_arg (gfc_actual_arglist * actual, gfc_actual_arglist * base)
   if (name[0] != '\0')
     {
       for (a = base; a; a = a->next)
-       if (strcmp (a->name, name) == 0)
+       if (a->name != NULL && strcmp (a->name, name) == 0)
          {
-           gfc_error
-             ("Keyword '%s' at %C has already appeared in the current "
-              "argument list", name);
+           gfc_error ("Keyword '%s' at %C has already appeared in the "
+                      "current argument list", name);
            return MATCH_ERROR;
          }
     }
 
-  strcpy (actual->name, name);
+  actual->name = gfc_get_string (name);
   return MATCH_YES;
 
 cleanup:
-  gfc_set_locus (&name_locus);
+  gfc_current_locus = name_locus;
+  return m;
+}
+
+
+/* Match an argument list function, such as %VAL.  */
+
+static match
+match_arg_list_function (gfc_actual_arglist *result)
+{
+  char name[GFC_MAX_SYMBOL_LEN + 1];
+  locus old_locus;
+  match m;
+
+  old_locus = gfc_current_locus;
+
+  if (gfc_match_char ('%') != MATCH_YES)
+    {
+      m = MATCH_NO;
+      goto cleanup;
+    }
+
+  m = gfc_match ("%n (", name);
+  if (m != MATCH_YES)
+    goto cleanup;
+
+  if (name[0] != '\0')
+    {
+      switch (name[0])
+       {
+       case 'l':
+         if (strncmp (name, "loc", 3) == 0)
+           {
+             result->name = "%LOC";
+             break;
+           }
+       case 'r':
+         if (strncmp (name, "ref", 3) == 0)
+           {
+             result->name = "%REF";
+             break;
+           }
+       case 'v':
+         if (strncmp (name, "val", 3) == 0)
+           {
+             result->name = "%VAL";
+             break;
+           }
+       default:
+         m = MATCH_ERROR;
+         goto cleanup;
+       }
+    }
+
+  if (gfc_notify_std (GFC_STD_GNU, "Extension: argument list "
+                     "function at %C") == FAILURE)
+    {
+      m = MATCH_ERROR;
+      goto cleanup;
+    }
+
+  m = match_actual_arg (&result->expr);
+  if (m != MATCH_YES)
+    goto cleanup;
+
+  if (gfc_match_char (')') != MATCH_YES)
+    {
+      m = MATCH_NO;
+      goto cleanup;
+    }
+
+  return MATCH_YES;
+
+cleanup:
+  gfc_current_locus = old_locus;
   return m;
 }
 
@@ -1395,10 +1507,11 @@ cleanup:
    the opening parenthesis to the closing parenthesis.  The argument
    list is assumed to allow keyword arguments because we don't know if
    the symbol associated with the procedure has an implicit interface
-   or not.  We make sure keywords are unique.  */
+   or not.  We make sure keywords are unique. If SUB_FLAG is set,
+   we're matching the argument list of a subroutine.  */
 
 match
-gfc_match_actual_arglist (int sub_flag, gfc_actual_arglist ** argp)
+gfc_match_actual_arglist (int sub_flag, gfc_actual_arglist **argp)
 {
   gfc_actual_arglist *head, *tail;
   int seen_keyword;
@@ -1407,7 +1520,7 @@ gfc_match_actual_arglist (int sub_flag, gfc_actual_arglist ** argp)
   match m;
 
   *argp = tail = NULL;
-  old_loc = *gfc_current_locus ();
+  old_loc = gfc_current_locus;
 
   seen_keyword = 0;
 
@@ -1430,7 +1543,7 @@ gfc_match_actual_arglist (int sub_flag, gfc_actual_arglist ** argp)
 
       if (sub_flag && gfc_match_char ('*') == MATCH_YES)
        {
-         m = gfc_match_st_label (&label, 0);
+         m = gfc_match_st_label (&label);
          if (m == MATCH_NO)
            gfc_error ("Expected alternate return label at %C");
          if (m != MATCH_YES)
@@ -1441,7 +1554,7 @@ gfc_match_actual_arglist (int sub_flag, gfc_actual_arglist ** argp)
        }
 
       /* After the first keyword argument is seen, the following
-         arguments must also have keywords.  */
+        arguments must also have keywords.  */
       if (seen_keyword)
        {
          m = match_keyword_arg (tail, head);
@@ -1450,21 +1563,28 @@ gfc_match_actual_arglist (int sub_flag, gfc_actual_arglist ** argp)
            goto cleanup;
          if (m == MATCH_NO)
            {
-             gfc_error
-               ("Missing keyword name in actual argument list at %C");
+             gfc_error ("Missing keyword name in actual argument list at %C");
              goto cleanup;
            }
 
        }
       else
        {
-         /* See if we have the first keyword argument.  */
-         m = match_keyword_arg (tail, head);
-         if (m == MATCH_YES)
-           seen_keyword = 1;
+         /* Try an argument list function, like %VAL.  */
+         m = match_arg_list_function (tail);
          if (m == MATCH_ERROR)
            goto cleanup;
 
+         /* See if we have the first keyword argument.  */
+         if (m == MATCH_NO)
+           {
+             m = match_keyword_arg (tail, head);
+             if (m == MATCH_YES)
+               seen_keyword = 1;
+             if (m == MATCH_ERROR)
+               goto cleanup;
+           }
+
          if (m == MATCH_NO)
            {
              /* Try for a non-keyword argument.  */
@@ -1476,6 +1596,7 @@ gfc_match_actual_arglist (int sub_flag, gfc_actual_arglist ** argp)
            }
        }
 
+
     next:
       if (gfc_match_char (')') == MATCH_YES)
        break;
@@ -1491,7 +1612,7 @@ syntax:
 
 cleanup:
   gfc_free_actual_arglist (head);
-  gfc_set_locus (&old_loc);
+  gfc_current_locus = old_loc;
 
   return MATCH_ERROR;
 }
@@ -1501,9 +1622,8 @@ cleanup:
    element.  */
 
 static gfc_ref *
-extend_ref (gfc_expr * primary, gfc_ref * tail)
+extend_ref (gfc_expr *primary, gfc_ref *tail)
 {
-
   if (primary->ref == NULL)
     primary->ref = tail = gfc_get_ref ();
   else
@@ -1524,33 +1644,45 @@ extend_ref (gfc_expr * primary, gfc_ref * tail)
    statement.  */
 
 static match
-match_varspec (gfc_expr * primary, int equiv_flag)
+match_varspec (gfc_expr *primary, int equiv_flag)
 {
   char name[GFC_MAX_SYMBOL_LEN + 1];
   gfc_ref *substring, *tail;
   gfc_component *component;
-  gfc_symbol *sym;
+  gfc_symbol *sym = primary->symtree->n.sym;
   match m;
 
   tail = NULL;
 
-  if (primary->symtree->n.sym->attr.dimension
-      || (equiv_flag
-         && gfc_peek_char () == '('))
+  if ((equiv_flag && gfc_peek_char () == '(') || sym->attr.dimension)
     {
-
+      /* In EQUIVALENCE, we don't know yet whether we are seeing
+        an array, character variable or array of character
+        variables.  We'll leave the decision till resolve time.  */
       tail = extend_ref (primary, tail);
       tail->type = REF_ARRAY;
 
-      m = gfc_match_array_ref (&tail->u.ar, primary->symtree->n.sym->as,
-                               equiv_flag);
+      m = gfc_match_array_ref (&tail->u.ar, equiv_flag ? NULL : sym->as,
+                              equiv_flag);
       if (m != MATCH_YES)
        return m;
+
+      if (equiv_flag && gfc_peek_char () == '(')
+       {
+         tail = extend_ref (primary, tail);
+         tail->type = REF_ARRAY;
+
+         m = gfc_match_array_ref (&tail->u.ar, NULL, equiv_flag);
+         if (m != MATCH_YES)
+           return m;
+       }
     }
 
-  sym = primary->symtree->n.sym;
   primary->ts = sym->ts;
 
+  if (equiv_flag)
+    return MATCH_YES;
+
   if (sym->ts.type != BT_DERIVED || gfc_match_char ('%') != MATCH_YES)
     goto check_substring;
 
@@ -1594,6 +1726,15 @@ match_varspec (gfc_expr * primary, int equiv_flag)
     }
 
 check_substring:
+  if (primary->ts.type == BT_UNKNOWN)
+    {
+      if (gfc_get_default_type (sym, sym->ns)->type == BT_CHARACTER)
+       {
+        gfc_set_default_type (sym, 0, sym->ns);
+        primary->ts = sym->ts;
+       }
+    }
+
   if (primary->ts.type == BT_CHARACTER)
     {
       switch (match_substring (primary->ts.cl, equiv_flag, &substring))
@@ -1607,6 +1748,9 @@ check_substring:
          if (primary->expr_type == EXPR_CONSTANT)
            primary->expr_type = EXPR_SUBSTRING;
 
+         if (substring)
+           primary->ts.cl = NULL;
+
          break;
 
        case MATCH_NO:
@@ -1636,12 +1780,12 @@ check_substring:
    dumped).  If we see a full part or section of an array, the
    expression is also an array.
 
-   We can have at most one full array reference. */
+   We can have at most one full array reference.  */
 
 symbol_attribute
-gfc_variable_attr (gfc_expr * expr, gfc_typespec * ts)
+gfc_variable_attr (gfc_expr *expr, gfc_typespec *ts)
 {
-  int dimension, pointer, target;
+  int dimension, pointer, allocatable, target;
   symbol_attribute attr;
   gfc_ref *ref;
 
@@ -1653,6 +1797,7 @@ gfc_variable_attr (gfc_expr * expr, gfc_typespec * ts)
 
   dimension = attr.dimension;
   pointer = attr.pointer;
+  allocatable = attr.allocatable;
 
   target = attr.target;
   if (pointer)
@@ -1673,12 +1818,12 @@ gfc_variable_attr (gfc_expr * expr, gfc_typespec * ts)
            break;
 
          case AR_SECTION:
-           pointer = 0;
+           allocatable = pointer = 0;
            dimension = 1;
            break;
 
          case AR_ELEMENT:
-           pointer = 0;
+           allocatable = pointer = 0;
            break;
 
          case AR_UNKNOWN:
@@ -1693,18 +1838,20 @@ gfc_variable_attr (gfc_expr * expr, gfc_typespec * ts)
          *ts = ref->u.c.component->ts;
 
        pointer = ref->u.c.component->pointer;
+       allocatable = ref->u.c.component->allocatable;
        if (pointer)
          target = 1;
 
        break;
 
       case REF_SUBSTRING:
-       pointer = 0;
+       allocatable = pointer = 0;
        break;
       }
 
   attr.dimension = dimension;
   attr.pointer = pointer;
+  attr.allocatable = allocatable;
   attr.target = target;
 
   return attr;
@@ -1714,7 +1861,7 @@ gfc_variable_attr (gfc_expr * expr, gfc_typespec * ts)
 /* Return the attribute from a general expression.  */
 
 symbol_attribute
-gfc_expr_attr (gfc_expr * e)
+gfc_expr_attr (gfc_expr *e)
 {
   symbol_attribute attr;
 
@@ -1731,7 +1878,7 @@ gfc_expr_attr (gfc_expr * e)
        attr = e->value.function.esym->result->attr;
 
       /* TODO: NULL() returns pointers.  May have to take care of this
-         here.  */
+        here.  */
 
       break;
 
@@ -1748,7 +1895,7 @@ gfc_expr_attr (gfc_expr * e)
    seen.  */
 
 match
-gfc_match_structure_constructor (gfc_symbol * sym, gfc_expr ** result)
+gfc_match_structure_constructor (gfc_symbol *sym, gfc_expr **result)
 {
   gfc_constructor *head, *tail;
   gfc_component *comp;
@@ -1761,7 +1908,7 @@ gfc_match_structure_constructor (gfc_symbol * sym, gfc_expr ** result)
   if (gfc_match_char ('(') != MATCH_YES)
     goto syntax;
 
-  where = *gfc_current_locus ();
+  where = gfc_current_locus;
 
   gfc_find_component (sym, NULL);
 
@@ -1785,8 +1932,7 @@ gfc_match_structure_constructor (gfc_symbol * sym, gfc_expr ** result)
        {
          if (comp->next == NULL)
            {
-             gfc_error
-               ("Too many components in structure constructor at %C");
+             gfc_error ("Too many components in structure constructor at %C");
              goto cleanup;
            }
 
@@ -1831,23 +1977,26 @@ cleanup:
    array reference, argument list of a function, etc.  */
 
 match
-gfc_match_rvalue (gfc_expr ** result)
+gfc_match_rvalue (gfc_expr **result)
 {
   gfc_actual_arglist *actual_arglist;
-  char name[GFC_MAX_SYMBOL_LEN + 1];
+  char name[GFC_MAX_SYMBOL_LEN + 1], argname[GFC_MAX_SYMBOL_LEN + 1];
   gfc_state_data *st;
   gfc_symbol *sym;
   gfc_symtree *symtree;
-  locus where;
+  locus where, old_loc;
   gfc_expr *e;
-  match m;
+  match m, m2;
   int i;
+  gfc_typespec *ts;
+  bool implicit_char;
 
   m = gfc_match_name (name);
   if (m != MATCH_YES)
     return m;
 
-  if (gfc_find_state (COMP_INTERFACE) == SUCCESS)
+  if (gfc_find_state (COMP_INTERFACE) == SUCCESS
+      && !gfc_current_ns->has_import_set)
     i = gfc_get_sym_tree (name, NULL, &symtree);
   else
     i = gfc_get_ha_sym_tree (name, &symtree);
@@ -1857,15 +2006,43 @@ gfc_match_rvalue (gfc_expr ** result)
 
   sym = symtree->n.sym;
   e = NULL;
-  where = *gfc_current_locus ();
+  where = gfc_current_locus;
 
   gfc_set_sym_referenced (sym);
 
-  if (sym->attr.function && sym->result == sym
-      && (gfc_current_ns->proc_name == sym
+  if (sym->attr.function && sym->result == sym)
+    {
+      /* See if this is a directly recursive function call.  */
+      gfc_gobble_whitespace ();
+      if (sym->attr.recursive
+         && gfc_peek_char () == '('
+         && gfc_current_ns->proc_name == sym)
+       {
+         if (!sym->attr.dimension)
+           goto function0;
+
+         gfc_error ("'%s' is array valued and directly recursive "
+                    "at %C , so the keyword RESULT must be specified "
+                    "in the FUNCTION statement", sym->name);
+         return MATCH_ERROR;
+       }
+       
+      if (gfc_current_ns->proc_name == sym
          || (gfc_current_ns->parent != NULL
-             && gfc_current_ns->parent->proc_name == sym)))
-    goto variable;
+             && gfc_current_ns->parent->proc_name == sym))
+       goto variable;
+
+      if (sym->attr.entry
+         && (sym->ns == gfc_current_ns
+             || sym->ns == gfc_current_ns->parent))
+       {
+         gfc_entry_list *el = NULL;
+         
+         for (el = sym->ns->entries; el; el = el->next)
+           if (sym == el->sym)
+             goto variable;
+       }
+    }
 
   if (sym->attr.function || sym->attr.external || sym->attr.intrinsic)
     goto function0;
@@ -1890,8 +2067,11 @@ gfc_match_rvalue (gfc_expr ** result)
       break;
 
     case FL_PARAMETER:
-      if (sym->value
-         && sym->value->expr_type != EXPR_ARRAY)
+      /* A statement of the form "REAL, parameter :: a(0:10) = 1" will
+        end up here.  Unfortunately, sym->value->expr_type is set to 
+        EXPR_CONSTANT, and so the if () branch would be followed without
+        the !sym->as check.  */
+      if (sym->value && sym->value->expr_type != EXPR_ARRAY && !sym->as)
        e = gfc_copy_expr (sym->value);
       else
        {
@@ -1908,7 +2088,7 @@ gfc_match_rvalue (gfc_expr ** result)
       if (sym == NULL)
        m = MATCH_ERROR;
       else
-        m = gfc_match_structure_constructor (sym, &e);
+       m = gfc_match_structure_constructor (sym, &e);
       break;
 
     /* If we're here, then the name is known to be the name of a
@@ -1923,9 +2103,9 @@ gfc_match_rvalue (gfc_expr ** result)
        }
 
       /* At this point, the name has to be a non-statement function.
-         If the name is the same as the current function being
-         compiled, then we have a variable reference (to the function
-         result) if the name is non-recursive.  */
+        If the name is the same as the current function being
+        compiled, then we have a variable reference (to the function
+        result) if the name is non-recursive.  */
 
       st = gfc_enclosing_unit (NULL);
 
@@ -1970,13 +2150,13 @@ gfc_match_rvalue (gfc_expr ** result)
       e->symtree = symtree;
       e->expr_type = EXPR_FUNCTION;
       e->value.function.actual = actual_arglist;
-      e->where = *gfc_current_locus ();
+      e->where = gfc_current_locus;
 
       if (sym->as != NULL)
        e->rank = sym->as->rank;
 
       if (!sym->attr.function
-         && gfc_add_function (&sym->attr, NULL) == FAILURE)
+         && gfc_add_function (&sym->attr, sym->name, NULL) == FAILURE)
        {
          m = MATCH_ERROR;
          break;
@@ -1991,19 +2171,21 @@ gfc_match_rvalue (gfc_expr ** result)
     case FL_UNKNOWN:
 
       /* Special case for derived type variables that get their types
-         via an IMPLICIT statement.  This can't wait for the
-         resolution phase.  */
+        via an IMPLICIT statement.  This can't wait for the
+        resolution phase.  */
 
       if (gfc_peek_char () == '%'
+         && sym->ts.type == BT_UNKNOWN
          && gfc_get_default_type (sym, sym->ns)->type == BT_DERIVED)
        gfc_set_default_type (sym, 0, sym->ns);
 
       /* If the symbol has a dimension attribute, the expression is a
-         variable.  */
+        variable.  */
 
       if (sym->attr.dimension)
        {
-         if (gfc_add_flavor (&sym->attr, FL_VARIABLE, NULL) == FAILURE)
+         if (gfc_add_flavor (&sym->attr, FL_VARIABLE,
+                             sym->name, NULL) == FAILURE)
            {
              m = MATCH_ERROR;
              break;
@@ -2017,8 +2199,8 @@ gfc_match_rvalue (gfc_expr ** result)
        }
 
       /* Name is not an array, so we peek to see if a '(' implies a
-         function call or a substring reference.  Otherwise the
-         variable is just a scalar.  */
+        function call or a substring reference.  Otherwise the
+        variable is just a scalar.  */
 
       gfc_gobble_whitespace ();
       if (gfc_peek_char () != '(')
@@ -2028,7 +2210,8 @@ gfc_match_rvalue (gfc_expr ** result)
          e->symtree = symtree;
          e->expr_type = EXPR_VARIABLE;
 
-         if (gfc_add_flavor (&sym->attr, FL_VARIABLE, NULL) == FAILURE)
+         if (gfc_add_flavor (&sym->attr, FL_VARIABLE,
+                             sym->name, NULL) == FAILURE)
            {
              m = MATCH_ERROR;
              break;
@@ -2039,35 +2222,61 @@ gfc_match_rvalue (gfc_expr ** result)
          break;
        }
 
-      /* See if this could possibly be a substring reference of a name
-         that we're not sure is a variable yet.  */
+      /* See if this is a function reference with a keyword argument
+        as first argument. We do this because otherwise a spurious
+        symbol would end up in the symbol table.  */
+
+      old_loc = gfc_current_locus;
+      m2 = gfc_match (" ( %n =", argname);
+      gfc_current_locus = old_loc;
 
       e = gfc_get_expr ();
       e->symtree = symtree;
 
-      if ((sym->ts.type == BT_UNKNOWN || sym->ts.type == BT_CHARACTER)
-         && match_substring (sym->ts.cl, 0, &e->ref) == MATCH_YES)
+      if (m2 != MATCH_YES)
        {
-
-         e->expr_type = EXPR_VARIABLE;
-
-         if (sym->attr.flavor != FL_VARIABLE
-             && gfc_add_flavor (&sym->attr, FL_VARIABLE, NULL) == FAILURE)
+         /* Try to figure out whether we're dealing with a character type.
+            We're peeking ahead here, because we don't want to call 
+            match_substring if we're dealing with an implicitly typed
+            non-character variable.  */
+         implicit_char = false;
+         if (sym->ts.type == BT_UNKNOWN)
            {
-             m = MATCH_ERROR;
-             break;
+             ts = gfc_get_default_type (sym,NULL);
+             if (ts->type == BT_CHARACTER)
+               implicit_char = true;
            }
 
-         if (sym->ts.type == BT_UNKNOWN
-             && gfc_set_default_type (sym, 1, NULL) == FAILURE)
+         /* See if this could possibly be a substring reference of a name
+            that we're not sure is a variable yet.  */
+
+         if ((implicit_char || sym->ts.type == BT_CHARACTER)
+             && match_substring (sym->ts.cl, 0, &e->ref) == MATCH_YES)
            {
-             m = MATCH_ERROR;
+
+             e->expr_type = EXPR_VARIABLE;
+
+             if (sym->attr.flavor != FL_VARIABLE
+                 && gfc_add_flavor (&sym->attr, FL_VARIABLE,
+                                    sym->name, NULL) == FAILURE)
+               {
+                 m = MATCH_ERROR;
+                 break;
+               }
+
+             if (sym->ts.type == BT_UNKNOWN
+                 && gfc_set_default_type (sym, 1, NULL) == FAILURE)
+               {
+                 m = MATCH_ERROR;
+                 break;
+               }
+
+             e->ts = sym->ts;
+             if (e->ref)
+               e->ts.cl = NULL;
+             m = MATCH_YES;
              break;
            }
-
-         e->ts = sym->ts;
-         m = MATCH_YES;
-         break;
        }
 
       /* Give up, assume we have a function.  */
@@ -2077,7 +2286,7 @@ gfc_match_rvalue (gfc_expr ** result)
       e->expr_type = EXPR_FUNCTION;
 
       if (!sym->attr.function
-         && gfc_add_function (&sym->attr, NULL) == FAILURE)
+         && gfc_add_function (&sym->attr, sym->name, NULL) == FAILURE)
        {
          m = MATCH_ERROR;
          break;
@@ -2096,7 +2305,7 @@ gfc_match_rvalue (gfc_expr ** result)
        }
 
       /* If our new function returns a character, array or structure
-         type, it might have subsequent references.  */
+        type, it might have subsequent references.  */
 
       m = match_varspec (e, 0);
       if (m == MATCH_NO)
@@ -2135,10 +2344,15 @@ gfc_match_rvalue (gfc_expr ** result)
    starts as a symbol, can be a structure component or an array
    reference.  It can be a function if the function doesn't have a
    separate RESULT variable.  If the symbol has not been previously
-   seen, we assume it is a variable.  */
+   seen, we assume it is a variable.
 
-match
-gfc_match_variable (gfc_expr ** result, int equiv_flag)
+   This function is called by two interface functions:
+   gfc_match_variable, which has host_flag = 1, and
+   gfc_match_equiv_variable, with host_flag = 0, to restrict the
+   match of the symbol to the local scope.  */
+
+static match
+match_variable (gfc_expr **result, int equiv_flag, int host_flag)
 {
   gfc_symbol *sym;
   gfc_symtree *st;
@@ -2146,44 +2360,58 @@ gfc_match_variable (gfc_expr ** result, int equiv_flag)
   locus where;
   match m;
 
-  m = gfc_match_sym_tree (&st, 1);
+  /* Since nothing has any business being an lvalue in a module
+     specification block, an interface block or a contains section,
+     we force the changed_symbols mechanism to work by setting
+     host_flag to 0. This prevents valid symbols that have the name
+     of keywords, such as 'end', being turned into variables by
+     failed matching to assignments for, eg., END INTERFACE.  */
+  if (gfc_current_state () == COMP_MODULE
+      || gfc_current_state () == COMP_INTERFACE
+      || gfc_current_state () == COMP_CONTAINS)
+    host_flag = 0;
+
+  m = gfc_match_sym_tree (&st, host_flag);
   if (m != MATCH_YES)
     return m;
-  where = *gfc_current_locus ();
+  where = gfc_current_locus;
 
   sym = st->n.sym;
   gfc_set_sym_referenced (sym);
   switch (sym->attr.flavor)
     {
     case FL_VARIABLE:
+      if (sym->attr.protected && sym->attr.use_assoc)
+       {
+         gfc_error ("Assigning to PROTECTED variable at %C");
+         return MATCH_ERROR;
+       }
       break;
 
     case FL_UNKNOWN:
-      if (gfc_add_flavor (&sym->attr, FL_VARIABLE, NULL) == FAILURE)
+      if (gfc_add_flavor (&sym->attr, FL_VARIABLE,
+                         sym->name, NULL) == FAILURE)
        return MATCH_ERROR;
+      break;
 
-      /* Special case for derived type variables that get their types
-         via an IMPLICIT statement.  This can't wait for the
-         resolution phase.  */
-
-      if (gfc_peek_char () == '%'
-         && gfc_get_default_type (sym, sym->ns)->type == BT_DERIVED)
-       gfc_set_default_type (sym, 0, sym->ns);
-
+    case FL_PARAMETER:
+      if (equiv_flag)
+       gfc_error ("Named constant at %C in an EQUIVALENCE");
+      else
+       gfc_error ("Cannot assign to a named constant at %C");
+      return MATCH_ERROR;
       break;
 
     case FL_PROCEDURE:
       /* Check for a nonrecursive function result */
       if (sym->attr.function && (sym->result == sym || sym->attr.entry))
        {
-
          /* If a function result is a derived type, then the derived
             type may still have to be resolved.  */
 
          if (sym->ts.type == BT_DERIVED
              && gfc_use_derived (sym->ts.derived) == NULL)
            return MATCH_ERROR;
-
          break;
        }
 
@@ -2194,6 +2422,24 @@ gfc_match_variable (gfc_expr ** result, int equiv_flag)
       return MATCH_ERROR;
     }
 
+  /* Special case for derived type variables that get their types
+     via an IMPLICIT statement.  This can't wait for the
+     resolution phase.  */
+
+    {
+      gfc_namespace * implicit_ns;
+
+      if (gfc_current_ns->proc_name == sym)
+       implicit_ns = gfc_current_ns;
+      else
+       implicit_ns = sym->ns;
+       
+      if (gfc_peek_char () == '%'
+         && sym->ts.type == BT_UNKNOWN
+         && gfc_get_default_type (sym, implicit_ns)->type == BT_DERIVED)
+       gfc_set_default_type (sym, 0, implicit_ns);
+    }
+
   expr = gfc_get_expr ();
 
   expr->expr_type = EXPR_VARIABLE;
@@ -2212,3 +2458,18 @@ gfc_match_variable (gfc_expr ** result, int equiv_flag)
   *result = expr;
   return MATCH_YES;
 }
+
+
+match
+gfc_match_variable (gfc_expr **result, int equiv_flag)
+{
+  return match_variable (result, equiv_flag, 1);
+}
+
+
+match
+gfc_match_equiv_variable (gfc_expr **result)
+{
+  return match_variable (result, 1, 0);
+}
+