Skip to content
13 changes: 13 additions & 0 deletions cobc/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@

2026-03-16 Uttam Singh Bhadauriya <uttamsinghbhadoriya23@gmail.com>

* pplex.l: add EXEC_STATE exclusive start condition to
tokenize EXEC <TAG> ... END-EXEC blocks; add AREA_A lookahead
rule for EXEC; return INCLUDE token for INCLUDE keyword,
plain TOKEN for words; consume all other content silently
* ppparse.y: add exec_statement grammar rule dispatched
from statement_no_replace; EXEC TAG INCLUDE handled as COPY
(full copybook expansion with -I and -ffold-copy support);
all other EXEC TAG blocks warn at "unsupported" level
(defaulting to error) and are ignored; add _exec_token_list
to consume body tokens for parsing purposes only

2025-12-29 Roger Bowler <rbowler@snipix.net>

* tree.c (finalize_file): if file is EXTFH enabled then don't warn for
Expand Down
45 changes: 45 additions & 0 deletions cobc/pplex.l
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ static int quotation_mark = 0;
static int echo_newline = 0;
static int listing_line = 0;
static int requires_listing_line;
static int exec_subsystem_seen = 0; /* set after first EXEC token returned */
static enum cb_format source_format = CB_FORMAT_AUTO;
static int indicator_column = 7;
static int indicator_error = 0;
Expand Down Expand Up @@ -226,6 +227,7 @@ MAYBE_AREA_A [ ]?#?
%x CONTROL_STATEMENT_STATE
%x DISPLAY_DIRECTIVE_STATE
%x IMP_DIRECTIVE_STATE
%X EXEC_STATE

%%

Expand Down Expand Up @@ -501,6 +503,7 @@ MAYBE_AREA_A [ ]?#?
^{AREA_A}[ \n]*/"COPY"[ ,;\n] { count_newlines (yytext); }
^{AREA_A}[ \n]*/"INCLUDE"[ ,;\n] { count_newlines (yytext); }
^{AREA_A}[ \n]*/"REPLACE"[ ,;\n] { count_newlines (yytext); }
^{AREA_A}[ \n]*/"EXEC"[ ,;\n] { count_newlines (yytext); }

"COPY"/[ ,;\n] {
yy_push_state (COPY_STATE);
Expand All @@ -525,6 +528,12 @@ MAYBE_AREA_A [ ]?#?
return REPLACE;
}

"EXEC"/[ ,;\n] {
exec_subsystem_seen = 0;
BEGIN(EXEC_STATE);
return EXEC;
}

^{MAYBE_AREA_A}.{6}[ ]*"*CONTROL" |
^{MAYBE_AREA_A}.{6}[ ]*"*CBL" {
BEGIN CONTROL_STATEMENT_STATE;
Expand Down Expand Up @@ -569,6 +578,35 @@ MAYBE_AREA_A [ ]?#?
}
}

<EXEC_STATE>{
"END-EXEC"([ \t]*\.)? {
BEGIN (INITIAL);
return END_EXEC;
}
"INCLUDE" { return INCLUDE; }
{WORD}\.{WORD} {
/* dotted name e.g. SQLCA.cpy or table.field */
pplval.s = cobc_plex_strdup (yytext);
return TOKEN;
}
{WORD} {
pplval.s = cobc_plex_strdup (yytext);
if (!exec_subsystem_seen) {
exec_subsystem_seen = 1;
return SUBSYSTEM;
}
return TOKEN;
}
{ALNUM_LITERAL} {
/* quoted copybook name e.g. INCLUDE "EMPREC" */
pplval.s = cobc_plex_strdup (yytext + 1);
pplval.s[strlen (pplval.s) - 1] = '\0';
return TEXT_NAME;
}
\n { cb_source_line++; }
. { /* silently consumed */ }
}

<SUBSTITUTION_SECTION_STATE,
CONTROL_DIVISION_STATE>{
"REPLACE" {
Expand Down Expand Up @@ -1205,6 +1243,13 @@ ENDIF_DIRECTIVE_STATE>{
<<EOF>> {
struct copy_info *current_copy_info = copy_stack;

if (YY_START == EXEC_STATE) {
BEGIN (INITIAL);
cb_plex_error (newline_count, _("missing END-EXEC at end of file"));
newline_count = 0;
return END_EXEC;
}

yy_delete_buffer (YY_CURRENT_BUFFER);

/* Terminate at the end of all input */
Expand Down
35 changes: 35 additions & 0 deletions cobc/ppparse.y
Original file line number Diff line number Diff line change
Expand Up @@ -753,6 +753,10 @@ ppparse_clear_vars (const struct cb_define_struct *p)
%token <s> VARIABLE_NAME "Variable"
%token <s> LITERAL "Literal"

%token EXEC
%token END_EXEC "END-EXEC"
%token <s> SUBSYSTEM "Subsystem"

%type <s> _copy_in
%type <s> copy_source
%type <s> _literal
Expand Down Expand Up @@ -830,6 +834,7 @@ statement:

statement_no_replace:
copy_statement
| exec_statement
| directive TERMINATOR
| listing_statement
| CONTROL_STATEMENT control_options _dot TERMINATOR
Expand Down Expand Up @@ -1726,6 +1731,36 @@ replacing_list:
}
;

_exec_token_list:
/* empty */
| _exec_token_list TOKEN
{
/* should be handled by preparser, ignored
if seen here purely for parsing reasons */
}
;

exec_statement:
EXEC SUBSYSTEM INCLUDE copy_source END_EXEC
{
/* EXEC TAG INCLUDE copybook — warn and handle as COPY */
cb_warning (cb_warn_unsupported,
_("EXEC %s INCLUDE handled as COPY"), $2);
fputc ('\n', ppout);
ppcopy ($4, NULL, NULL);
}
| EXEC SUBSYSTEM _exec_token_list END_EXEC
{
/* EXEC TAG ... END-EXEC — warn and ignore */
cb_warning (cb_warn_unsupported,
_("EXEC %s statement ignored"), $2);
}
| EXEC error END_EXEC
{
yyerrok;
}
;

text_src:
EQEQ token_list EQEQ
{
Expand Down
178 changes: 178 additions & 0 deletions tests/testsuite.src/syn_definition.at
Original file line number Diff line number Diff line change
Expand Up @@ -2947,3 +2947,181 @@ AT_DATA([prog.cob], [

AT_CHECK([$COMPILE_ONLY -Wno-unfinished prog.cob], [0], [], [])
AT_CLEANUP


### GnuCOBOL Test Suite - EXEC block handling


AT_SETUP([EXEC no tag])
AT_KEYWORDS([extensions])

AT_DATA([prog.cob], [
IDENTIFICATION DIVISION.
PROGRAM-ID. prog.
PROCEDURE DIVISION.
MAIN.
EXEC END-EXEC.
STOP RUN.
])

AT_CHECK([$COMPILE_ONLY prog.cob], [1], [],
[prog.cob:6: error: syntax error, unexpected END-EXEC, expecting Subsystem
])

AT_CLEANUP


AT_SETUP([EXEC empty block])
AT_KEYWORDS([extensions])

AT_DATA([prog.cob], [
IDENTIFICATION DIVISION.
PROGRAM-ID. prog.
PROCEDURE DIVISION.
MAIN.
EXEC CICS END-EXEC.
STOP RUN.
])

AT_CHECK([$COMPILE_ONLY -Werror=unsupported prog.cob], [1], [],
Comment thread
GitMensch marked this conversation as resolved.
[prog.cob:6: error: EXEC CICS statement ignored
])

AT_CLEANUP


AT_SETUP([EXEC statement ignored])
AT_KEYWORDS([extensions])

AT_DATA([prog.cob], [
IDENTIFICATION DIVISION.
PROGRAM-ID. prog.
PROCEDURE DIVISION.
MAIN.
EXEC SQL CONNECT RESET END-EXEC.
STOP RUN.
])

AT_CHECK([$COMPILE_ONLY -Werror=unsupported prog.cob], [1], [],
[prog.cob:6: error: EXEC SQL statement ignored
])

AT_CLEANUP


AT_SETUP([EXEC SQL INCLUDE sqlca and copybook])
AT_KEYWORDS([extensions])

AT_DATA([emprec.cpy], [
01 EMP-TABLE.
03 ENO PIC S9(4) COMP.
03 LNAME PIC X(10).
])

AT_DATA([prog.cob], [
IDENTIFICATION DIVISION.
PROGRAM-ID. prog.
DATA DIVISION.
WORKING-STORAGE SECTION.
EXEC SQL
INCLUDE SQLCA
END-EXEC.
EXEC SQL
INCLUDE EMPREC
END-EXEC.
PROCEDURE DIVISION.
MAIN.
DISPLAY SQLCODE.
MOVE 1 TO ENO.
STOP RUN.
])

AT_CHECK([$COMPILE_ONLY -Werror=unsupported -ffold-copy=LOWER prog.cob], [1], [],
[prog.cob:8: error: EXEC SQL INCLUDE handled as COPY
prog.cob:11: error: EXEC SQL INCLUDE handled as COPY
])

AT_CHECK([rm -f emprec.cpy], [0], [], [])
AT_CHECK([$COMPILE_ONLY -Werror=unsupported -ffold-copy=LOWER prog.cob], [1], [], [prog.cob:8: error: EXEC SQL INCLUDE handled as COPY
prog.cob:11: error: EXEC SQL INCLUDE handled as COPY
prog.cob:11: error: emprec: No such file or directory
prog.cob: in paragraph 'MAIN':
prog.cob:15: error: 'ENO' is not defined
])

AT_CLEANUP


AT_SETUP([EXEC SQL INCLUDE quoted literal])
AT_KEYWORDS([extensions])

AT_DATA([emprec.cpy], [
01 EMP-TABLE.
03 ENO PIC S9(4) COMP.
03 LNAME PIC X(10).
])

AT_DATA([prog.cob], [
IDENTIFICATION DIVISION.
PROGRAM-ID. prog.
DATA DIVISION.
WORKING-STORAGE SECTION.
EXEC SQL
INCLUDE "EMPREC"
END-EXEC.
PROCEDURE DIVISION.
MAIN.
MOVE 1 TO ENO.
STOP RUN.
])

AT_CHECK([$COMPILE_ONLY -Werror=unsupported -ffold-copy=LOWER prog.cob], [1], [],
[prog.cob:8: error: EXEC SQL INCLUDE handled as COPY
])

AT_CLEANUP


AT_SETUP([EXEC SQL INCLUDE dotted name])
AT_KEYWORDS([extensions])

AT_DATA([prog.cob], [
IDENTIFICATION DIVISION.
PROGRAM-ID. prog.
DATA DIVISION.
WORKING-STORAGE SECTION.
EXEC SQL
INCLUDE SQLCA.cpy
END-EXEC.
PROCEDURE DIVISION.
MAIN.
DISPLAY SQLCODE.
STOP RUN.
])

AT_CHECK([$COMPILE_ONLY -Werror=unsupported -ffold-copy=LOWER prog.cob], [1], [],
[prog.cob:8: error: EXEC SQL INCLUDE handled as COPY
])

AT_CLEANUP


AT_SETUP([END-EXEC missing])
AT_KEYWORDS([extensions])

AT_DATA([prog.cob], [
IDENTIFICATION DIVISION.
PROGRAM-ID. prog.
PROCEDURE DIVISION.
MAIN.
* typo added on purpose to check handling that
EXEC SQL CONNECT RESET ENDEXEC.
STOP RUN.
])

AT_CHECK([$COMPILE_ONLY -Werror=unsupported prog.cob], [1], [],
[prog.cob:9: error: missing END-EXEC at end of file
prog.cob:9: error: EXEC SQL statement ignored
])

AT_CLEANUP
Loading