Menu ▾ ▴

#1270 Tracking: nine small cases where cobc -std=cobol2014 refuses COBOL 2014 source

GC 3.x
open
nobody
None
5 - default
2026-10-30
2026-10-30
No

This ticket groups nine small, independent cases in which cobc refuses source that ISO/IEC 1989:2014 allows. Each case has its own program, expected result and suspected fix site, and any of them can be split into its own ticket. In each, the user gets a compile error for a legal program.

  1. A level-01 or level-77 item with a VALUE literal and no PICTURE is refused (patch attached).
  2. EVALUATE with a condition as subject and a condition as object is refused.
  3. Reference modification of EXCEPTION-STATUS and similar no-argument functions gives "syntax error, unexpected :".
  4. Reference modification of standard alphanumeric functions such as CHAR is refused.
  5. REWRITE record-name RECORD FROM ... gives "syntax error, unexpected RECORD" (patch attached).
  6. Under -std=cobol2014, ROUNDED MODE IS NEAREST-EVEN gives a syntax error because of a word-list typo (patch attached). This is a word-list error, not a conformance question.
  7. BYTE-LENGTH (x, PHYSICAL) and LENGTH (x, PHYSICAL) with a comma are refused (patch attached).
  8. SET condition-name TO TRUE is refused when the 88 VALUE is SPACE and the item is numeric-edited.
  9. NOT before a condition that has its own NOT is refused.

In every case the 3.3-dev output is byte-identical to the 3.2.0 output unless stated. Rule numbers are those of ISO/IEC 1989:2023.

1. PICTURE clause required for a level-01/77 item whose PICTURE is implied by a VALUE literal

To reproduce

imppic.cob:

IDENTIFICATION DIVISION.
PROGRAM-ID. IMPPIC.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 A VALUE "ABC".
PROCEDURE DIVISION.
    DISPLAY "[" A "]" FUNCTION LENGTH(A)
    STOP RUN.
cobc -std=cobol2014 -fformat=free -x -o imppic imppic.cob

What happens

3.2.0 exits 1:

imppic.cob:5: error: PICTURE clause required for 'A'
    3 | DATA DIVISION.
    4 | WORKING-STORAGE SECTION.
    5 > 01 A VALUE "ABC".
    6 | PROCEDURE DIVISION.
    7 |     DISPLAY "[" A "]" FUNCTION LENGTH(A)

3.3-dev r5751 gives the same output, exit 1.

The same error appears on both versions with -std=cobol2002 and with the default dialect, with 77 A VALUE "ABC"., and with 01 A VALUE N"ABC". (after the "handling of national literal is unfinished" warning). The same entry at level 05 (01 G. / 05 A VALUE "ABC".) compiles and prints [ABC]3 on both.

What should happen

The program compiles and prints [ABC]3. §13.16.3 (data description entry), syntax rules:

  • 8): "For any other entry describing an elementary item, a PICTURE clause shall be specified except as indicated in Syntax rule 9."
  • 9): "The PICTURE clause may be omitted for an elementary item when an alphanumeric, boolean, or national literal that is not a zero-length literal is specified in the data-item format of the VALUE clause."
  • 1): "Level-number may be 77 or 1 through 49". No rule limits rule 9 by level.

The implied PICTURE is X(length) for an alphanumeric literal and N(length) for a national one. The same rule 9 (without "that is not a zero-length literal") is in the 2002 standard and in the committee draft of 2014.

Proposed fix

cobol2014-syntax-gaps-case1-implicit-picture.patch changes create_implicit_picture in cobc/field.c. The test if (f->level == 1 || f->level == 77 || !first_value) (line 1226 in r5751) becomes if (!first_value). A level-01 or level-77 item whose first VALUE is a nonnumeric literal now gets the implied X(length) picture that the level-05 item already gets. An item with no VALUE, or with a numeric literal, still gets "PICTURE clause required".

The patch does not touch the national case. The implied picture is always X(n), so VALUE N"ABC" without PICTURE gives error: invalid VALUE clause at every level with the patch, as it does at level 05 on r5751 today. Rule 9 wants N(length) there, which depends on cobc's unfinished national-literal handling.

With the patch, cobc -std=cobol2014 -fformat=free -x -o imppic imppic.cob gives exit 0 with no diagnostics, and ./imppic prints, exit 0:

[ABC]3

The same holds without -std. 77 A VALUE "ABC". is accepted with -std=cobol2014 and -std=cobol2002.

make check on 3.3-dev r5751 with the patch passes: 1373 behaved as expected, 9 skipped, 0 failed (unpatched: 1372, 9, 0). The patch adds the test "Implicit picture from value, level 01 and 77" to tests/testsuite.src/syn_value.at, next to "Implicit picture from value"; the new test 200 passes. It also adds ChangeLog entries.

2. EVALUATE with a condition subject and a condition object is refused

To reproduce

evca.cob:

IDENTIFICATION DIVISION.
PROGRAM-ID. EVCA.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 N PIC 9 VALUE 1.
88 IS-ONE VALUE 1.
88 IS-TWO VALUE 2.
PROCEDURE DIVISION.
EVALUATE IS-TWO
WHEN IS-TWO DISPLAY "MATCH"
WHEN OTHER DISPLAY "NO MATCH"
END-EVALUATE
STOP RUN.
cobc -std=cobol2014 -fformat=free -x -o evca evca.cob

What happens

3.2.0 exits 1:

evca.cob:9: error: invalid use of 88 level in WHEN expression
    7 | 88 IS-TWO VALUE 2.
    8 | PROCEDURE DIVISION.
    9 > EVALUATE IS-TWO
   10 | WHEN IS-TWO DISPLAY "MATCH"
   11 | WHEN OTHER DISPLAY "NO MATCH"

3.3-dev r5751 gives the same output, exit 1. It is also the same with the default dialect.

Variants (lines 9 and 10 changed), on both versions:

  • EVALUATE TRUE ALSO IS-TWO / WHEN TRUE ALSO IS-TWO: error: invalid use of 88 level in WHEN expression, exit 1.
  • EVALUATE N = 2 / WHEN IS-TWO: error: invalid use of 88 level in WHEN expression, exit 1.
  • EVALUATE N = 2 / WHEN N > 5: error: condition expression found where decimal expression was expected, exit 1.
  • EVALUATE IS-TWO / WHEN TRUE (control): compiles, prints NO MATCH.

What should happen

The program compiles and prints MATCH. IS-TWO is false (N is 1) as subject and as object, so the truth values match. The three variants are also valid and print MATCH for the same reason.

  • §14.9.13.3 syntax rule 7) b): "Condition-2 or the words TRUE or FALSE appearing as a selection object shall correspond to condition-1 or the words TRUE or FALSE in the set of selection subjects."
  • §14.9.13.3 syntax rule 10) and Table 15 (Combination of operands in the EVALUATE statement): the object "Condition" with the subject "Condition" is "Y".
  • §14.9.13.4 general rule 3) e): "Any selection subject specified by condition-1 is assigned a truth value according to the rules for evaluating conditional expressions."
  • §14.9.13.4 general rule 4) a) 3.: "If the truth value of the selection subject and selection object match, the result of the analysis is true."

Syntax rule 7) b) is in the 2002 standard. The 2014 committee draft has the same rule and the same table (Table 16 there).

Where the fix belongs

In cobc/typeck.c, evaluate_test, an object that references a level-88 item gets "invalid use of 88 level in WHEN expression" unless the subject is the word TRUE or FALSE. Any other condition object falls into the "Regular comparison" subject = object, which for two relation conditions gives the decimal_expand error. A subject that is a condition (condition-1) needs the same truth-value comparison as a TRUE/FALSE subject. In cobc/parser.y, evaluate_subject keeps a conditional subject as a plain expression, so evaluate_test cannot tell it from a value.

No patch is attached for this case. The parser would have to mark a conditional subject, and evaluate_test would need a truth-value comparison for every condition subject/object pairing. That change spans parser.y and typeck.c and also touches the path of #1265.

  • #1265: the same evaluate_test path; a condition-name subject with a relation-condition object crashes cobc.
  • #15: added the 88-level object check for an identifier subject, which Table 15 rightly forbids.

3. Reference modification of a no-argument function: "syntax error, unexpected :"

To reproduce

frefmod.cob:

IDENTIFICATION DIVISION.
PROGRAM-ID. FREFMOD.
PROCEDURE DIVISION.
DISPLAY "[" FUNCTION EXCEPTION-STATUS (1:3) "]"
STOP RUN.
cobc -std=cobol2014 -fformat=free -x -o frefmod frefmod.cob

What happens

3.2.0 exits 1:

frefmod.cob:4: error: syntax error, unexpected :
    2 | PROGRAM-ID. FREFMOD.
    3 | PROCEDURE DIVISION.
    4 > DISPLAY "[" FUNCTION EXCEPTION-STATUS (1:3) "]"
    5 | STOP RUN.
    6 | <EOF>

3.3-dev r5751 gives the same output, exit 1. It is also the same with the default dialect.

FUNCTION EXCEPTION-LOCATION (1:1) and FUNCTION EXCEPTION-STATEMENT (1:1) give the same error on both versions. FUNCTION CURRENT-DATE (1:4) and FUNCTION WHEN-COMPILED (1:4) compile and print [2026]. Written FUNCTION EXCEPTION-STATUS () (1:3) (a form the general format does not show), the parse succeeds and case 4's check refuses it: error: FUNCTION 'EXCEPTION-STATUS' cannot have reference modification.

What should happen

The program compiles and prints [ ] (no exception has been raised).

  • §15.33.2: the general format is FUNCTION EXCEPTION-STATUS, with no arguments. §15.33.1: "The type of the function is alphanumeric."
  • §8.4.3.2.3 syntax rule 6): "If a function's definition permits arguments and a left parenthesis immediately follows function-prototype-name-1 or intrinsic-function-name-1, the left parenthesis is always treated as the left parenthesis of that function's arguments." EXCEPTION-STATUS permits none, so (1:3) is a reference modifier.
  • §8.4.3.3.3 syntax rule 2): "If identifier-1 is a function-identifier, it shall reference an alphanumeric, boolean, or national function."
  • §15.33.3 rule 1): "If the last exception status indicates no exception, alphanumeric spaces are returned."

The same holds for EXCEPTION-LOCATION and EXCEPTION-STATEMENT. EXCEPTION-FILE behaves the same in cobc, but ISO/IEC 1989:2023 gave it an optional argument (§15.28.2 FUNCTION EXCEPTION-FILE [ ( argument-1 ) ]; §E.3.3 item 25). Under 2023 rules its parenthesis is an argument list. It has no argument in the 2014 edition.

Where the fix belongs

In cobc/parser.y, rule function, alternative FUNCTION_NAME func_args func_refmod (line 20226 in r5751), the first parenthesised group is parsed as func_args for every function the scanner returns as FUNCTION_NAME, whether or not the function takes arguments. The parse stops at the colon. CURRENT-DATE and WHEN-COMPILED have their own tokens and go through func_no_parm func_refmod. Deciding by the function_list argument counts (0 and 0 for these functions in cobc/reserved.c) would fix the parse. Case 4 is the second half.

No patch is attached for this case. The generic FUNCTION_NAME func_args rule cannot see the argument count, so the fix needs either new scanner tokens for the no-argument functions or a scanner decision on the parenthesis. The result is refused by case 4's check until that is fixed too.

4. "cannot have reference modification" for standard alphanumeric functions

To reproduce

fcharrm.cob:

IDENTIFICATION DIVISION.
PROGRAM-ID. FCHARRM.
PROCEDURE DIVISION.
DISPLAY "[" FUNCTION CHAR (66) (1:1) "]"
STOP RUN.
cobc -std=cobol2014 -fformat=free -x -o fcharrm fcharrm.cob

What happens

3.2.0 exits 1:

fcharrm.cob:4: error: FUNCTION 'CHAR' cannot have reference modification
    2 | PROGRAM-ID. FCHARRM.
    3 | PROCEDURE DIVISION.
    4 > DISPLAY "[" FUNCTION CHAR (66) (1:1) "]"
    5 | STOP RUN.
    6 | <EOF>

3.3-dev r5751 gives the same output, exit 1. It is also the same with the default dialect.

FUNCTION LOCALE-COMPARE ("A" "A") (1:1) gives error: FUNCTION 'LOCALE-COMPARE' cannot have reference modification on both versions. FUNCTION UPPER-CASE ("ab") (1:1) compiles and prints [A].

What should happen

The program compiles and prints [A] (ordinal position 66 in the native ASCII collating sequence).

  • §8.4.3.3.3 syntax rule 2): "If identifier-1 is a function-identifier, it shall reference an alphanumeric, boolean, or national function."
  • §8.4.3.3.3 syntax rule 5): "Unless otherwise specified, reference modification is allowed anywhere an identifier referencing a data item of class alphanumeric, boolean, or national is permitted."
  • §15.15.1 (CHAR): "The type of this function is alphanumeric." §15.51.1 (LOCALE-COMPARE): "The function type is alphanumeric."

No function definition in clause 15 excludes reference modification.

Where the fix belongs

In cobc/reserved.c, function_list, the last field of each entry is the reference-modification flag. It is 0 for CHAR, LOCALE-COMPARE, EXCEPTION-FILE, EXCEPTION-LOCATION, EXCEPTION-STATEMENT and EXCEPTION-STATUS (all alphanumeric) and 1 for UPPER-CASE and most others. cb_build_intrinsic in cobc/tree.c refuses on it. For a standard alphanumeric, boolean or national function the flag should be 1.

No patch is attached for this case, because the flag is more than a check. For a function with the flag set, cobc/codegen.c passes the offset and length as the first two arguments of the libcob routine (cob_intr_upper_case (const int offset, const int length, cob_field *srcfield)). cob_intr_char (cob_field *srcfield), cob_intr_locale_compare (const int params, ...) and cob_intr_exception_status (void) take none. Setting the flag therefore changes the libcob interface of these functions, or needs reference modification applied in generated code instead. That choice belongs to the maintainers.

5. REWRITE record-name RECORD FROM ...: "syntax error, unexpected RECORD"

To reproduce

rwrec.cob (creates its own file):

IDENTIFICATION DIVISION.
PROGRAM-ID. RWREC.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT F ASSIGN TO "rwrec.dat".
DATA DIVISION.
FILE SECTION.
FD F.
01 R PIC X(3).
WORKING-STORAGE SECTION.
01 W PIC X(3) VALUE "NEW".
PROCEDURE DIVISION.
OPEN OUTPUT F
MOVE "OLD" TO R
WRITE R
CLOSE F
OPEN I-O F
READ F
REWRITE R RECORD FROM W
CLOSE F
OPEN INPUT F
READ F
DISPLAY R
CLOSE F
STOP RUN.
cobc -std=cobol2014 -fformat=free -x -o rwrec rwrec.cob

What happens

3.2.0 exits 1:

rwrec.cob:20: error: syntax error, unexpected RECORD
   18 | OPEN I-O F
   19 | READ F
   20 > REWRITE R RECORD FROM W
   21 | CLOSE F
   22 | OPEN INPUT F

3.3-dev r5751 gives the same output, exit 1. It is also the same with the default dialect.

MOVE W TO R / REWRITE R RECORD gives the same error. REWRITE R FROM W compiles and the program prints NEW on both versions.

What should happen

The program compiles and prints NEW.

  • §14.9.35.2, general format: REWRITE { record-name-1 | FILE file-name-1 } RECORD [ FROM { identifier-1 | literal-1 } ] ..., with RECORD not underlined (checked on the printed page).
  • §5.2.3: "Optional words are reserved words or context-sensitive words. They are shown in uppercase and not underlined in general formats."
  • §14.9.35.3 syntax rule 6): "If record-name-1 is specified, identifier-1 or literal-1 shall be valid as a sending operand in a MOVE statement specifying record-name-1 as the receiving operand." (W and R are both PIC X(3).)

The 2014 committee draft prints the same format with RECORD not underlined.

Proposed fix

cobol2014-syntax-gaps-case5-rewrite-record.patch changes rewrite_body in cobc/parser.y (line 16354 in r5751). The rule file_or_record_name from_option ... had no optional RECORD. The patch inserts the existing _record nonterminal after file_or_record_name and renumbers the action's $2/$4 to $3/$5. This covers REWRITE record-name-1 RECORD and REWRITE FILE file-name-1 RECORD, with or without FROM. bison reports no new conflicts (%expect 0 holds).

With the patch, cobc -std=cobol2014 -fformat=free -x -o rwrec rwrec.cob gives exit 0 with no diagnostics, and ./rwrec prints, exit 0:

NEW

The MOVE W TO R / REWRITE R RECORD variant also compiles and prints NEW.

make check on 3.3-dev r5751 with the patch passes: 1373 behaved as expected, 9 skipped, 0 failed (unpatched: 1372, 9, 0). The patch adds the test "REWRITE with optional RECORD" to tests/testsuite.src/syn_file.at; the new test 223 passes. It also adds ChangeLog entries.

  • #411: quotes the format REWRITE FILE file-name-1 [RECORD] FROM ... but is about the FILE phrase, not this syntax error.

6. -std=cobol2014: ROUNDED MODE IS NEAREST-EVEN gives "syntax error" (cobol2014.words lists NEAREST-EVEN-INTERMEDIATE)

To reproduce

rmne.cob:

IDENTIFICATION DIVISION.
PROGRAM-ID. RMNE.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 V PIC 9V9999 VALUE 1.2250.
01 R PIC 9.99.
PROCEDURE DIVISION.
COMPUTE R ROUNDED MODE IS NEAREST-EVEN = V
DISPLAY R
STOP RUN.
cobc -std=cobol2014 -fformat=free -x -o rmne rmne.cob

What happens

3.2.0 exits 1:

rmne.cob:8: error: syntax error, unexpected Identifier
    6 | 01 R PIC 9.99.
    7 | PROCEDURE DIVISION.
    8 > COMPUTE R ROUNDED MODE IS NEAREST-EVEN = V
    9 | DISPLAY R
   10 | STOP RUN.

3.3-dev r5751 gives the same output, exit 1.

Without -std the program compiles and prints 1.22 on both versions. Under -std=cobol2014, NEAREST-AWAY-FROM-ZERO in its place compiles (prints 1.23). ADD V TO 0 GIVING R ROUNDED MODE NEAREST-EVEN gives the same syntax error. OPTIONS. / DEFAULT ROUNDED MODE IS NEAREST-EVEN. gives it at the OPTIONS line (3.3-dev then adds PROCEDURE DIVISION header missing and syntax error, unexpected DATA). Both compile and print 1.22 without -std.

cobc --list-reserved -std=cobol2014 | grep -i nearest, both versions:

NEAREST-AWAY-FROM-ZERO          Yes (Context sensitive)
NEAREST-EVEN-INTERMEDIATE       No (Context sensitive)
NEAREST-TO-ZERO                 No
NEAREST-TOWARD-ZERO             Yes (Context sensitive)

and without -std (3.2.0):

NEAREST-AWAY-FROM-ZERO          Yes (Context sensitive)
NEAREST-EVEN                    Yes (Context sensitive)
NEAREST-TOWARD-ZERO             Yes (Context sensitive)

What should happen

This is a word-list bug, not a conformance claim. The MODE phrase is processor-dependent, §A.3 item 14: "The MODE phrase is dependent on the capabilities of the processor. When support for this phrase is provided, support for at least one of the following shall be provided in the ROUNDED phrase" (item 9 says the same of the DEFAULT ROUNDED clause). A compiler may therefore refuse a mode it does not support. cobc does support NEAREST-EVEN, and only -std=cobol2014 hides it. With the word available, the program prints 1.22.

  • §14.7.4.2 lists NEAREST-EVEN among the eight modes of ROUNDED [ MODE IS { ... } ]. §8.10 lists NEAREST-EVEN as a context-sensitive word of the "INTERMEDIATE ROUNDING clause and ROUNDED phrase".
  • §14.7.4.3 general rule 5): "If the NEAREST-EVEN phrase is specified and the arithmetic value cannot be exactly represented in the resultant identifier, the arithmetic value is rounded to the nearest value that can be represented in the resultant identifier. If two such values are equally near, the value whose rightmost digit is even is chosen." 1.2250 is halfway between 1.22 and 1.23.

The word NEAREST-EVEN-INTERMEDIATE is in no edition. It looks like the §8.10 row "NEAREST-EVEN | INTERMEDIATE ROUNDING clause and ROUNDED phrase" run together.

Proposed fix

cobol2014-syntax-gaps-case6-nearest-even.patch changes config/cobol2014.words line 318 from reserved: NEAREST-EVEN-INTERMEDIATE* to reserved: NEAREST-EVEN*. The entry for NEAREST-EVEN in cobc/reserved.c (context-sensitive in CB_CS_ROUNDED) is already correct, and no other file in config/ names NEAREST-EVEN-INTERMEDIATE.

With the patch, cobc -std=cobol2014 -fformat=free -x -o rmne rmne.cob gives exit 0 with no diagnostics, and ./rmne prints, exit 0:

1.22

Under -std=cobol2014, OPTIONS. / DEFAULT ROUNDED MODE IS NEAREST-EVEN. and ADD V TO 0 GIVING R ROUNDED MODE NEAREST-EVEN also compile, and both store 1.22.

make check on 3.3-dev r5751 with the patch passes: 1373 behaved as expected, 9 skipped, 0 failed (unpatched: 1372, 9, 0). The patch adds the test "ROUNDED NEAREST-EVEN with -std=cobol2014" to tests/testsuite.src/run_fundamental.at, after "ROUNDED NEAREST-EVEN"; the new test 599 passes. It also adds ChangeLog entries.

7. BYTE-LENGTH (x, PHYSICAL) and LENGTH (x, PHYSICAL): "unexpected comma delimiter"

To reproduce

blx.cob:

IDENTIFICATION DIVISION.
PROGRAM-ID. BLX.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 X PIC X(3).
PROCEDURE DIVISION.
    DISPLAY FUNCTION BYTE-LENGTH (X, PHYSICAL)
    STOP RUN.
cobc -std=cobol2014 -fformat=free -x -o blx blx.cob

What happens

3.2.0 exits 1:

blx.cob:7: error: syntax error, unexpected comma delimiter, expecting PHYSICAL or )
    5 | 01 X PIC X(3).
    6 | PROCEDURE DIVISION.
    7 >     DISPLAY FUNCTION BYTE-LENGTH (X, PHYSICAL)
    8 |     STOP RUN.
    9 | <EOF>

3.3-dev r5751 gives the same output, exit 1. It is also the same with the default dialect.

FUNCTION LENGTH (X, PHYSICAL) gives the same error. BYTE-LENGTH (X PHYSICAL) and BYTE-LENGTH (X; PHYSICAL) compile (with warning: PHYSICAL argument for LENGTH functions is not implemented [-Wpending]) and print 3. FUNCTION TRIM (X, LEADING) compiles.

What should happen

The program compiles and prints 3.

  • §5.2.8: "The separators comma and semicolon may be used anywhere the separator space is used in general formats and other syntactic specifications."
  • §15.14.2, general format: FUNCTION BYTE-LENGTH ( argument-1 [ PHYSICAL ] ). A separator space stands between argument-1 and PHYSICAL.
  • §15.14.4 rule 1): "The returned value is an integer that is the length of argument-1 in number of bytes." X is not a variable-length group, so PHYSICAL does not change the value.

Proposed fix

cobol2014-syntax-gaps-case7-length-physical.patch changes the alternative LENGTH_FUNC TOK_OPEN_PAREN length_arg PHYSICAL TOK_CLOSE_PAREN func_refmod of rule function in cobc/parser.y (line 20196 in r5751). It uses a new nonterminal length_physical: PHYSICAL, COMMA_DELIM PHYSICAL or SEMI_COLON PHYSICAL.

We first tried length_arg _e_sep PHYSICAL, as trim_args writes it. It also accepts the separators, but bison's default reduction of the empty _e_sep cuts the syntax error for a bad argument down to expecting PHYSICAL, dropping ). That made the existing test "FUNCTION LENGTH / BYTE-LENGTH" fail. With the explicit nonterminal the message becomes syntax error, unexpected Literal, expecting comma delimiter or PHYSICAL or semi-colon or ) (on r5751: expecting PHYSICAL or )), and the patch updates that one expected line in the existing test. bison reports no new conflicts.

With the patch, cobc -std=cobol2014 -fformat=free -x -o blx blx.cob exits 0:

blx.cob:8: warning: PHYSICAL argument for LENGTH functions is not implemented [-Wpending]
    6 | PROCEDURE DIVISION.
    7 |     DISPLAY FUNCTION BYTE-LENGTH (X, PHYSICAL)
    8 >     STOP RUN.
    9 | <EOF>

and ./blx prints, exit 0:

3

FUNCTION LENGTH (X, PHYSICAL) and FUNCTION BYTE-LENGTH (X; PHYSICAL) compile with the same warning and print 3.

make check on 3.3-dev r5751 with the patch passes: 1373 behaved as expected, 9 skipped, 0 failed (unpatched: 1372, 9, 0). The patch adds the test "FUNCTION LENGTH / BYTE-LENGTH with separator" to tests/testsuite.src/syn_functions.at; the new test 487 and the adjusted test 486 pass. It also adds ChangeLog entries.

8. SET condition-name TO TRUE refused when the 88 VALUE is SPACE and the item is numeric-edited

To reproduce

setsp.cob:

IDENTIFICATION DIVISION.
PROGRAM-ID. SETSP.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 E PIC Z(5) VALUE "  123".
   88 E-BLANK VALUE SPACES.
PROCEDURE DIVISION.
    SET E-BLANK TO TRUE
    DISPLAY "[" E "]"
    STOP RUN.
cobc -std=cobol2014 -fformat=free -x -o setsp setsp.cob

What happens

3.2.0 exits 1:

setsp.cob:8: error: invalid SET statement
    6 |    88 E-BLANK VALUE SPACES.
    7 | PROCEDURE DIVISION.
    8 >     SET E-BLANK TO TRUE
    9 |     DISPLAY "[" E "]"
   10 |     STOP RUN.

3.3-dev r5751 gives the same output, exit 1. It is also the same with the default dialect.

The 88 entry itself is accepted. With 88 E-BLANK VALUE " ". the program compiles and prints [ ] on both versions. With 88 E-BLANK VALUE LOW-VALUE. the SET is refused the same way.

What should happen

The program compiles and prints [ ].

  • §14.9.39.4 general rule 6): "If the TRUE phrase is specified, the literal in the VALUE clause associated with condition-name-1 is placed in the conditional variable according to the rules for the VALUE clause". The VALUE clause's rules govern the store, not the MOVE statement's.
  • §8.3.3.6.3 syntax rule 1): "A figurative constant may be used whenever 'literal' appears in a format or when a rule allows it".
  • §13.18.63.3 syntax rule 7) (all formats): "If the item is of category numeric-edited and the literal is of class alphanumeric or national, the class of the literal shall conform to that of the data item". An alphanumeric literal is therefore allowed for a numeric-edited item, as cobc's acceptance of the 88 entry shows.
  • The refusal matches the MOVE statement's §14.9.25.3 syntax rule 5): "the move of an alphanumeric figurative constant (SPACE, QUOTE, HIGH-VALUE, LOW-VALUE, ALL "literal", or ALL symbolic-character) to either a numeric item or a numeric-edited item is prohibited". That rule belongs to MOVE, and no MOVE is written here.

The SET rule has the same words in the 2002 standard and the 2014 committee draft.

Where the fix belongs

In cobc/typeck.c, cb_emit_set_true builds the store with cb_build_move of the VALUE literal, and validate_move is called with is_value 0. Its figurative-constant arm (SPACE, LOW-VALUE, HIGH-VALUE, QUOTE with a numeric or numeric-edited target, around line 11160 in r5751) jumps to invalid: whenever the statement is SET, before the cb_move_fig_space_to_numeric check. No dialect option changes it. Validating this store under the VALUE-clause rules (the is_value path, which already admits SPACE for a numeric-edited item) would follow general rule 6. This is inferred from the source.

No patch is attached for this case. The refusal is an explicit STMT_SET test in validate_move, and cb_build_move has no VALUE-clause mode to call instead. The fix needs a store path for SET TRUE/FALSE that applies the VALUE-clause rules, so it is not a one-line change.

9. NOT before a condition that has its own NOT: "boolean expected with logical operator"

To reproduce

negnot.cob:

IDENTIFICATION DIVISION.
PROGRAM-ID. NEGNOT.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 X PIC S9(4) VALUE 1.
PROCEDURE DIVISION.
    IF NOT X IS NOT ZERO
       DISPLAY "1 T"
    ELSE
       DISPLAY "1 F"
    END-IF
    IF NOT X IS NOT = 0
       DISPLAY "2 T"
    ELSE
       DISPLAY "2 F"
    END-IF
    IF NOT X IS NOT NUMERIC
       DISPLAY "3 T"
    ELSE
       DISPLAY "3 F"
    END-IF
    STOP RUN.
cobc -std=cobol2014 -fformat=free -x -o negnot negnot.cob

What happens

3.2.0 exits 1:

negnot.cob:7: error: invalid expression: boolean expected with logical operator
    5 | 01 X PIC S9(4) VALUE 1.
    6 | PROCEDURE DIVISION.
    7 >     IF NOT X IS NOT ZERO
    8 |        DISPLAY "1 T"
    9 |     ELSE
negnot.cob:12: error: invalid expression: boolean expected with logical operator
   10 |        DISPLAY "1 F"
   11 |     END-IF
   12 >     IF NOT X IS NOT = 0
   13 |        DISPLAY "2 T"
   14 |     ELSE
negnot.cob:17: error: invalid expression: boolean expected with logical operator
   15 |        DISPLAY "2 F"
   16 |     END-IF
   17 >     IF NOT X IS NOT NUMERIC
   18 |        DISPLAY "3 T"
   19 |     ELSE

3.3-dev r5751 gives the same output, exit 1. It is also the same with the default dialect.

With the inner condition parenthesised (IF NOT (X IS NOT ZERO) and so on) the program compiles and prints 1 F, 2 F, 3 T on both versions. Without the inner NOT (IF NOT X IS ZERO, IF NOT X = 0, IF NOT X IS NUMERIC) it compiles and prints 1 T, 2 T, 3 F.

What should happen

The program compiles and prints 1 F, 2 F, 3 T.

  • §8.8.4.2.1: "The simple conditions are the relation, boolean, class, condition-name, switch-status, sign, and omitted-argument conditions." X IS NOT ZERO (sign), X IS NOT = 0 (relation) and X IS NOT NUMERIC (class) are simple conditions, each with its own optional NOT in its general format.
  • §8.8.4.10.1: "A condition is negated by use of the logical operator 'NOT', which reverses the truth value of the condition to which it is applied."
  • §8.8.4.11.3, Table 5 (Combinations of conditions, logical operators, and parentheses): NOT may be first and may be followed by a simple-condition. The only NOT pairing excluded is NOT NOT: "the pair 'NOT (' is permissible while the pair 'NOT NOT' is not permissible". None of these conditions is combined, so the abbreviated combined relation rules (§8.8.4.12) do not apply.

Where the fix belongs

The error comes from cb_build_binary_op in cobc/tree.c (line 6379 in r5751), reached from the expression builder in cobc/typeck.c (cb_build_expr, build_expr_reduce and the '!' case). When the condition after a leading NOT carries its own NOT, the leading NOT is applied to an operand that is not yet a condition. This is inferred from the source and the message. We did not trace it in a debugger, and no patch is attached for this case.

  • #875: a sign condition refused depending on its position in a combined condition (fixed).
  • #663: not less or equals 0 (fixed). Both are other NOT/sign cases in the same expression builder.

Details

GnuCOBOL 3.2.0 (Ubuntu gnucobol3 3.2-4build1) and 3.3-dev r5751 (CI snapshot 3.3-dev.138 of 2026-10-29), x86_64 Linux. Every case was re-run 2026-10-30. On 3.2.0 each successful compile also prints the C compiler's <command-line>: warning: '_FORTIFY_SOURCE' redefined (from the Ubuntu package's build flags); it is left out above.

Attached: one program per case (imppic.cob, evca.cob, frefmod.cob, fcharrm.cob, rwrec.cob, rmne.cob, blx.cob, setsp.cob, negnot.cob), and a proposed patch for cases 1, 5, 6 and 7: cobol2014-syntax-gaps-case1-implicit-picture.patch, cobol2014-syntax-gaps-case5-rewrite-record.patch, cobol2014-syntax-gaps-case6-nearest-even.patch, cobol2014-syntax-gaps-case7-length-physical.patch.

The four patches are independent. Each is against 3.3-dev r5751, applies with patch -p1 at the top of the source tree, and was built and tested alone (make check with TESTSUITEFLAGS=-j8; unpatched r5751 gives 1372 behaved as expected, 9 skipped, 0 failed). Each adds one testsuite case and ChangeLog entries.

13 Attachments

Discussion


Log in to post a comment.