Skip to content

Examples added to namelist delim + reformat #154

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 27, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
197 changes: 144 additions & 53 deletions proposals/namelist_delimiters/namelist_proposal.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,21 @@ Date: 19 November 2019
Proposal for Fortran Standard: 202y


Introduction
============
1. Introduction

According to the current standard, a WRITE statement can write a namelist
file that does not conform to the namelist specification. This happens
when the namelist group contains a character array and the DELIM specifier
has a value of NONE. In particular, this is the default behavior of a
WRITE statement whose input is a namelist.
According to the current standard, a WRITE statement can write a
namelist file that does not conform to the namelist specification. This
happens when the namelist group contains a character array and the DELIM
specifier has a value of NONE. In particular, this is the default
behavior of a WRITE statement whose input is a namelist.

Our proposal is to require delimiters when using WRITE to write a namelist
to a file, by either requiring a value of DELIM which is
Our proposal is to require delimiters when using WRITE to write a
namelist to a file, by either requiring a value of DELIM which is
namelist-compliant, or by overriding a value of NONE when the input is a
namelist.


Motivation
==========
2. Motivation

The namelist format is described in section 13.11 of the standard, and
13.11.3.3p7 requires that character arrays in namelist groups must be
Expand All @@ -34,47 +32,46 @@ delimited with single or double quotes.
delimited by apostrophes or quotes.

Any namelist whose character arrays are non-delimited is non-conformant.
Any parsing of this output is therefore considered to be unformatted, and
the interpretation is at the discretion of the interpreter.
Any parsing of this output is therefore considered to be unformatted,
and the interpretation is at the discretion of the interpreter.

Without delimiters, many character arrays become unparseable. If a
character array contains any lexical tokens, then it is likely that
non-delimited values will be misinterpreted as part of the namelist object
structure. For example, any character array containing a slash ``/`` may
abruptly terminate the current namelist group. Note 13.36 also recognizes
the challenges of distinguishing between non-delimited character arrays and
object names.
character array contains any lexical namelist tokens, such as `&` or
`/`, then any non-delimited values may be misinterpreted as part of the
namelist object structure.

The standard acknowledges the limitations of non-delimited character array
parsing, and specifically directs the interpreter to ignore the value of
DELIM when reading a namelist (12.5.6.8).
The standard acknowledges the limitations of non-delimited character
array parsing, and specifically directs the interpreter to ignore the
value of DELIM when reading a namelist (12.5.6.8).

The scalar-default-char-expr shall evaluate to APOSTROPHE, QUOTE, or
NONE. The DELIM= specifier is permitted only for a connection for
formatted input/output. It specifies the delimiter mode (12.6.2.8) for
list-directed (13.10.4) and namelist (13.11.4.2) output for the
formatted input/output. It specifies the delimiter mode (12.6.2.8)
for list-directed (13.10.4) and namelist (13.11.4.2) output for the
connection. This mode has no effect on input.

However, despite the acknowledgement of the issues above, the default
behavior of a WRITE command is to produce non-delimited character arrays.
From 13.11.4.2p1,
However, despite the acknowledgment of the issues above, the default
behavior of a WRITE command is to produce non-delimited character
arrays. From 13.11.4.2p1,

Values in namelist output records are edited as for list-directed output
(13.10.4).
Values in namelist output records are edited as for list-directed
output (13.10.4).

This is done despite the fact that list-directed output follows different
I/O rules for character arrays. From 13.10.3.1p7 (my emphasis),
This is done despite the fact that list-directed output follows
different I/O rules for character arrays. From 13.10.3.1p7 (my
emphasis),

When the next effective item is of type character, the input form
consists of a **possibly** delimited sequence of zero or more rep-chars
whose kind type parameter is implied by the kind of the effective item.
consists of a **possibly** delimited sequence of zero or more
rep-chars whose kind type parameter is implied by the kind of the
effective item.

The namelist specification 13.11.3.3p7 deliberately omits "possibly" from
its description.
The namelist specification 13.11.3.3p7 deliberately omits "possibly"
from its description.

In other words, list-directed output permits non-delimited arrays, whereas
namelists do not. In addition, the default value of DELIM is to revert
back to its value in the OPEN call. From 12.5.6.8p1,
In other words, list-directed output permits non-delimited arrays,
whereas namelists do not. In addition, the default value of DELIM is to
revert back to its value in the OPEN call. From 12.5.6.8p1,

If this specifier is omitted in an OPEN statement that initiates a
connection, the default value is NONE.
Expand All @@ -83,26 +80,120 @@ The default behavior of a WRITE call using namelist data is therefore to
produce an output which is non-conformant with the namelist standard.


Proposal
========
3. Example

Consider the program listed below, which will produce a namelist
containing a single group `sample_nml`, containing a single character
array, `input`.

program writenml
implicit none
character(len=20) :: input
namelist /sample_nml/ input

input = trim("some/path/to/file")
open(5, file="out.nml")
write(5, nml=sample_nml)
end program writenml

According to the interpretation above, the absence of a DELIM argument
means that `input` is formatted with no delimiter. A
standard-conforming output would be

&SAMPLE_NML
INPUT = some/path/to/file
/

For this example, we have used the output produced by the Intel Fortran
Compiler 19.0.5.281.

Now consider the following program, which reads this namelist.

program readnml
implicit none
character(len=20) :: input
namelist /sample_nml/ input

open(5, file='out.nml')
read(5, nml=sample_nml)

open(6, file='new.nml')
write(6, nml=sample_nml)
end program readnml

The namelist `new.nml` produced by this program is the following.

&SAMPLE_NML
INPUT = some
/

The namelist group `sample_nml` is terminated after the first `/` token,
and any characters following the token are ignored.

Although the interpretation is correct, it also means that a write
statement of the following form

write(unit, nml=filename)

where the DELIM argument is unset will produce namelists which are
non-conforming. The fact that this is not only possible, but is the
default behavior, is counterintuitive and is likely to introduce errors
into namelist I/O operations.

As an aside, we note that GNU Fortran explicitly breaks from the
standard and does produce a quote-delimited namelist, such as the one
shown below.

&SAMPLE_NML
INPUT="some/path/to/file ",
/

This namelist above was produced by GNU Fortran 9.2.1.


4. Proposal

We propose one of the following additions to the *io-control-spec-list*,
detailed in 12.6.2.1.

A. If *namelist-group-name* appears, then a DELIM= specifier with the value
of either APOSTROPHE or QUOTE shall also appear.
A. If *namelist-group-name* appears, then a DELIM= specifier with the
value of either APOSTROPHE or QUOTE shall also appear.

Option A would take the current recommended advice to always use DELIM when
writing namelist output and turn it into an explicit rule. However, it
would cause currently compliant code to be non-compliant, and may require
modifications if used by future interpreters.
Option A would take the current recommended advice to always use DELIM
when writing namelist output and turn it into an explicit rule. The
following statement would constitute an error

B. If *namelist-group-name* appears and a DELIM= specifier has the value of
NONE, then this value is ignored and the data transfer uses a value of
APOSTROPHE.
write(unit, nml=filename)

Option B would change the behavior of existing standard-compliant
interpreters, in that non-delimited character arrays would be replaced with
apostrophe-delimited arrays. But existing source code would otherwise
remain compliant and continue to compile on both older and newer
and would require the user to include a DELIM argument, e.g.

write(unit, nml=filename, delim="quote")

This would also mean that currently compliant code missing a DELIM would
be non-compliant, and may require modifications if used by future
interpreters.

B. If *namelist-group-name* appears and a DELIM= specifier has the value
of NONE, then this value is ignored and the data transfer uses a
value of APOSTROPHE.

Option B would change the behavior of existing standard-compliant
interpreters, in that non-delimited character arrays would be replaced
with apostrophe-delimited arrays. But existing source code would
otherwise remain compliant and continue to compile on both older and
newer interpreters.


5. Reference

Discussion of this issue on the Intel Fortran forums:

https://software.intel.com/en-us/forums/intel-fortran-compiler/topic/831685

Discussion of GNU Fortran's decision to use quote delimiters:

https://gcc.gnu.org/ml/gcc-patches/2014-03/msg00030.html

Initial submission and discussion to the J3 Fortran Github repository:

https://github.com/j3-fortran/fortran_proposals/pull/94