CALL 参数(省略?文字?)

CALL arguments (omitted? literal?)

我有以下接受字符串、长度和 "boolean" 参数的 COBOL 子例程。该子例程显示不带尾随空格的字符串。如果输入字符串的全长与子例程中用于字符串参数的存储不同,则提供长度。 "boolean" 表示显示字符串后是否要进行。

   IDENTIFICATION DIVISION.
   PROGRAM-ID. Display-String.

   DATA DIVISION.
   LOCAL-STORAGE SECTION.
   01  i                   PIC 9(3).
   01  Len                 PIC 9(3).

   LINKAGE SECTION.
   01  LS-Input-String     PIC X(255).
   01  LS-Input-Length     PIC 9(3).
   01  LS-Advancing        PIC X.
       88  LS-Advance      VALUE 'T' WHEN SET TO FALSE 'F'.

   PROCEDURE DIVISION USING LS-Input-String, LS-Input-Length,
           LS-Advancing.
       MOVE LENGTH OF LS-Input-String TO Len

       IF ADDRESS OF LS-Input-Length NOT = NULL THEN
           MOVE FUNCTION MIN(LS-Input-Length Len) TO Len
       END-IF

       PERFORM VARYING i FROM Len BY -1
           UNTIL i LESS THAN 1 OR LS-Input-String(i:1) NOT = ' '
       END-PERFORM

       IF i > ZERO
           IF LS-Advance THEN
               DISPLAY LS-Input-String(1:i)
           ELSE
               DISPLAY LS-Input-String(1:i) WITH NO ADVANCING
           END-IF
       ELSE
           IF LS-Advance THEN
               DISPLAY ' '
           END-IF
       END-IF
       GOBACK.

当我将其命名为:

时效果很好
MOVE LENGTH OF WS-My-String TO WS-Length
CALL 'Display-String' USING WS-My-String, WS-Length, 'F'

但是我得到了错误的结果(子例程没有得到 10 但空白或其他东西):

CALL 'Display-String' USING WS-My-String, 10, 'F'

所以它不接受第二个参数的文字,即使它可以很好地解释第三个参数文字。

我在编写这个子例程时想到的随机问题是:

  1. 是否允许在 CALL 中将文字作为参数?我已通读文档,但无法弄清楚。我没有找到文字的例子,但没有明确的相反陈述。我怀疑从字面上传递 'F' 是错误的,但是 "happens to work".

  2. 有没有更好的方法来处理像这样的函数中的各种长度的字符串?

  3. 除了 DISPLAY ' ' 之外,是否有更规范的方式向输出发出换行符而不显示 space?

  4. 理想情况下,我希望能够省略一个参数并让默认值接管 CALL,但是当我尝试这样做时出现了某种内存引用错误类似于:CALL 'Display-String' USING OMITTED, 0, 'F'。我阅读了一些关于 OMITTED 的文档,但不明白如何让它发挥作用。

我在 Linux 版本 3.9.10-100.fc17 上使用 cobc (OpenCOBOL) 1.1.0。i686.PAE (Fedora 17)。

在 Cobol 中,调用程序与被调用模块完全分开编译,没有像 C 中那样的头文件。所以在编译调用程序时,编译器不会知道被调用程序的参数 的格式。 Cobol 编译器将根据它拥有的一组规则来格式化参数。 Cobol 编译器决定的格式可能与调用程序所期望的格式不同。

因此,如有疑问,请在调用时使用变量

你的情况,我怀疑

CALL 'Display-String' USING WS-My-String, '010', 'F'

会起作用

一个CALL语句有三个USING选项:BY REFERENCEBY CONTENT; BY VALUE; OMITTED。好的,四个,然后数最后一个。

它们在指定时默认为 BY REFERENCE。指定的最新选项指的是 CALL ... USING ... 中的以下项目,直到出现另一个选项。

将这些应用到您编写的代码中,您所有使用的项目都是 BY REFERENCE。

是的,CALL 语句中允许使用文字。文字只能按内容或按值使用。所以你的 CALL 应该是:

CALL 'Display-String'          USING BY REFERENCE 
                                         WS-My-String
                                     BY CONTENT 
                                         10 
                                     BY CONTENT 
                                         'F'

或者:

CALL 'Display-String'          USING BY REFERENCE 
                                         WS-My-String
                                     BY VALUE 
                                         10 
                                     BY VALUE 
                                         'F'

如果您使用 BY VALUE,您还必须在匹配的 PROCEDURE DIVISION USING ...(或 ENTRY ... USING ...)项目上指定 BY VALUE。

但是,这并不是您的文字故事的结局,因为存在错误。我建议您考虑升级到 GnuCOBOL(OpenCOBOL 的新名称)2.0。您可以在 SourceForge.Net 的 GnuCOBOL 讨论区找到关于此问题的讨论。它将被修复。如果您愿意,可以自己修复它并将其包含在源代码中...

应该涵盖问题一和问题二。

第三,有趣的问题。不是 COBOL 的规范方式,因为 COBOL 本身没有换行符等。 GnuCOBOL 领域的一个好问题。您可以显示适当值的十六进制文字,但不可传输。各种 COBOL 编译器在 DISPLAY 上都有语言扩展。 any在没有数据DISPLAY的时候能不能用,我不知道。有一个Z-literal,它是一个二进制零的文字"terminated",但我不认为literal-content可以是"missing"。其他人会有意见和想法。

第四,您应该能够在 CALL 中使用 OMITTED。您不能将 OMITTED 用于 BY VALUE 项目,但它可以用于 BY REFERENCE 和 BY CONTENT 项目。

能够使用它也意味着能够在你调用的程序中处理它。如果您使用字符串 OMITTED 调用您的程序,您的程序将失败,因为它假设有一个 field/value 可以访问,但不会有。


好的,一些评论。

PROCEDURE DIVISION USING LS-Input-String, LS-Input-Length,
           LS-Advancing.

代码中的逗号没有任何作用。如果要突出独立性:

PROCEDURE DIVISION            USING LS-Input-String
                                    LS-Input-Length
                                    LS-Advancing
                                    .

如果有人不小心把 ,, 留在身边,其他人可能会认为 "it must mean something"。

   MOVE LENGTH OF LS-Input-String TO Len

   IF ADDRESS OF LS-Input-Length NOT = NULL THEN
       MOVE FUNCTION MIN(LS-Input-Length Len) TO Len
   END-IF

有两种获取标识符长度的方法:LENGTH OFFUNCTION LENGTH。后者允许这样做:

   IF ADDRESS OF LS-Input-Length NOT = NULL
       MOVE FUNCTION MIN ( 
                           LS-Input-Length 
                           FUNCTION  LENGTH ( 
                                              LS-Input-String 
                                            ) 
                         ) 
                                    TO Len
   END-IF

但是:

   MOVE LENGTH OF LS-Input-String TO Len

   IF ADDRESS OF LS-Input-Length NOT = NULL THEN
       IF LS-Input-Length LESS THAN Len
           MOVE LS-Input-Length TO Len
       END-IF
   END-IF

对我来说,如果你碰巧做很多这样的事情,会更清晰,表现会更好。

我不会把东西塞在一起。在其他编译器上,您至少会从中得到一些诊断信息:

LS-Input-String(i:1)

我会成功的,类似的:

LS-Input-String ( i : 1 )

括号本身至少应该有空格。

要检查完全空白,我...检查完全空白,但更早。在这种情况下保存循环,简化循环的终止条件:

   IF LS-Input-String EQUAL TO SPACE
       IF LS-Advance 
           DISPLAY ' '
       END-IF
   ELSE
       PERFORM VARYING i FROM Len BY -1
           UNTIL LS-Input-String ( i : 1 ) 
                  NOT EQUAL TO SPACE
       END-PERFORM
       IF LS-Advance THEN
           DISPLAY LS-Input-String ( 1 : i )
       ELSE
           DISPLAY LS-Input-String ( 1 : i ) 
             WITH NO ADVANCING
       END-IF
   END-IF

我会把那些 "legs" 放到段落中并执行它们,但效果是一样的。

   GOBACK.

   GOBACK
   .

在 PROCEDURE DIVISION 中,我只在标签或 SECTION 的末尾或它们自己的一行上编码 full-stops/periods。移动代码或插入新代码时,您永远不必担心移动 full-stop/period.

我也会做一些略有不同的事情,但影响会更大。

按照您的编码方式,如果字符串的长度被省略,则调用程序必须提供 255 字节的标识符。如果没有,那么您的 CALLed 程序将拾取它不应该拾取的东西。

如果那是你想要的,那好吧。如果不是,我会考虑不使长度可选,并使用实际字段的长度, OCCURS DEPENDING ON.

01  LS-Input-String.
    05  FILLER OCCURS 0 TO 255 TIMES
        DEPENDING ON LS-Input-Length.
        10  FILLER                         PIC X.
01  LS-Input-Length                        PIC 9(3).

...

    MOVE LS-Input-Length            TO Len

现在,当您输入零长度时,

           DISPLAY LS-Input-String

做的更像你想要的。一个新行,但在旧行上什至没有 space。