Hollerith data statements - fortran

The below refers to fortran 66 code. Trying to recompile very old programs. Cannot understand the reason for the error. Need work around recommendations. trying not to recode in updated fortran.
DATA NPOP/6HPOPS-I,6HPOPS-D,6HPOPS-C,6HPOPS-A,6HPOPS-E,6HPOP-S /
^
Truncating characters on right side of hollerith constant at (^) azthree.for:24:
DATA NPOP/6HPOPS-I,6HPOPS-D,6HPOPS-C,6HPOPS-A,6HPOPS-E,6HPOP-S /
^
Truncating characters on right side of hollerith constant at (^) azthree.for:24:
DATA NPOP/6HPOPS-I,6HPOPS-D,6HPOPS-C,6HPOPS-A,6HPOPS-E,6HPOP-S /
^

I've never used Fortran66, but Hollerith constants declare the next characters as data, not code. So 6H would mean something like: The 6 characters after the H are supposed to be data, not code.
In essence, I would think that 6HPOPS-I would be the same as "POPS-I".
Maybe if you could give us the declaration of NPOP that would help to understand the issue.
I have kind of recreated the error message with this code:
PROGRAM holl
IMPLICIT NONE
CHARACTER*1 NPOP(6)
INTEGER i
DATA NPOP / 6HPOPS-I,6HPOPS-D,6HPOPS-C,
+ 6HPOPS-A,6HPOPS-E,6HPOP-S /
DO 100 i = 1, 6
PRINT *, NPOP(i)
100 CONTINUE
END PROGRAM
This gives the compiler warnings:
$ gfortran -o holl holl.f
holl.f:6.38:
+ 6HPOPS-A,6HPOPS-E,6HPOP-S /
1
Warning: Legacy Extension: Hollerith constant at (1)
holl.f:5.20:
DATA NPOP / 6HPOPS-I,6HPOPS-D,6HPOPS-C,
1
Warning: Initialization string starting at (1) was truncated to fit the variable (1/6)
holl.f:5.29:
DATA NPOP / 6HPOPS-I,6HPOPS-D,6HPOPS-C,
1
Warning: Initialization string starting at (1) was truncated to fit the variable (1/6)
But it's not quite your errors. I don't know which compiler you use, and in your case, the marker for the truncation seems to point to the H itself.
So we really need more info from you:
More code, specifically the declaration of NPOP
Compiler version and -options

Related

How to translate from EQUIVALENCE to index offset [duplicate]

This question already has answers here:
Syntax error in call statement in Fortran
(1 answer)
Incompatible ranks 0 and 2 in assignment [duplicate]
(1 answer)
Closed 4 years ago.
I am trying to modernize a Fortran 77 codebase which makes heavy use of common blocks in include files. One of my goals is to translate the codebase so it uses modules instead of this common/include construction. However, the code also uses equivalence statements here and there, referring to common variables. It is not allowed to equivalence to/from module variables, so this is a problem.
Now, luckily, the equivalence statements are only used to alias (parts of) arrays and never for 'magic' between different variables types. Therefore I have tried to translate the code by simply calculating index offsets and referring to the original arrays instead of equivalenc-ing them. However, this has lead to some unexpected compilation errors and runtime crashes.
For example, consider the change from
IF(RLX*ABS(DXT/(X2-X1)) .GT. 0.05) RLX = 0.05*ABS((X2-X1)/DXT)
to
IF(RLX*ABS(DXT/(COM2(1)-COM1(1))) .GT. 0.05) RLX = 0.05*ABS((COM2(1)-COM1(1))/DXT)
, which is supposed to change the include file code from
REAL COM1(NCOM), COM2(NCOM)
COMMON/V_VAR1/ X1
COMMON/V_VAR2/ X2
EQUIVALENCE (X1, COM1(1)), (X2, COM2(1))
to simply
COMMON COM1(NCOM), COM2(NCOM)
, but leads to the following compilation error:
IF(RLX*ABS(DXT/(COM2(1)-COM1(1))) .GT. 0.05) RLX = 0.05*ABS((COM2(1)-COM1(1))/DXT)
1
Error: Missing ')' in statement at or before (1)
This statement seems correct to me, though. So what am I missing here?
If I alleviate the above problem by changing the code to
DX = COM2(1) - COM1(1)
IF(RLX*ABS(DXT/DX) .GT. 0.05) RLX = 0.05*ABS(DX/DXT)
I do not get compilation errors. However, then I run into Signal: SIGFPE (Arithmetic exception)'s at runtime, because for some reason the change from X1 to COM1(1) and X2 to COM2(1) leads to seemingly unrelated variables to not get proper initial values (which leads to division by zero, and consequently to the addition of nan's, and therefore to the arithmetic exception).
Obviously, I am missing something crucial here, so I tried to find a good reference for doing this sort of translation. Does anyone know of something like that? Or has anyone run into this problem before and found a solution? Any help would be greatly appreciated.
As pointed in the comments, the error arises after refactoring the code probably because you are working in fixed-form and the source line cannot go beyond 72 characters (all the remaining characters are ignored).
If you are modernizing the code, you should left fixed-form behind and write in free-form. Sometimes compilers assume source-form based on file extension. If this is the case, you can change the file extension from .f to .f90. Or else, you can pass the desired format as a compiler flag (-ffree-form in gfortran, -free in Intel Fortran).
If by any case you are stuck into fixed-form, you'd better do a line-continuation by putting an arbitrary non-blank character at column 6 of the continued line.

Are Fortran FORMATs done during compile time or execution time?

Part of the FORTRAN Syntax is FORMAT for example:
WRITE(*,10)'this is a string', 'this is a second string', 'this is a third string'
10 FORMAT(1x,a10,1x,a10,1x,a20)
What I want to know is when the code is formatted, is it compile-time or execution-time? How could I test this? Checking the differences in assembly?
The format strings are typically interpreted at runtime. After all those edits it is not that typical after all, see Steve's answer. The answer describes gfortran which might even be less typical, but is important and widespread. Especially when the format string is a character variable (that can be anything), but also the FORMAT statement. You often get an error message for incorrect format only at runtime. For example:
WRITE(*,10) x
10 FORMAT(i0)
END
gives
> ./a.out
At line 8 of file format3.f90 (unit = 6, file = 'stdout')
Fortran runtime error: Expected INTEGER for item 1 in formatted transfer, got REAL
(i0)
^
In your case:
gfortran -O3 format3.f90 -fdump-tree-optimized
gives
dt_parm.0.common.filename = &"format3.f90"[1]{lb: 1 sz: 1};
dt_parm.0.common.line = 1;
dt_parm.0.format = &"(1x,a10,1x,a10,1x,a20)"[1]{lb: 1 sz: 1};
dt_parm.0.format_len = 22;
dt_parm.0.common.flags = 4096;
dt_parm.0.common.unit = 6;
_gfortran_st_write (&dt_parm.0);
_gfortran_transfer_character_write (&dt_parm.0, &"this is a string"[1]{lb: 1 sz: 1}, 16);
_gfortran_transfer_character_write (&dt_parm.0, &"this is a second string"[1]{lb: 1 sz: 1}, 23);
_gfortran_transfer_character_write (&dt_parm.0, &"this is a third string"[1]{lb: 1 sz: 1}, 22);
_gfortran_st_write_done (&dt_parm.0);
dt_parm.0 ={v} {CLOBBER};
The _gfortran_st_write (&dt_parm.0); sets the writing mode and that includes the format string.
You can notice that the format is stored in a character variable and could be interpreted at runtime if necessary, but it is not actually used in the code generated by the compiler. It is potentially used inside _gfortran_transfer_character_write that are part of the libgfortran runtime library.
The above is for gfortran. One can imagine a lot can be actually optimized away and compiled, but I am not aware that compilers do that.
If you are curious, the gfortran format interpretting code is in https://github.com/gcc-mirror/gcc/blob/trunk/libgfortran/io/format.c
The compilers I have worked on have always translated the format to an internal representation at compile time, other than formats stored in a character variable. The run-time system still has to have the ability to "compile" formats at run-time, but the compiler can check for errors. The actual formatting of the output always happens at run-time.

SLATEC - compilation Error

I want to compile the slatec library downloaded at netlike.org.
I wrote a simple Makefile to compile all routines. However, I get an error when compiling the **mach.f files like d1mach.f that contain the machine specific values.
The error occurs only when I (as I should, if I understand the description correctly) uncomment the values for my machine (intel). If I don't do this, the compilation doesn't create an error, but the routine dsos doesn't work, i.e. the iteration doesn't start but instead it always evaluated the test function at the starting point.
The error message:
src/d1mach.f:85:37:
EQUIVALENCE (DMACH(5),LOG10(1))
1
Error: Expecting a comma in EQUIVALENCE at (1)
make: *** [obj/d1mach.o] Error 1
I guess the reason is If a variable name is also a function name (15.5.1), that name must not appear in the list. what I found under point 8.2.1 in the Fortran77 Standard.
Anyone, ever had this issue and solved it?
EDIT:
The short version of d1mach.f is:
DOUBLE PRECISION FUNCTION D1MACH (I)
C
INTEGER SMALL(4)
INTEGER LARGE(4)
INTEGER RIGHT(4)
INTEGER DIVER(4)
INTEGER LOG10(4)
C
DOUBLE PRECISION DMACH(5)
SAVE DMACH
C
EQUIVALENCE (DMACH(1),SMALL(1))
EQUIVALENCE (DMACH(2),LARGE(1))
EQUIVALENCE (DMACH(3),RIGHT(1))
EQUIVALENCE (DMACH(4),DIVER(1))
EQUIVALENCE (DMACH(5),LOG10(1))
C
C
DATA DMACH(1) / Z'0010000000000000' /
DATA DMACH(2) / Z'7FEFFFFFFFFFFFFF' /
DATA DMACH(3) / Z'3CA0000000000000' /
DATA DMACH(4) / Z'3CB0000000000000' /
DATA DMACH(5) / Z'3FD34413509F79FF' /
C
C
IF (I .LT. 1 .OR. I .GT. 5) CALL XERMSG ('SLATEC', 'D1MACH',
+ 'I OUT OF BOUNDS', 1, 2)
C
D1MACH = DMACH(I)
RETURN
C
END

gfortran Error: Integer too big for its kind at (1) [duplicate]

This question already has an answer here:
Fortran: Integer too big for its kind
(1 answer)
Closed 7 years ago.
I want to see integer kind number of gfortran
so I write this line
write(*,"(1X,I20,'correspond to kind ',I2)"),11111111111,kind(11111111111)
There will be compilation error says
precision of type test.f90:67:57: Error: Integer too big for its kind
at (1). Th is check can be disabled with the option -fno-range-check
So I tried recompile with -fno-range-check. But it gives result
-1773790777correspond to kind 4
What is wrong? On the other hand, intel fortran gives no error and correct answer
An integer literal without any kind designation is always of the default kind no matter what value you enter1. There is therefore no much sense to even inquire
kind(111111111111)
the kind of any such literal is always the default kind, provided the value is valid. So the same as kind(1).
All integer kinds have a limited range of values. The largest one you can get using
write(*,*) HUGE(1)
Here instead of 1 you can use any other constant or variable of the integer kind you examine. Most often, the default value of HUGE will be 2147483647 which corresponds to 32-bit integers.
To use larger integer literal constants, use larger non-default kinds.
It doesn't matter if you use the methods from Fortran 90:
integer, parameter :: lk = selected_int_kind(15)
write(*,*) 11111111111_lk
or from Fortran 2008
use iso_fortran_env
integer, parameter :: lk = int64
write(*,*) 11111111111_lk
Both will work. Of course kind(11111111111_lk) will return the value of lk.
1 That is in standard Fortran. Some compilers may promote a large value to a larger kind for you, but only as a non-standard extension. You may be unpleasantly surprised when moving to a compiler, which keeps the standard behaviour.
There may be a better explanation, but this is how I understand it. The short answer is the compiler defaults to a 4 byte integer.
Fortran is statically typed and you have not declared a variable type. The compiler is forced to use the default integer kind, 4 bytes in this case. The kind function simply returns the 'kind' of integer used. The compiler is letting you know that you are trying to assign a value too large for a 4 byte integer. When you apply -fno-range-check the compiler ignores this fact and the value overflows, thus the negative value returned. You can specify that the default integer kind be 8 bytes, -fdefault-integer-8. See the gfortran docs
Example foo.f90:
program foo
write(*,"(1X,I20,' correspond to kind ',I2)"),111111111111,kind(111111111111)
write(*,"(1X,I20,' correspond to kind ',I2)"),11,kind(11)
end program foo
Compiled with:
$ gfortran -fdefault-integer-8 -o foo.exe foo.f90
$ foo
Results in:
111111111111 correspond to kind 8
11 correspond to kind 8
So you can see the compiler is indifferent to the actual value you are testing.
However, I don't think this gets at the root of what you are trying to do, which I assume is to discover the minimum size of integer necessary for a specific numeric value. I don't know of a way to do this off hand with fortran. See this here and here for solutions you might be able to port from C. The second approach looks promising. In a dynamically typed language like Python the type assignment is handled for you.
>>> type(111111111111)
<type 'long'>
>>> type(11111)
<type 'int'>

Fortran DO loop, warning to use integer only

I installed gfortran on my Ubuntu 15.04 system. While compiling Fortran code, the DO loop asks to take integer parameters only and not real values or variables. That includes the loop variable and the step expression. Why can't it take real values too?
The following is a program taken from here, exercise 3.5 of the section nested do loops.
program xytab
implicit none
!constructs a table of z=x/y for values of x from 1 to 2 and
!y from 1 to 4 in steps of .5
real :: x, y, z
print *, ' x y z'
do x = 1,2
do y = 1,4,0.5
z = x/y
print *, x,y,z
end do
end do
end program xytab
The error shown after compiling is:
xytab.f95:8.4:
do y = 1,4,0.5
1
Warning: Deleted feature: Loop variable at (1) must be integer
xytab.f95:8.12:
do y = 1,4,0.5
1
Warning: Deleted feature: Step expression in DO loop at (1) must be integer
xytab.f95:7.3:
do x = 1,2
1
Warning: Deleted feature: Loop variable at (1) must be integer
The Fortran standard now requires that a do construct's loop control is given by (scalar) integer expressions and that the loop variable is a (scalar) integer variable. The loop control consists of the start, step, and stop expressions (your step expression is 0.5). See R818 and R819 (8.1.6.2) of the Fortran 2008 document. That, then, is the short and simple answer: the standard says so.
It's a little more complicated than that, as the messages from the compiler suggest. Using other forms for loop control was present in Fortran up until Fortran 95. That is, from Fortran 95 onward using real expressions is a deleted feature.
What harm is there in using real expressions? Used correctly, one could imagine, there is no harm. But there's real difficulty in portability with them.
Consider
do x=0., 1., 0.1
...
end do
How many iterations? That would be (under the rules of Fortran 90) MAX(INT((m2 – m1 + m3) / m3), 0) where (m1 is the start value (0.), m2 the stop value (1.) and m3 the step value (0.1)). Is that 10 or 11 (or even 9)? It depends entirely on your numeric representation: we recall that 0.1 may not be exactly representable as a real number and INT truncates in converting to integer. You'd also have to worry about repeated addition of real numbers.
So, use integers and do some arithmetic inside the loop
do y_loop = 0, 6
y = 1 + y_loop/2.
...
end do
or
y = 1
do
if (y>4) exit
...
y = y+0.5
end do
Finally, you mention .f90 and .f95 file suffixes. gfortran doesn't take the first to mean that the source code follows the Fortran 90 standard (where the code would be fine). Further, the messages from the compiler are merely warnings, and these can be suppressed using the -std=legacy option. Conversely, using -std=f95 (or later standards) these become errors.
As a bonus fun fact consider the following piece of Fortran 90 code.
real y
integer i
loop_real: do y=1, 4, 0.5
end do loop_real
loop_integer: do i=1, 4, 0.5
end do loop_integer
While the loop named loop_real is valid, that named loop_integer isn't. In the calculation of the iteration count the three expressions are converted to the kind, with kind parameters, of the loop variable. INT(0.5) is 0.