Fortran - 转换为C时可以解决问题

时间:2015-02-19 22:23:09

标签: fortran

我将这个Fortran代码翻译成C代码。使用go语句的好方法是什么。我已经设法解决了一些转到的问题,但是你看到的那些是100多个线上跳跃。我不知道如何解决这个问题,是否有一个简单的策略来做到这一点而不去c?

270    IF (R .EQ. 0) THEN
           GO TO 290
       ELSE 
           GO TO 300
       END IF
290    M=M+1; GO TO 400       
300    DO 305 I = 1,L
           IF (ICHAR(D(I)) - ICHAR("-")) 305,320,305
305    CONTINUE
       GO TO 390

3 个答案:

答案 0 :(得分:1)

完成了相当数量的重组Fortran代码以最大限度地减少对GOTO的使用,我可以告诉你,你经常 - 通常,甚至 - 将GOTO映射到结构化编程结构的部分上例如条件语句,循环和开关(Fortran中的SELECT CASE)。在某些情况下,您可以安全地移动代码块以促进这一点。

在历史悠久的代码中发现大多数标签只有一个传入分支并且这些情况通常很容易处理,这种情况并不少见。但是,在这样的代码中,你必须要小心有多个传入分支的行。

有时退一步并将整个子程序作为一个单元进行分析会有所帮助。您可能会迷失在所有单个的getos和标签中,但更高级别的分析可能会揭示难以辨别的转换选项。此外,您可能需要分多步执行整体转换。无论如何,从更容易的位开始。有时清除它们会使其他转换更容易看到或执行。

我通常在Fortran代码上执行这样的转换,然后转换为无转码C很简单。但是,如果您对C更熟,那么您可以考虑将Fortran代码直接转换为goto-载满C,然后转换C代码。但是,没有任何方法可以解决问题。

至于您的示例代码,没有足够的信息来判断如何对其进行转换(即使在较长的pastebin代码段中也是如此)。可能存在从子程序中的任何其他地方传入任何标记语句的分支,如果不了解这些变换,您无法知道哪些变换是安全的。

答案 1 :(得分:1)

我首先要编译代码并使用一些goto语句在C中正确运行。先调试一下。这是重要的部分,可能会让你忙碌一段时间。消除所有GOTO并不那么重要。

然后逐步改进代码,使其在每次重构步骤后正确编译和运行,无论是删除goto还是执行其他操作。

请注意,在执行此操作时可能会引入错误。您可以通过使代码首先工作并在执行重构步骤之前将其检入源代码控制来减少问题。

在此示例中,一个此类重构步骤将通过复制/移动内联用于跳转到GO TO 290的代码来替换M=M+1; GO TO 400语句。完成后,ELSE很容易简化。

同样,您可以替换

IF (ICHAR(D(I)) - ICHAR("-")) 305,320,305

if (ICHAR(D(I)) == ICHAR("-")) goto 320

然后更多代码可以简化。 (好吧,在代码用C语言编译之前,你必须做这个改变。)

如果原始代码合理,大多数GOTO将变成合理的结构化代码。如果没有,你手上有意大利面条代码和更大的问题。在这种情况下,尝试使其工作,然后逐步重写。

答案 2 :(得分:0)

我建议给TOOLPACK一个旋转来重构代码。

可以在http://www.ibiblio.org/pub/Linux/devel/lang/fortran/!INDEX.short.html找到一个版本,它只需要对现代unix系统进行一些调整(在C端,它可以告诉你哪种语言更稳定......)。

我将你的例子改为litte(使其编译)到

      SUBROUTINE FOO(D,L)
      CHARACTER*1 D(L)
      INTEGER L
      R = 42.3
      M = 52
 270  IF (R .EQ. 0) THEN
         GO TO 290
      ELSE 
         GO TO 300
      END IF
 290  M=M+1
      GO TO 400       
 300  DO 305 I = 1,L
         IF (ICHAR(D(I)) - ICHAR('-')) 305,320,305
 305  CONTINUE
      GO TO 390

 400  PRINT *,L,M
 390  PRINT *,R
 320  PRINT *,'FOUND'
      END

并通过TOOLPACK的stf脚本运行它。这就是它的结果:

      SUBROUTINE FOO(D,L)
      CHARACTER*1 D(L)
      INTEGER L

      R = 42.3
      M = 52
      IF (R.EQ.0) THEN
          M = M + 1

          PRINT *,L,M

      ELSE
          DO 10 I = 1,L
              IF (ICHAR(D(I))-ICHAR('-').EQ.0) GOTO 20
   10     CONTINUE
      ENDIF

      PRINT *,R
   20 PRINT *,'FOUND'
      END

它也可以为你做变量声明等。

TOOLPACK严格遵守Fortran 77标准非常严格,因此字符串ENDDOIMPLICIT NONE的双引号将无效。恕我直言,它将意大利面条代码转换为更有条理的东西,而不是弥补它。此外,这不是一个你想要在一个源代码上重复运行的程序 - 你可以转换一次源代码(可能只有一些实用程序,一个接着一个),然后继续处理它。