错误:逻辑运算符 '.eq.' 的操作数在 (1) 处为 INTEGER(4)/HOLLERITH。

3

我刚开始学习Fortran,需要帮助。我正在使用SUSE上的gfortran编译我的代码,但遇到以下错误:

200 IF ( ID .EQ. 4HEOT ) GO TO 20
               1

Error: Operands of logical operator '.eq.' at (1) are INTEGER(4)/HOLLERITH

以下是代码的主文件链接,其中1818行显示了错误。

我的文件链接是:https://files.engineering.com/getfile.aspx?folder=cd6961f3-d38b-4e61-a43d-269fa18c7d11&file=sfeng.f

如何修复这个错误?

为了提供一个简化/最小化的示例,我在此处添加了代码:

      SUBROUTINE CDRD ( II )

      IMPLICIT DOUBLE PRECISION (A-H,O-Z)
c     ohad 15/7/08
c      IMPLICIT INTEGER*8 (I-N)
      IMPLICIT INTEGER*4 (I-N)

C*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=C
C     THIS SUBROUTINE READS PROPULSION SYSTEM DRAG DATA.               C
C                                                                      C
C     USE NON-ZERO "II" TO WRITE TABLE DATA.                           C
C*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=C

      CHARACTER*80    TITLE, CDFILE
      DIMENSION       A(100),IREP(30),IDD(4)

      COMMON /UNITS / IU5, IU6, IU7, IU8, IU9, IU16, IU17, IU18
      COMMON /CYUNIT/ IU3, IU4, IU10, IU11, IU12, IU13, IU14, IU15
      COMMON /CYICOM/ IENG, IPRINT, NPRINT, NPDRY, NPAB, NITMAX,
     1                IVAT, LIMCD
      COMMON /CDSIZE/ CDNOZ(5000)
      COMMON /ICDTAB/ ICDDAT(10), NTBL
      COMMON /CDLOC/  LOCCD(5)
      COMMON /CDFIL / CDFILE, A10, A9REF, A10REF, XNOZ, XNREF, RCRV,
     1                NAB, NABREF
C======================================================================C
      IU12  = 12
      IUNIT = IU12
      OPEN (UNIT=IUNIT, FILE=CDFILE, STATUS='OLD', ERR=9992)
      REWIND (IUNIT)
      NTBL = 0
      NMAX = 5000
      MR   = 0
      IF ( NTBL .EQ. 0 ) THEN
        LOC = 1
        DO 10 M = 1,NMAX
   10   CDNOZ(M) = 0.
      ENDIF

   20 READ (IU12, 5000, END=400, ERR=6666 ) IP, ITABNO, TITLE

   30 IF(ITABNO .EQ. 0) THEN
        NREM = NMAX-LOC
        IF ( II .GT. 0 ) THEN
          WRITE(IU6,5010) NTBL
          WRITE(IU6,5020) (N, ICDDAT(N), LOCCD(N), N = 1,NTBL)
          WRITE(IU6,5030) NMAX, NREM
        ENDIF
        IF( MR .GT. 0 ) WRITE(IU6,5040) (IREP(IQ), IQ = 1,MR)
        RETURN
      ELSE
        NTBL = NTBL+1
        ICDDAT(NTBL) = ITABNO
        LOCCD(NTBL)  = LOC
        IF ( NTBL .GT. 1 ) THEN
          DO 40 I = 2,NTBL
            IF ( ITABNO .EQ. ICDDAT(I-1) ) GO TO 50
   40     CONTINUE
          GO TO 150
   50     MLOC = LOCCD(I-1)
          ILOC = MLOC
          LOCCD(I-1) = LOC
          NTBL = NTBL - 1
          MR   = MR + 1
          IREP(MR) = ITABNO
          LIBLOC = 100000
          DO 60 IRK = 1,NTBL
            LIBRA = LOCCD(IRK)
            IF ( (LIBRA .GE. MLOC) .AND. (LIBRA .LT. LIBLOC) )
     *                                  LIBLOC = LIBRA
   60     CONTINUE
          LEO = LIBLOC - MLOC
          IF ( LEO .NE. 0 ) THEN
            IZAR = LOC - 1
            DO 70 I = LIBLOC,IZAR
              CDNOZ(MLOC) = CDNOZ(I)
              MLOC = MLOC + 1
   70       CONTINUE
            DO 80 I = 1,NTBL
              LLOC = LOCCD(I)
              IF ( LLOC .GT. ILOC ) LOCCD(I) = LLOC - LEO
   80       CONTINUE
          ENDIF
          DO 90 I = MLOC,LOC
   90     CDNOZ(I) = 0.
          LOC = MLOC
        ENDIF
      ENDIF

  150 IF ( II .GT. 0 ) THEN
        WRITE ( IU6, 5060 ) ITABNO, TITLE
        IP = 1
      ENDIF

      ICC = 0
      LZ  = LOC
      DO 180 ICL = 1,4
  180 IDD(ICL) = 4H    
  190 IDL = ID
      READ (IU12, 5070, END=200, ERR=6666 ) ID, N, (A(I), I = 1,N)
  200 IF ( ID .EQ. 4HEOT ) GO TO 20
      ICC = ICC + 1
      IF ( ICC .LE. 4 )      IDD(ICC) = ID
      IF ( ID  .EQ. IDL )    GO TO 280
      IF ( ID  .NE. IDD(4) ) GO TO 210
      IF ( IDL .EQ. IDD(2) ) GO TO 280
      LOC = LE
      L = LX
      GO TO 220
  210 CDNOZ(LOC) = N
      L  = LOC
      IF ( ID .EQ. IDD(3) ) LX = L
      IF ( ID .NE. IDD(2) ) GO TO 260
      LY = L
      LZ = LZ + 1
      GO TO 260

C ... WRITE THE TABULAR DATA.
  220 IF ( IP .NE. 0 ) THEN
        LY = LY+1
        WRITE(IU6,5080) IDD(1), CDNOZ(LZ), IDD(2), CDNOZ(LY)
        JF = 0
        M  = N
        LF = LX
  240   NP = M
        IF ( M .GT. 8 ) NP = 8
        M  = M - NP
        LE = LF + NP
        LF = LF + 1
        WRITE(IU6,5090) IDD(3), (CDNOZ(I), I = LF,LE)
        LF = LE
        JE = JF + NP
        JF = JF + 1
        WRITE(IU6,5090) IDD(4), (A(I), I = JF,JE)
        JF = JE
        IF( M .GT. 0 ) GO TO 240
      ENDIF

  260 DO 270 I = 1,N
        LOC = LOC + 1
        CDNOZ(LOC) = A(I)
  270 CONTINUE
      LE = LOC
      IF ( ID .EQ. IDD(4) ) CDNOZ(LOC+2) = 1.
      LOC = L + 2*N + 6
      IF ( LOC .GT. NMAX ) GO TO 300
      GO TO 190
  280 CDNOZ(LOC) = CDNOZ(LX)
      L = LOC
      DO 290 I = 1,N
        LOC = LOC + 1
        CDNOZ(LOC) = CDNOZ(LX+I)
  290 CONTINUE
      GO TO 220
  300 WRITE(IU6,5100) ITABNO
      ITABNO = 0
      GO TO 30

  400 CONTINUE
      ITABNO = 0
      GO TO 30

 6666 CONTINUE
      WRITE(IU6,6669) IU12
      STOP

 5000 FORMAT (I1,I4,A)
 5010 FORMAT (//,33X,'TABLE DATA INPUT SUMMARY, ',I3,' TABLES',//,
     1    28X,'TABLE NUMBER  REFERENCE NUMBER   ARRAY LOCATION')
 5020 FORMAT (33X,I2,12X,I5,14X,I5)
 5030 FORMAT (/,36X,'DATA STORAGE ALLOCATION ',I7,/,
     1          36X,'DATA STORAGE NOT USED   ',I7,/)
 5040 FORMAT(10X,'THE FOLLOWING TABLES HAVE BEEN REPLACED',10(I5,','))
 5060 FORMAT (//,3X,I4,A,/)
 5070 FORMAT(A4,I3,3X,(T11,7F10.0))
 5080 FORMAT(1X,A4,' = ',E13.5,1X,A4,' = ',E13.5)
 5090 FORMAT(20X,A4,1X,8E13.5)
 5100 FORMAT (' ********* TABLE OVER FLOW, TABLE ',I5,' NOT LOADED')
 6669 FORMAT(/,' ERROR READING ENGINE TABULAR INPUT DATA FROM UNIT',
     *       I3,'.',/,' PROGRAM ABORTED IN SUBROUTINE TABRD.')

 9992 CONTINUE
      WRITE(IU6,9999) 'ERROR OPENING THE INPUT FILE ', CDFILE,
     *       ' AS UNIT ', IUNIT, '.',
     *              'PROGRAM ABORTED IN SUBROUTINE CDRD.'
 9999 FORMAT(//,1X,2A,/,A,I2,A,/,1X,A,/)
      STOP
      END

我不知道为什么EQ没有按照它应该的方式起作用。 - Khan
什么是Hollerith常量? - Khan
4HEOT 是一种 Hollerith 常量。现在我们称之为 "EOT"。为了提供更多帮助,您应该提供更多上下文(请参见 [mcve] - 是的,这需要付出努力)。此外,许多用户可能不愿意为40年前就已经过时的代码提供帮助。 - francescalus
谢谢,@francescalus。我已经在我的帖子中添加了最小的代码部分。我不明白为什么第一个字母中的数字是4,当只有“EOT”-3个字母时,它代表什么意思? - Khan
EOT 后面有一个空格。 - francescalus
3个回答

5
你之所以出现错误,是因为你的代码使用了非标准FORTRAN 77代码,而你的编译器(gfortran)不支持。

正如gfortran检测到的那样,你正在使用霍勒斯常量4HEOT

霍勒斯是字符类型的前身。最后一个允许使用霍勒斯的Fortran标准是FORTRAN 66(ANSI X3.9-1966)。尽管它不是FORTRAN 77标准的一部分,但它包含了附录C,其中提供了向想要作为扩展提供它的处理器的建议。你对Hollerith的使用甚至没有遵循这些建议,特别是:

C3. Hollerith常量的限制

Hollerith常量只能出现在DATA语句和CALL语句的参数列表中。

那么发生了什么?

你的代码的相关语句如下:

      IMPLICIT INTEGER*4 (I-N)
      READ (IU12, 5070, END=200, ERR=6666 ) ID, N, (A(I), I = 1,N)
  200 IF ( ID .EQ. 4HEOT ) GO TO 20
 5070 FORMAT(A4,I3,3X,(T11,7F10.0))
  1. 变量ID使用非标准符号integer*4隐式声明为4字节整数(有关详细信息,请参见Fortran: integer*4 vs integer(4) vs integer(kind=4))。

  2. READ语句使用A4编辑描述符将值分配给ID。 这是FORTRAN 77标准附录C允许读取Hollerith变量的方法:

    C1. Hollerith数据类型

    Hollerith是一种数据类型; 但是,符号名称不能是Hollerith类型。 除常量外,Hollerith数据在类型为整数,实数或逻辑的名称下进行标识。 它们不能被标识为字符类型。 [...]

    Hollerith数据是一串字符。 [...]空格字符在Hollerith数据中很重要。 Hollerith数据的内部表示可能与其他数据类型不同。

    可以通过DATA语句(C4)或READ语句(C6)定义带有Hollerith值的整数,实数或逻辑实体。[...]当具有Hollerith值的整数,实数或逻辑实体被定义时,该实体及其相关联的内容成为未定义用作整数,实数或逻辑数据。

    C6. Hollerith数据的编辑

    当输入/输出列表项的类型为整数,实数或逻辑值时,可以使用Aw编辑描述符来处理Hollerith数据。 在输入时,输入列表项将使用Hollerith数据定义。 在输出时,必须使用Hollerith数据定义列表项。

    编辑与用于字符数据的Aw编辑描述符相同,除了len是可以存储在单个数字存储单元中的字符的最大数量。

    因此,整数变量ID包含描述4个字符的Hollerith数据。 每个字节一个字符,ID定义为4字节变量,这似乎没问题。

  3. IF语句将Hollerith变量ID与Hollerith常量4HEOT进行比较(可能是为了检查是否处于表格结束位置,鉴于上下文)。 这甚至不被建议的标准扩展支持,但是,我们有两个由4个字符组成的字符串,所以决定它们是否相等应该不会很困难。 只是可惜,gfortran从未被告知如何执行此操作(讽刺模式关闭)。

您该如何修复它?

我能想到许多可能性(除了找到编写此代码的人向他恳求修复,但他很可能已经退休)。对于未来最好的解决方案是Option 1:
Option 1
通过引入新的字符变量重写代码,使所有与字符编辑描述符(A[w])的I/O都对应于列出的字符变量。用字符常量"EOT"替换有问题的Hollerith常量。
Option 2
一些Fortran编译器可以使用字符编辑描述符读写整数,而不是实际的Hollerith变量。使用其中一个编译器(例如gfortran):它认为ID仍然是整数而不是Hollerith,因此假定ID保持为整数,并且读取操作将4个字符的变量读入其中。
在这种情况下,可以用其编码的整数替换Hollerith常量。例如,您可以通过定义...
      DATA ID_EOT/4HEOT /

现在,ID_EOT已经有了一个整数值(可能是ICHAR("E")+256*(ICHAR("O")+256*(ICHAR("T")+256*ICHAR(" ")))),您可以将有问题的IF语句替换为以下内容:

  200 IF ( ID .EQ. ID_EOT ) GO TO 20

该选项不符合标准,因此不具备可移植性,并且可能会导致类似于您正在经历的问题的未来问题(对您或其他人)。然而,它至少符合如何实施扩展的书面建议,比您现在拥有的更好。
以下编译器(已检查版本)似乎支持带有 Hollerith 的 DATA 语句:Intel(17.0.4)、gfortran(7.3.0)、CRAY(8.5.8)、PGI(18.4)、NAG(6.2)和 Sun(8.8)。除了 NAG 编译器外,它们所有的编译器似乎都允许使用字符编辑描述符读写整数。请注意,测试非常有限,仅针对 4HEOT 常量进行。
选项3: 使用可以处理您的代码的编译器-我认为 Intel Fortran 可以编译和运行它。
该选项不符合标准,因此不具备可移植性,并且可能会导致类似于您正在经历的问题的未来问题(对您或其他人)。它甚至不符合 FORTRAN 77 标准附录 C 中的扩展建议。这是需要付出最少工作的选项,代价是不改善任何内容并保留未来的问题 - 当曾经编写 FORTRAN 66 的人越来越少时。

霍勒里斯的概述很好,加一。 - Ross

0

有几种解决方法。当然,可以将所有的 Hollerith 常量更改为 CHARACTER 变量,但这可能会有些问题,因为与 CHARACTER 参数不同,Hollerith 隐藏了额外的长度信息,导致在子程序中作为参数传递时会出现一些问题。在支持此语法的编译器中,Hollerith 常量在表达式中的行为通常是不一致、文档不完善并且几乎没有支持。在 DATA 语句中可能得到更好的支持,但也不能依赖这一点。

gfortran 表示他们支持将 Hollerith 常量作为函数参数使用,但最早支持 BOZ 字面量的经典转换函数(例如 INT)不起作用:请参考下面的示例。如果你喜欢遥远的狂笑声,可以向 bugzilla 发送一个错误报告关于这个问题。我在使用 TRANSFER 和赋值操作时取得了更好的结果:

program holler
   use ISO_FORTRAN_ENV
   integer(INT32) ID
! holler.txt should exist in the current directory
! and contain at least 4 characters
   open(10,file='holler.txt',status='old')
   read(10,'(A4)') ID
!   write(*,'(*(g0))') 'ID == 4HEOT  = ',ID == 4HEOT ! Fails
!   write(*,'(*(g0))') 'ID == 4HEOT  = ',ID == int(4HEOT ,KIND(ID)) ! Fails
   write(*,'(*(g0))') 'ID == 4HEOT  = ',ID == transfer(4HEOT ,ID) ! Success
   BLOCK
      integer(kind(ID)) compare
      compare = 4HEOT ! Note trailing space
      write(*,'(*(g0))') 'ID == 4HEOT  = ',ID == compare ! Success
   END BLOCK
end program holler

在我看来,将 Hollerith 常量(FORTRAN 66 中的扩展,在 FORTRAN 77 中得到了应用)作为 TRANSFER 内置函数(Fortran 95 标准引入)的参数使用,就像试图将一只驴子留在 The Shard 的停车场里几个小时一样:它可能会有效,但这将涉及混合属于不同时代的项,没有任何规则可言,而且很可能不受支持或未经广泛验证。在 DATA 语句中使用 Hollerith 更有意义,因为它是 66 标准的一部分,所以应该曾经得到过支持和验证。 - jme52
在BLOCK中使用Hollerith(Fortran 2008引入)甚至更令人震惊,但我理解这是为了在示例中更清晰明了。 - jme52
@ripero 如果你认为Hollerith在任何情况下都得到了显著的支持或验证,那么...但这并不是我的经验。在我看来,它已经足够老旧,不能被信任。事实上,在gfortran手册中提供了TRANSFER的示例。 - user5713492
我在答案中更新了一些有关编译器的信息。如果您能提供一些洞察何时似乎支持Holleriths失败的信息,那将非常好。我自己不会相信 Holleriths - 而且请不要谈论BOZ字面量... - jme52
@ripero,我现在可能没有时间,我真的很忙。但是忙碌是好事。如果你只是阅读给定编译器的可用文档,你会发现它在这个领域非常模糊,并且与编译器实际执行的操作不太一致。供应商们已经有很多事情要做,比如支持参数化派生类型和常量表达式中的转换内部函数,我更希望他们将精力投入到支持符合标准的代码上。 - user5713492

0

正如编译器错误所示,您正在比较一个 整数 和一个 HOLLERITH。我刚刚发现,它是在 FORTRAN77 之前使用的一种包含字符的 字符串!您不能将一个 整数 与一个 字符串 进行比较。

如果您想使用 read字符串 转换为 整数,请参见 here

如果您想要比较字符串,请改用 write


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接