From 7bb60977011c47547660352028935ec92b1f0282 Mon Sep 17 00:00:00 2001 From: engboris Date: Thu, 25 Apr 2024 19:15:43 +0200 Subject: [PATCH] Add >>IMP INCLUDE directive --- NEWS | 2 + cobc/ChangeLog | 6 ++ cobc/cobc.c | 1 + cobc/cobc.h | 2 + cobc/codegen.c | 20 +++++- cobc/pplex.l | 28 ++++++++ cobc/ppparse.y | 34 +++++++++ cobc/scanner.l | 38 ++++++++++ doc/gnucobol.texi | 2 + tests/testsuite.src/syn_misc.at | 102 +++++++++++++++++++++++++++ tests/testsuite.src/used_binaries.at | 31 ++++++++ 11 files changed, 263 insertions(+), 3 deletions(-) diff --git a/NEWS b/NEWS index f14ccc283..6244780cd 100644 --- a/NEWS +++ b/NEWS @@ -41,6 +41,8 @@ NEWS - user visible changes -*- outline -*- calls to externals. The files are put into quotes, unless they start by '<'. Quoted files are expected to have absolute paths, as the C compiler is called in a temp directory instead of the project directory. + The directive >>IMP INCLUDE "FILE.h" or >>IMP INCLUDE can be used + as an alternative to this compiler option. ** output of unlimited errors may be requested by -fmax-errors=0, to stop compiliation at first error use -Wfatal-errors diff --git a/cobc/ChangeLog b/cobc/ChangeLog index 1b31823bf..06a68b5d8 100644 --- a/cobc/ChangeLog +++ b/cobc/ChangeLog @@ -9,6 +9,12 @@ replace stream) and we use a circular buffer for the temporary queue of tokens instead of a list. +2024-04-25 Boris Eng + + * cobc.h, pplex.l, ppparse.y: new >>IMP INCLUDE directive to include + multiple header files in the C generated code. Has the same behavior as the + --include compiler option. + 2024-03-17 Fabrice Le Fessant Emilien Lemaire diff --git a/cobc/cobc.c b/cobc/cobc.c index d89878c7d..2c92ad806 100644 --- a/cobc/cobc.c +++ b/cobc/cobc.c @@ -237,6 +237,7 @@ const char *cb_storage_file_name = NULL; const char *cb_call_extfh = NULL; struct cb_text_list *cb_copy_list = NULL; struct cb_text_list *cb_include_file_list = NULL; +struct cb_text_list *cb_include_file_list_directive = NULL; struct cb_text_list *cb_include_list = NULL; struct cb_text_list *cb_depend_list = NULL; struct cb_text_list *cb_intrinsic_list = NULL; diff --git a/cobc/cobc.h b/cobc/cobc.h index 7b5f30bbd..38b167921 100644 --- a/cobc/cobc.h +++ b/cobc/cobc.h @@ -475,6 +475,7 @@ extern FILE *cb_depend_file; extern struct cb_text_list *cb_depend_list; extern struct cb_text_list *cb_copy_list; extern struct cb_text_list *cb_include_file_list; +extern struct cb_text_list *cb_include_file_list_directive; extern struct cb_text_list *cb_include_list; extern struct cb_text_list *cb_intrinsic_list; extern struct cb_text_list *cb_extension_list; @@ -597,6 +598,7 @@ extern unsigned int ppparse_verify (const enum cb_support tag, extern void ppparse_error (const char *); extern int cobc_deciph_source_format (const char *); +extern int cobc_deciph_header_filename (const char *); extern void cobc_set_source_format (const enum cb_format); extern enum cb_format cobc_get_source_format (void) COB_A_PURE; extern int cobc_get_indicator_column (void) COB_A_PURE; diff --git a/cobc/codegen.c b/cobc/codegen.c index 2dd0c7520..f75ff8db5 100644 --- a/cobc/codegen.c +++ b/cobc/codegen.c @@ -1830,14 +1830,28 @@ output_gnucobol_defines (const char *formatted_date) output_line ("#define COB_MODULE_TIME\t\t%d", i); { - struct cb_text_list *l = cb_include_file_list ; - for (;l;l=l->next){ - if (l->text[0] == '<'){ + struct cb_text_list *l = cb_include_file_list; + struct cb_text_list *ld = cb_include_file_list_directive; + struct cb_text_list *next; + for (;l;l=l->next) { + if (l->text[0] == '<') { output_line ("#include %s", l->text); } else { output_line ("#include \"%s\"", l->text); } } + while (ld) { + if (ld->text[0] == '<') { + output_line ("#include %s", ld->text); + } else { + output_line ("#include \"%s\"", ld->text); + } + next = ld->next; + if (next != NULL) + free (ld); + ld = next; + } + cb_include_file_list_directive = NULL; } } diff --git a/cobc/pplex.l b/cobc/pplex.l index 02bb2640c..f5906362f 100644 --- a/cobc/pplex.l +++ b/cobc/pplex.l @@ -227,6 +227,7 @@ MAYBE_AREA_A [ ]?#? %x ALNUM_LITERAL_STATE %x CONTROL_STATEMENT_STATE %x DISPLAY_DIRECTIVE_STATE +%x IMP_DIRECTIVE_STATE %% @@ -360,6 +361,11 @@ MAYBE_AREA_A [ ]?#? return CALL_DIRECTIVE; } +^{MAYBE_AREA_A}[ ]*">>"[ ]?"IMP" { + BEGIN IMP_DIRECTIVE_STATE; + return IMP_DIRECTIVE; +} + ^{MAYBE_AREA_A}[ ]*">>"[ ]*\n { /* empty 2002+ style directive */ cb_plex_warning (COBC_WARN_FILLER, newline_count, @@ -724,6 +730,7 @@ ELSE_DIRECTIVE_STATE, ENDIF_DIRECTIVE_STATE, ALNUM_LITERAL_STATE, CONTROL_STATEMENT_STATE, +IMP_DIRECTIVE_STATE, COBOL_WORDS_DIRECTIVE_STATE>{ \n { BEGIN INITIAL; @@ -993,6 +1000,14 @@ ENDIF_DIRECTIVE_STATE>{ } } +{ + "INCLUDE" { return INCLUDE; } /* GnuCOBOL 3.3 extension */ + {ALNUM_LITERAL} { + pplval.s = cobc_plex_strdup (yytext); + return TOKEN; + } +} + { "IS" { return IS; } "NOT" { return NOT; } @@ -1867,6 +1882,19 @@ int cobc_deciph_source_format (const char *sfname) { return 1; } +int cobc_deciph_header_filename (const char *filename) { + size_t n = strlen(filename); + if (filename[0] == '<' && filename[n-1] == '>' && + filename[n-3] == '.' && filename[n-2] == 'h') { + return 0; + } else if (filename[n-2] == '.' && filename[n-1] == 'h') { + return 0; + } + else { + return 1; + } +} + void plex_clear_vars (void) { diff --git a/cobc/ppparse.y b/cobc/ppparse.y index 76b3c9a58..fa9513b47 100644 --- a/cobc/ppparse.y +++ b/cobc/ppparse.y @@ -741,6 +741,9 @@ ppparse_clear_vars (const struct cb_define_struct *p) %token WITH %token LOCATION +%token IMP_DIRECTIVE +%token INCLUDE + %token TERMINATOR "end of line" %token TOKEN "Word or Literal" @@ -768,6 +771,7 @@ ppparse_clear_vars (const struct cb_define_struct *p) %type alnum_equality_list %type ec_list %type unquoted_literal +%type imp_include_sources %type _copy_replacing %type replacing_list @@ -838,6 +842,7 @@ directive: | TURN_DIRECTIVE turn_directive | LISTING_DIRECTIVE listing_directive | LEAP_SECOND_DIRECTIVE leap_second_directive +| IMP_DIRECTIVE imp_directive | IF_DIRECTIVE { current_cmd = PLEX_ACT_IF; @@ -1368,6 +1373,35 @@ leap_second_directive: | OFF ; +imp_directive: + /* GnuCOBOL 3.3 extension */ + INCLUDE imp_include_sources + { + struct cb_text_list *p = $2; + while (p != NULL) { + fprintf (ppout, "#INCLUDE %s\n", p->text); + p = p->next; + } + } +; + +imp_include_sources: + TOKEN + { + char *f = fix_filename ($1); + if (cobc_deciph_header_filename (f) != 0) + ppp_error_invalid_option ("IMP", f); + $$ = ppp_list_add (NULL, f); + } +| imp_include_sources TOKEN + { + char *f = fix_filename ($2); + if (cobc_deciph_header_filename (f) != 0) + ppp_error_invalid_option ("IMP", f); + $$ = ppp_list_add ($1, f); + } +; + turn_directive: ec_list CHECKING on_or_off { diff --git a/cobc/scanner.l b/cobc/scanner.l index 15f3d1871..1595a8fa5 100644 --- a/cobc/scanner.l +++ b/cobc/scanner.l @@ -192,6 +192,7 @@ static void copy_two_words_in_quotes (char ** const, char ** const); static void add_synonym (const int, const int); static void make_synonym (void); static void clear_constants (void); +static struct cb_text_list *scan_list_add (struct cb_text_list *, const char *); %} @@ -323,6 +324,14 @@ AREA_A "#AREA_A"\n cobc_areacheck = 0; } +<*>^[ ]?"#INCLUDE".*\n { + yytext[strlen(yytext)-1] = '\0'; + cb_include_file_list_directive = scan_list_add ( + cb_include_file_list_directive, + yytext + 9 + ); +} + <*>^{AREA_A}[ ]*/"." { count_lines (yytext + 9); /* skip "\n#area_a\n" */ if (cobc_in_procedure && cobc_areacheck) { @@ -1297,6 +1306,17 @@ H#[0-9A-Za-z]+ { } } +{ + "IS" { + /* Ignore */ + } + [^ \n;]+ { + BEGIN INITIAL; + scan_picture (yytext); + RETURN_TOK (PICTURE); + } +} + <> { /* At EOF - Clear variables */ clear_constants (); @@ -2583,6 +2603,22 @@ clear_constants (void) top_78_ptr = NULL; } +static struct cb_text_list * +scan_list_add (struct cb_text_list *list, const char *text) +{ + struct cb_text_list *p; + + p = cobc_plex_malloc (sizeof (struct cb_text_list)); + p->text = cobc_plex_strdup (text); + if (!list) { + p->last = p; + return p; + } + list->last->next = p; + list->last = p; + return list; +} + /* Global functions */ void @@ -2772,3 +2808,5 @@ cb_find_defined_program_by_id (const char *orig_id) return NULL; } + + diff --git a/doc/gnucobol.texi b/doc/gnucobol.texi index af4eb9fd2..dea8111ae 100644 --- a/doc/gnucobol.texi +++ b/doc/gnucobol.texi @@ -383,6 +383,8 @@ Add a @code{#include} @file{file.h} at the beginning of the generated C source file. The file name is put into quotes, unless it starts by @code{<}. Quoted files should be absolute paths, since C files are compiled in temporary directories. +The directive @code{>>IMP INCLUDE "FILE.h"} or @code{>>IMP INCLUDE } +can be used as an alternative to this compiler option. The option also implies @option{-fno-gen-c-decl-static-call}. This option can be used to check function prototypes when static calls are used. When this option is used, the source file is diff --git a/tests/testsuite.src/syn_misc.at b/tests/testsuite.src/syn_misc.at index 5b9aff259..2522867c0 100644 --- a/tests/testsuite.src/syn_misc.at +++ b/tests/testsuite.src/syn_misc.at @@ -8385,3 +8385,105 @@ prog.cob:18: error: ANY LENGTH items may only be BY REFERENCE formal parameters AT_CLEANUP +AT_SETUP([IMP INCLUDE directive]) +AT_KEYWORDS([IMP INCLUDE]) + +AT_DATA([prog.cob], [ + >>IMP INCLUDE "file.h" + IDENTIFICATION DIVISION. + PROGRAM-ID. prog. + PROCEDURE DIVISION. + GOBACK. +]) + +AT_CHECK([$COMPILE_ONLY -fformat=fixed prog.cob], [0], [], []) + +AT_DATA([prog.cob], [ +>>IMP INCLUDE "file.h" +identification division. +program-id. prog. +procedure division. + goback. +]) + +AT_CHECK([$COMPILE_ONLY -fformat=free prog.cob], [0], [], []) + +AT_CLEANUP + +AT_SETUP([IMP INCLUDE directive multiple files]) +AT_KEYWORDS([IMP INCLUDE]) + +AT_DATA([prog.cob], [ +>>IMP INCLUDE "file1.h" "file2.h" "file3.h" +identification division. +program-id. prog. +procedure division. + goback. +]) + +AT_CHECK([$COMPILE_ONLY -fformat=free prog.cob], [0], [], []) + +AT_CLEANUP + +AT_SETUP([IMP INCLUDE directive file format]) +AT_KEYWORDS([IMP INCLUDE]) + +AT_DATA([prog.cob], [ +>>IMP INCLUDE "file" +identification division. +program-id. prog. +procedure division. + goback. +]) + +AT_CHECK([$COMPILE_ONLY -fformat=free prog.cob], [1], [], +[prog.cob:2: error: invalid IMP directive option 'file' +]) + +AT_DATA([prog.cob], [ +>>IMP INCLUDE file.h +identification division. +program-id. prog. +procedure division. + goback. +]) + +AT_CHECK([$COMPILE_ONLY -fformat=free prog.cob], [1], [], +[prog.cob:2: error: syntax error, unexpected ., expecting Word or Literal +prog.cob:2: error: PROGRAM-ID header missing +prog.cob:2: error: syntax error, unexpected end of file, expecting SECTION +]) + +AT_DATA([prog.cob], [ +>>IMP INCLUDE "file1.h" "file2" "file3.h" +identification division. +program-id. prog. +procedure division. + goback. +]) + +AT_CHECK([$COMPILE_ONLY --fformat=free prog.cob], [1], [], +[prog.cob:2: error: invalid IMP directive option 'file2' +]) + +AT_DATA([prog.cob], [ +>>IMP INCLUDE "file1.h" file2 "file3.h" +identification division. +program-id. prog. +procedure division. + goback. +]) + +AT_CHECK([$COMPILE_ONLY --fformat=free prog.cob], [1], [], +[prog.cob:2: error: PROGRAM-ID header missing +prog.cob:2: error: ENVIRONMENT DIVISION header missing +prog.cob:2: error: CONFIGURATION SECTION header missing +prog.cob:2: error: SPECIAL-NAMES header missing +prog.cob:2: error: invalid system-name 'file2' +prog.cob:2: error: invalid symbol '#' - skipping word +prog.cob:2: error: invalid system-name 'h' +prog.cob:4: error: syntax error, unexpected IDENTIFICATION, expecting CRT or Identifier +prog.cob:4: error: syntax error, unexpected DIVISION +]) + +AT_CLEANUP diff --git a/tests/testsuite.src/used_binaries.at b/tests/testsuite.src/used_binaries.at index d7266092e..e33a4c53a 100644 --- a/tests/testsuite.src/used_binaries.at +++ b/tests/testsuite.src/used_binaries.at @@ -1139,3 +1139,34 @@ AT_CHECK([$COMPILE_MODULE -Wno-unfinished --copy "f.copy" -fstatic-call prog2.co ]) AT_CLEANUP + +AT_SETUP([check include header file with directive]) +#AT_KEYWORDS([imp include]) + +AT_DATA([file.h], [ +COB_EXT_IMPORT void f (char *, long); +]) +AT_DATA([prog.cob], [ + >> IMP INCLUDE "file.h" + IDENTIFICATION DIVISION. + PROGRAM-ID. prog. + PROCEDURE DIVISION. + CALL "f" USING "Hello". +]) + +AT_CHECK([$COBC -m -I . -fstatic-call prog.cob], [1], [], [ignore]) + +AT_DATA([prog2.cob], [ + >> IMP INCLUDE "file.h" + IDENTIFICATION DIVISION. + PROGRAM-ID. prog. + DATA DIVISION. + WORKING-STORAGE SECTION. + 01 long USAGE BINARY-C-LONG. + PROCEDURE DIVISION. + CALL "f" USING "Hello" BY VALUE long RETURNING NOTHING. +]) + +AT_CHECK([$COBC -m -I . -fstatic-call prog2.cob], [0], [], []) + +AT_CLEANUP