2015-02-21 2 views
2

У меня есть следующая подпрограмма COBOL, которая принимает строку, длину и аргумент «boolean». Подпрограмма отображает строку без завершающих пробелов. Длина указана в том случае, если полная длина входной строки отличается от хранилища, используемого в подпрограмме для аргумента строки. «Boolean» указывает, должна ли линия быть показана после отображения строки.CALL arguments (опущен? Literal?)

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' 

Таким образом, он не принимает литерал для второго аргумента, хотя он интерпретирует правду 3-го аргумента.

случайных вопросов, которые я придумал во время написания этой подпрограммы является:

  1. ли литералы даже допускаются в качестве аргументов в CALL? Я прочитал документацию, но у меня проблемы с этим. Я не нашел примеров литералов, но никаких явных заявлений об обратном. Я подозреваю, что прохождение 'F' буквально неверно, но «бывает с работой».

  2. Есть ли лучший способ обработки строк различной длины в такой функции?

  3. Есть ли более канонический способ выдачи строки на выход, кроме DISPLAY ' ', и без отображения пробела?

  4. В идеале я хотел бы иметь возможность опустить аргумент, и пусть по умолчанию взять в CALL, но я получил какое-то эталонным ошибку памяти, когда я пытался сделать что-то вроде: CALL 'Display-String' USING OMITTED, 0, 'F'. Я прочитал некоторую документацию по адресу OMITTED, но не понимаю, как заставить ее работать.

Я использую cobc (OpenCOBOL) 1.1.0 на Linux версии 3.9.10-100.fc17.i686.PAE (Fedora 17).

+0

@BillWoodger очень извините. Я добавил его к моему вопросу. – lurker

+1

Если вы хотите, чтобы строка LS-Input-String была опущена, вам необходимо использовать код ADDRESS OF, аналогичный тому, что у вас есть для длины. Вам мешает ошибка компилятора. 2.0 лучше, я думаю, но не полностью исправлено. Это будет скоро. Вероятно. Посмотрите здесь, например: https://sourceforge.net/p/open-cobol/discussion/help/thread/210c3831/#572c. Пока ошибка не будет исправлена, вы получите некоторые результаты, которые не относятся к тому, что вы на самом деле делаете. –

+0

@BillWoodger благодарит кучу. Я мог бы отказаться от того, чтобы первый аргумент был пропущен. Это был эксперимент и не очень полезный. Первоначально я неправильно понял, как работает OMITTED, и думал, что он будет использовать значения по умолчанию, указанные в хранилище ссылок подпрограммы. Думаю, я заработаю и получаю 2.0. Я его построил, но в данный момент это огорчает нас о 'libcob.so.4'. Я это выясню. Я знаю, что это не сайт для проверки кода, но если я делаю что-то еще смешное, я ценю отзывы. – lurker

ответ

3

CALL утверждение имеет три варианта ИСПОЛЬЗОВАНИИ: BY REFERENCE; BY CONTENT; BY VALUE; OMITTED. Хорошо, четыре, затем подсчитав последний.

Они по умолчанию, если указано BY BYFERENCE. Последний указанный параметр относится к следующим элементам в 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 по процедуре согласования РАЗДЕЛЕНИЯ С ПОМОЩЬЮ ... (или ENTRY .. . ИСПОЛЬЗОВАНИЕ ...).

Однако это не конец вашей истории для буквального, потому что есть ошибка. Я предлагаю вам рассмотреть возможность перехода на GnuCOBOL (новое имя для OpenCOBOL) 2.0. Вы можете найти обсуждение этой проблемы в области обсуждения GnuCOBOL в SourceForge.Net. Это будет исправлено. Если вы увлечены, вы можете исправить это самостоятельно и получить это в источнике ...

Должно покрывать вопросы один и два.

В-третьих, интересный вопрос. Не метод canonical-for-COBOL, так как сам COBOL не имеет линейных каналов и подобных. Хороший вопрос для области GnuCOBOL. Вы можете отобразить шестнадцатеричный литерал соответствующего значения, но это не будет переносимым. Различные COBOL-компиляторы имеют языковые расширения на DISPLAY. Может ли кто-нибудь использовать, когда нет данных для DISPLAY, я не знаю. Существует Z-литераль, который буквально «завершается» двоичным нулем, но я не думаю, что буквальное содержание может быть «отсутствующим». У других будут мнения и идеи.

В-четвертых, вы должны использовать OMITTED на своем CALL. Вы не можете использовать OMITTED для элемента BY VALUE, но его можно использовать для элементов BY REFERENCE и BY CONTENT.

Способность использовать его также означает возможность иметь дело с ним в вашей программе CALLed. Если вы вызовете свою программу с помощью строки OMITTED, ваша программа завершится неудачей, так как предполагается, что для доступа к ней есть поле/значение, и их не будет.


ОК, некоторые обзоры.

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

Запятые в коде ничего не делают. Если вы хотите, чтобы выделить обособленность:

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 

Есть два способа получить при длине идентификатора: LENGTH OF; FUNCTION 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 

Я бы поставил эти «ноги» в пунктах и ​​ВЫПОЛНЯТЬ их, но эффект тот же.

GOBACK. 

    GOBACK 
    . 

В PROCEDURE DIVISION я только код полных остановки/периоды в конце этикетки или РАЗДЕЛА или на линии своих собственных. При перемещении кода или вставке нового кода вам никогда не придется беспокоиться о перемещении полной остановки/периода.

Я бы тоже сделал что-то немного другое, что имеет большее влияние.

Как вы его закодировали, если длина строки OMITTED, тогда программа CALLing должна указать и идентификатор 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 

делает это больше как вы хотите. Новая строка, но даже не место на старой строке.

+0

Спасибо. Каждый раз, когда я пытаюсь «BY VALUE» (отмечая его как в «CALL», так и в подпрограмме 'PROCEDURE DIVISION', по мере необходимости), я получаю« Попытка ссылаться на нераспределенную память ». Я попробовал «CALL» Display-String «ИСПОЛЬЗОВАТЬ СОДЕРЖАНИЕ« xyz », ПО СОДЕРЖАНИЮ 8, СОДЕРЖАНИЕМ« T'', и он отображает пробел, тогда как я ожидал бы «xyz». – lurker

+0

Я расскажу вам о модернизации GnuCobol. Версия, которую я имею, была последней схваченной с 'yum install cobol', поэтому мне нужно будет установить из источника, вероятно. Как мне получить 2.0? SourceForge.net говорит, что на пути к предварительному выпуску * ... – lurker

+0

@lurker Я получил здесь: https://sourceforge.net/projects/open-cobol/files/gnu-cobol/2.0/ Если вы есть проблемы со всем, попросите прочь в области обсуждения. –

2

В Cobol, то вызывающая программа составлена ​​полностью отдельно от вызываемого модуля, нет заголовочных файлов, как в C. Таким образом, при составлении программы вызова, компилятор не знать формат параметров из вызывается программа. Компилятор Cobol будет форматировать параметры на основе набора правил, которые он имеет. Формат, который решает компилятор Cobol, может отличаться от того, что ожидает ожидающая программа.

Так что, когда в сомнении, используйте переменную на вызов

В вашем случае, я подозреваю

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

будет работать

+0

Брюс, спасибо. На самом деле я попытался сыграть с буквальной строкой для первого аргумента. Хотя это и не очень полезный случай, он не давал мне ожидаемых результатов (либо скомпилировать, но отобразить кусочки произвольных данных из памяти). Использование строки для числового аргумента иногда приводит к результатам, но, опять же, не ожидаемым результатам. – lurker

+0

Я играл с этим дальше, и, да, если я передаю номер в качестве «010», он работает! Благодарю. – lurker

+0

Есть ли способ написать подпрограмму, чтобы можно было передавать буквальное число точно так же, как число? – lurker