All,

Another quirk of legacy compilers is their syntax for PARAMETER
statements. Such statements are similar to standard PARAMETER
statements but lack parentheses following the PARAMETER keyword. There
is a good reason the standard doesn't support this - because the
statement becomes ambiguous with assignment statements in fixed form.
Consider the following:

        parameter pi = 3.14d0

In fixed form, spaces are ignored so in standard Fortran the above
looks like an assignment to the variable "parameterpi". In legacy
compilers, the above is instead interpreted as

        parameter (pi = 3.14d0)

which of course declares the variable 'pi' to be a parameter with the
value 3.14.

Attached is a patch for the GNU Fortran front-end which allows the
compiler to interpret these legacy PARAMETER statements. The patch in
its current form does this without warning through -std=legacy
(warning for -std=gnu, error for -std=f*). Bootstraps and regtests on
x86_64-redhat-linux.

However, note that this would change by default the compiler's
interpretation of fixed-form variables starting with the string
"parameter", if any such cases existed in real code. IMO fixed form
code is isomorphic to legacy code, so I imagine most users writing
fixed-form/legacy code would intend for a legacy PARAMETER statement,
rather than assignment to variable PARAMETERPI, when writing such a
statement.

Beyond compatibility, one motivation for acceptance/recognizance of
these statements in GNU Fortran is the counterintuitive compile errors
currently seen when compiling legacy code which uses this type of
statement. Because the legacy PARAMETER statement is currently
interpreted as an assignment in fixed-form, and parameter statements
often precede other specification statements in real code, GNU Fortran
complains not about the parameter statement itself but often the
following line with "Unexpected data declaration" or similar. This
serves to confuse the user. An example of this can be seen by
compiling the attached dec_parameter_1.f in fixed form with the
current build of GNU Fortran.

I am amenable to only enabling support for legacy PARAMETER statements
through -fdec, so that the default (-std=gnu) behavior is unchanged
for such cases in fixed form. But this would leave the esoteric
"Unexpected data declaration statement" errors for legacy code without
-fdec. The case would be difficult to detect and work around
specifically since the entire parameter "assignment" statement is
eaten by the time the error comes about.

What do you think?

---
Fritz Reese

Author: Fritz O. Reese <fritzore...@gmail.com>
Date:   Tue Nov 1 12:26:57 2016 -0400

    Support legacy PARAMETER statements with -std=legacy.

        gcc/fortran/
        * decl.c (gfc_match_parameter): Allow omitted '()' with -std=legacy.
        * parse.c (decode_statement): Match "parmeter" before assignments.
        * gfortran.texi: Document.

        gcc/testsuite/gfortran.dg/
        * dec_parameter_1.f: New test.
        * dec_parameter_2.f90: Likewise.
        * dec_parameter_3.f90: Likewise.
        * dec_parameter_4.f90: Likewise.

 gcc/fortran/decl.c                            |   10 +++-
 gcc/fortran/gfortran.texi                     |   16 ++++++
 gcc/fortran/parse.c                           |    4 +-
 gcc/testsuite/gfortran.dg/dec_parameter_1.f   |   64 +++++++++++++++++++++++++
 gcc/testsuite/gfortran.dg/dec_parameter_2.f90 |   63 ++++++++++++++++++++++++
 gcc/testsuite/gfortran.dg/dec_parameter_3.f90 |   13 +++++
 gcc/testsuite/gfortran.dg/dec_parameter_4.f90 |   13 +++++
 7 files changed, 180 insertions(+), 3 deletions(-)
diff --git a/gcc/fortran/decl.c b/gcc/fortran/decl.c
index f18eb41..0120ceb 100644
--- a/gcc/fortran/decl.c
+++ b/gcc/fortran/decl.c
@@ -7821,10 +7821,16 @@ cleanup:
 match
 gfc_match_parameter (void)
 {
+  const char *term = " )%t";
   match m;
 
   if (gfc_match_char ('(') == MATCH_NO)
-    return MATCH_NO;
+    {
+      /* With legacy PARAMETER statements, don't expect a terminating ')'.  */
+      if (!gfc_notify_std (GFC_STD_LEGACY, "PARAMETER without '()' at %C"))
+       return MATCH_NO;
+      term = " %t";
+    }
 
   for (;;)
     {
@@ -7832,7 +7838,7 @@ gfc_match_parameter (void)
       if (m != MATCH_YES)
        break;
 
-      if (gfc_match (" )%t") == MATCH_YES)
+      if (gfc_match (term) == MATCH_YES)
        break;
 
       if (gfc_match_char (',') != MATCH_YES)
diff --git a/gcc/fortran/gfortran.texi b/gcc/fortran/gfortran.texi
index 85ab31b..1d60551 100644
--- a/gcc/fortran/gfortran.texi
+++ b/gcc/fortran/gfortran.texi
@@ -1472,6 +1472,7 @@ compatibility extensions along with those enabled by 
@option{-std=legacy}.
 * Bitwise logical operators::
 * Extended I/O specifiers::
 * Default exponents::
+* Legacy PARAMETER statements::
 @end menu
 
 @node Old-style kind specifications
@@ -2705,6 +2706,21 @@ For compatibility, GNU Fortran supports a default 
exponent of zero in real
 constants with @option{-fdec}.  For example, @code{9e} would be
 interpreted as @code{9e0}, rather than an error.
 
+@node Legacy PARAMETER statements
+@subsection Legacy PARAMETER statements
+@cindex PARAMETER
+
+For compatibility, GNU Fortran supports legacy PARAMETER statements without
+parentheses with @option{-std=legacy}.  A warning is emitted if used with
+@option{-std=gnu}, and an error is acknowledged with a real Fortran standard
+flag (@option{-std=f95}, etc...).  These statements take the following form:
+
+@smallexample
+implicit real (E)
+parameter e = 2.718282
+real c
+parameter c = 3.0e8
+@end smallexample
 
 @node Extensions not implemented in GNU Fortran
 @section Extensions not implemented in GNU Fortran
diff --git a/gcc/fortran/parse.c b/gcc/fortran/parse.c
index 2aa2afc..0ee054a 100644
--- a/gcc/fortran/parse.c
+++ b/gcc/fortran/parse.c
@@ -352,6 +352,9 @@ decode_statement (void)
     }
   gfc_matching_function = false;
 
+  /* Legacy parameter statements are ambiguous with assignments so try 
parameter
+     first.  */
+  match ("parameter", gfc_match_parameter, ST_PARAMETER);
 
   /* Match statements whose error messages are meant to be overwritten
      by something better.  */
@@ -528,7 +531,6 @@ decode_statement (void)
 
     case 'p':
       match ("print", gfc_match_print, ST_WRITE);
-      match ("parameter", gfc_match_parameter, ST_PARAMETER);
       match ("pause", gfc_match_pause, ST_PAUSE);
       match ("pointer", gfc_match_pointer, ST_ATTR_DECL);
       if (gfc_match_private (&st) == MATCH_YES)
diff --git a/gcc/testsuite/gfortran.dg/dec_parameter_1.f 
b/gcc/testsuite/gfortran.dg/dec_parameter_1.f
new file mode 100644
index 0000000..69ffa53
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/dec_parameter_1.f
@@ -0,0 +1,64 @@
+        ! { dg-do run }
+        ! { dg-options "-ffixed-form -std=legacy" }
+        !
+        ! Test DEC-style PARAMETER statements without parentheses in
+        ! fixed form.
+        !
+
+        subroutine sub1(t, x, y)
+          implicit real(8) (A-H,O-Z)
+          parameter   (pi_1 = 3.141592654d0, f_1 = 3.d08)
+          parameter    pi_2 = 3.141592654d0, f_2 = 3.d08
+          ! Note that if the parameter statements above are matched
+          ! incorrectly as assignments, the below specification
+          ! statements will be considered out-of-order and we see
+          ! 'unexpected specification statement'. A PARAMETER
+          ! statement should still be a specification statement.
+
+          real(8), intent(in) :: t
+          real(8), intent(out) :: x, y
+
+          real(8), volatile :: two
+          two = 2.0d0
+          x = two * pi_1 * f_1 * t
+          y = two * pi_2 * f_2 * t
+          z = two * pi_3 * f_3 * t
+          return
+        end subroutine
+
+        subroutine sub2(t, x, y, z)
+          implicit none
+          real(8) :: pi_1, pi_2, f_1, f_2
+                   parameter   (pi_1 = 3.141592654d0, f_1 = 3.d08)
+                   parameter    pi_2 = 3.141592654d0, f_2 = 3.d08
+          real(8), parameter :: pi_3 = 3.141592654d0, f_3 = 3.d08
+          ! Ditto sub1
+
+          real(8), intent(in) :: t
+          real(8), intent(out) :: x, y, z
+
+          real(8), volatile :: two
+          two = 2.0d0
+          x = two * pi_1 * f_1 * t
+          y = two * pi_2 * f_2 * t
+          z = two * pi_3 * f_3 * t
+        end subroutine
+
+        implicit none
+        real(8) :: x1, x2, y1, y2, z2
+        real(8), volatile :: t
+        t = 1.5e-6
+
+        call sub1(t, x1, y1)
+        call sub2(t, x2, y2, z2)
+
+        write(*,'(4D18.5)') t, x1, y1
+        write(*,'(4D18.5)') t, x2, y2, z2
+
+        if (x1 .ne. x2 .or. y1 .ne. y2
+     &      .or. x1 .ne. y1 .or. x2 .ne. y2
+     &      .or. y2 .ne. z2) then
+          call abort()
+        endif
+
+        end
diff --git a/gcc/testsuite/gfortran.dg/dec_parameter_2.f90 
b/gcc/testsuite/gfortran.dg/dec_parameter_2.f90
new file mode 100644
index 0000000..280f000
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/dec_parameter_2.f90
@@ -0,0 +1,63 @@
+! { dg-do run }
+! { dg-options "-ffree-form -std=legacy" }
+!
+! Test DEC-style PARAMETER statements without parentheses in free form.
+!
+
+subroutine sub1(t, x, y)
+  implicit real(8) (A-H,O-Z)
+  parameter   (pi_1 = 3.141592654d0, f_1 = 3.d08)
+  parameter    pi_2 = 3.141592654d0, f_2 = 3.d08 ! legacy PARAMETER
+  ! Note that if the parameter statements above are matched
+  ! incorrectly as assignments, the below specification
+  ! statements will be considered out-of-order and we see
+  ! 'unexpected specification statement'. A PARAMETER
+  ! statement should still be a specification statement.
+
+  real(8), intent(in) :: t
+  real(8), intent(out) :: x, y
+
+  real(8), volatile :: two
+  two = 2.0d0
+  x = two * pi_1 * f_1 * t
+  y = two * pi_2 * f_2 * t
+  z = two * pi_3 * f_3 * t
+  return
+end subroutine
+
+subroutine sub2(t, x, y, z)
+  implicit none
+  real(8) :: pi_1, pi_2, f_1, f_2
+           parameter   (pi_1 = 3.141592654d0, f_1 = 3.d08)
+           parameter    pi_2 = 3.141592654d0, f_2 = 3.d08 ! legacy PARAMETER
+  real(8), parameter :: pi_3 = 3.141592654d0, f_3 = 3.d08
+  ! Ditto sub1
+
+  real(8), intent(in) :: t
+  real(8), intent(out) :: x, y, z
+
+  real(8), volatile :: two
+  two = 2.0d0
+  x = two * pi_1 * f_1 * t
+  y = two * pi_2 * f_2 * t
+  z = two * pi_3 * f_3 * t
+end subroutine
+
+implicit none
+real(8) :: x1, x2, y1, y2, z2
+real(8), volatile :: t
+t = 1.5e-6
+
+call sub1(t, x1, y1)
+call sub2(t, x2, y2, z2)
+
+write(*,'(4D18.5)') t, x1, y1
+write(*,'(4D18.5)') t, x2, y2, z2
+
+if (x1 .ne. x2 .or. y1 .ne. y2 &
+    .or. x1 .ne. y1 .or. x2 .ne. y2 &
+    .or. y2 .ne. z2) then
+  call abort()
+endif
+
+end
diff --git a/gcc/testsuite/gfortran.dg/dec_parameter_3.f90 
b/gcc/testsuite/gfortran.dg/dec_parameter_3.f90
new file mode 100644
index 0000000..92f0f61
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/dec_parameter_3.f90
@@ -0,0 +1,13 @@
+! { dg-do compile }
+! { dg-options "-ffree-form -std=gnu" }
+!
+! Test warnings for DEC-style PARAMETER statements with std=gnu.
+!
+
+subroutine sub()
+  implicit real(8) (A-Z)
+  parameter pi = 3.1415926535d0 ! { dg-warning "Legacy Extension: PARAMETER" }
+  print *, pi
+end subroutine
+
+end
diff --git a/gcc/testsuite/gfortran.dg/dec_parameter_4.f90 
b/gcc/testsuite/gfortran.dg/dec_parameter_4.f90
new file mode 100644
index 0000000..280d56c
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/dec_parameter_4.f90
@@ -0,0 +1,13 @@
+! { dg-do compile }
+! { dg-options "-ffree-form -std=f95" }
+!
+! Test errors for DEC-style PARAMETER statements with a real standard.
+!
+
+subroutine sub()
+  implicit real(8) (A-Z)
+  parameter pi = 3.1415926535d0 ! { dg-error "Legacy Extension: PARAMETER" }
+  print *, pi
+end subroutine
+
+end

Reply via email to