From 8218884bce234f3741e322eb3e869e3ec71e4958 Mon Sep 17 00:00:00 2001 From: Fabrice Le Fessant Date: Tue, 6 Jun 2023 14:48:26 +0200 Subject: [PATCH] move ppecho() to replace.c --- cobc/ChangeLog | 5 + cobc/Makefile.am | 3 +- cobc/pplex.l | 285 ++---------------------------------------- cobc/ppparse.y | 4 +- cobc/replace.c | 316 +++++++++++++++++++++++++++++++++++++++++++++++ cobc/replace.h | 45 +++++++ cobc/tree.h | 4 +- 7 files changed, 384 insertions(+), 278 deletions(-) create mode 100644 cobc/replace.c create mode 100644 cobc/replace.h diff --git a/cobc/ChangeLog b/cobc/ChangeLog index dbe36918f..35d8066d1 100644 --- a/cobc/ChangeLog +++ b/cobc/ChangeLog @@ -1,4 +1,9 @@ +2023-07-02 Fabrice Le Fessant + + * pplex.l/replace.c: move the preprocessing code performing + COPY REPLACING and REPLACE from pplex.l to replace.c + 2023-07-02 Fabrice Le Fessant * pplex.l (ppecho, ppecho_direct): replace alt_space by passing a diff --git a/cobc/Makefile.am b/cobc/Makefile.am index 417af58aa..a96b7c3ab 100644 --- a/cobc/Makefile.am +++ b/cobc/Makefile.am @@ -22,7 +22,8 @@ bin_PROGRAMS = cobc cobc_SOURCES = cobc.c cobc.h ppparse.y pplex.c parser.y scanner.c config.c \ reserved.c error.c tree.c tree.h field.c typeck.c codegen.c help.c \ - config.def flag.def warning.def codeoptim.def ppparse.def codeoptim.c + config.def flag.def warning.def codeoptim.def ppparse.def \ + codeoptim.c replace.h replace.c #cobc_SOURCES = cobc.c cobc.h ppparse.y pplex.l parser.y scanner.l config.c diff --git a/cobc/pplex.l b/cobc/pplex.l index c5bfb2efd..ce5b65343 100644 --- a/cobc/pplex.l +++ b/cobc/pplex.l @@ -92,6 +92,7 @@ static int ppwrap (void) { #include "cobc.h" #include "tree.h" #include "ppparse.h" +#include "replace.h" #ifdef _WIN32 #include /* for access */ @@ -157,29 +158,13 @@ static int emit_area_a_tokens = 0; static char display_msg[PPLEX_BUFF_LEN]; -static struct cb_replace_list *current_replace_list = NULL; -static struct cb_replace_list *save_current_replace = NULL; -static struct cb_replace_list *base_replace_list = NULL; - -struct cb_token_list { - struct cb_token_list *next; /* next pointer */ - struct cb_token_list *last; - const char *text; - const char *token; -}; - -static struct cb_token_list *text_queue = NULL; -static size_t check_partial_match = 0; - static struct copy_info *copy_stack = NULL; static struct plex_stack plex_cond_stack[PLEX_COND_DEPTH]; /* Function declarations */ static int ppinput (char *, const size_t); -static void ppecho (const char *text, const char *token); -static void ppecho_direct (const char *text, const char *token); -static int ppecho_replace (struct cb_replace_list *); +static void ppecho (const char *text, const char *token ); static void switch_to_buffer (const int, const char *, const YY_BUFFER_STATE); @@ -187,7 +172,6 @@ static void check_listing (const char *, const unsigned int); static void skip_to_eol (void); static void count_newlines (const char *); static void display_finish (void); -static void set_print_replace_list (struct cb_replace_list *); static void get_new_listing_file (void); static struct cb_text_list *pp_text_list_add (struct cb_text_list *, @@ -1093,10 +1077,7 @@ ENDIF_DIRECTIVE_STATE>{ newline_count = 0; inside_bracket = 0; comment_allowed = 1; - current_replace_list = NULL; - base_replace_list = NULL; - save_current_replace = NULL; - text_queue = NULL; + cb_free_replace (); copy_stack = NULL; quotation_mark = 0; consecutive_quotation = 0; @@ -1118,7 +1099,7 @@ ENDIF_DIRECTIVE_STATE>{ current_copy_info->buffer); /* Restore variables */ - current_replace_list = current_copy_info->replacing; + cb_set_copy_replacing_list (current_copy_info->replacing); quotation_mark = current_copy_info->quotation_mark; cobc_set_source_format (current_copy_info->source_format); @@ -1131,35 +1112,6 @@ ENDIF_DIRECTIVE_STATE>{ /* Global functions */ -void -pp_set_replace_list (struct cb_replace_list *list, const cob_u32_t is_pushpop) -{ - /* Handle REPLACE verb */ - if (!list) { - /* REPLACE [LAST] OFF */ - if (!is_pushpop) { - base_replace_list = NULL; - return; - } - if (!base_replace_list) { - return; - } - base_replace_list = base_replace_list->prev; - return; - } - /* REPLACE [ALSO] ... */ - if (base_replace_list && is_pushpop) { - list->last->next = base_replace_list; - list->prev = base_replace_list; - } else { - list->prev = NULL; - } - base_replace_list = list; - if (cb_src_list_file) { - set_print_replace_list (list); - } -} - static int is_fixed_indicator (char c){ switch (c){ /* same indicators as in ppinput() */ @@ -1296,6 +1248,7 @@ ppopen (const char *name, struct cb_replace_list *replacing_list) { struct copy_info *current_copy_info; char *dname; + struct cb_replace_list *current_replace_list; if (ppin) { for (; newline_count > 0; newline_count--) { @@ -1331,6 +1284,7 @@ ppopen (const char *name, struct cb_replace_list *replacing_list) } /* preserve the current buffer */ + current_replace_list = cb_get_copy_replacing_list(); current_copy_info = cobc_malloc (sizeof (struct copy_info)); current_copy_info->file = cb_source_file; current_copy_info->buffer = YY_CURRENT_BUFFER; @@ -1354,9 +1308,9 @@ ppopen (const char *name, struct cb_replace_list *replacing_list) replacing_list->last->next = current_replace_list; replacing_list->last = current_replace_list->last; } - current_replace_list = replacing_list; + cb_set_copy_replacing_list (replacing_list); if (cb_src_list_file) { - set_print_replace_list (replacing_list); + cb_set_print_replace_list (replacing_list); } } @@ -1878,8 +1832,8 @@ get_new_listing_file (void) cb_current_file = newfile; } -static void -set_print_replace_list (struct cb_replace_list *list) +void +cb_set_print_replace_list (struct cb_replace_list *list) { struct cb_replace_list *r; const struct cb_text_list *l; @@ -1931,12 +1885,6 @@ switch_to_buffer (const int line, const char *file, const YY_BUFFER_STATE buffer yy_switch_to_buffer (buffer); } -static COB_INLINE COB_A_INLINE int -is_space_or_nl (const char c) -{ - return c == ' ' || c == '\n'; -} - static COB_INLINE COB_A_INLINE int is_cobol_word_char (const char c) { @@ -2599,219 +2547,10 @@ pp_text_list_add (struct cb_text_list *list, const char *text, return list; } -static struct cb_token_list * -pp_token_list_add (struct cb_token_list *list, - const char *text, - const char *token) -{ - struct cb_token_list *p; - void *tp; - int text_size = strlen (text); - - p = cobc_plex_malloc (sizeof (struct cb_token_list)); - if (token == NULL) { - tp = cobc_plex_malloc (text_size + 1); - p->token = NULL; - } else { - int token_size = strlen (token); - tp = cobc_plex_malloc( text_size + token_size + 2); - memcpy (tp+text_size+1, token, token_size); - p->token = tp+text_size+1; - } - memcpy (tp, text, text_size); - p->text = tp; - if (!list) { - p->last = p; - return p; - } - list->last->next = p; - list->last = p; - return list; -} - static void ppecho (const char *text, const char *token) { - /* performance note (last verified with GnuCOBOL 2.2): - while this function used 5% (according to callgrind) - of the complete time spent in a sample run with - -fsyntax-only on 880 production code files (2,500,000 LOC), - 3.8% of this time is spent in fwrite, therefore not much potential - for optimization */ - - struct cb_replace_list *save_ptr; - struct cb_token_list *save_ptr_text_queue; - int status, save_status; - -#if 0 /* Simon: disabled until found necessary, as this takes together with frwite - a big part of the parsing phase of cobc, increasing the IO cost by numbers */ - /* ensure nothing is in the stream buffer */ - fflush (ppout); -#endif - - if (text_queue == NULL && (text[0] == ' ' || text[0] == '\n')) { - ppecho_direct (text, token); - return; - } - if (!current_replace_list && !base_replace_list) { - /* Output queue */ - for (; text_queue; text_queue = text_queue->next) { - ppecho_direct(text_queue->text, text_queue->token); - } - ppecho_direct(text, token); - return; - } - if (!current_replace_list) { - current_replace_list = base_replace_list; - save_ptr = NULL; - } else { - current_replace_list->last->next = base_replace_list; - save_ptr = current_replace_list->last; - } - - /* Do replacement */ - text_queue = pp_token_list_add (text_queue, text, token); - - save_ptr_text_queue = text_queue; - status = ppecho_replace (save_ptr); - /* Search another replacement when have a Partial Match in the last ppecho call */ - if (check_partial_match && status != -1) { - save_status = status; - text_queue = save_ptr_text_queue; - while (text_queue && check_partial_match) { - if (is_space_or_nl (text_queue->text[0])) { - ppecho_direct (text_queue->text, - text_queue->token); - text_queue = text_queue->next; - continue; - } - status = ppecho_replace (save_ptr); - if (status > save_status) { - save_status = status; - } - if (text_queue) { - /* Write text_queue if is not replaced */ - if (status != -1 && check_partial_match) { - ppecho_direct (text_queue->text, - text_queue->token); - } - text_queue = text_queue->next; - } - } - status = save_status; - } - /* Manage Partial Match */ - if (status == -1) { - check_partial_match = save_ptr_text_queue != NULL; - return; - } - if (!status) { - current_replace_list = NULL; - } else { - save_ptr->next = NULL; - } - - /* No match */ - for (; text_queue; text_queue = text_queue->next) { - ppecho_direct (text_queue->text, text_queue->token); - } -} - -/* handle all kinds of COPY REPLACING and REPLACE */ -static int -ppecho_replace (struct cb_replace_list *save_ptr) -{ - char *temp_ptr; - size_t size; - size_t size2; - struct cb_token_list *queue; - struct cb_token_list *save_queue; - const struct cb_text_list *lno; - struct cb_replace_list *r; - - save_queue = NULL; - size = 0; - size2 = 0; - for (r = current_replace_list; r; r = r->next) { - queue = text_queue; - /* The LEADING/TRAILING code looks peculiar as we use */ - /* variables after breaking out of the loop BUT */ - /* ppparse.y guarantees that we have only one token */ - /* and therefore only one iteration of this loop */ - for (lno = r->src->text_list; lno; lno = lno->next) { - if (is_space_or_nl (lno->text[0])) { - continue; - } - while (queue && is_space_or_nl (queue->text[0])) { - queue = queue->next; - } - if (queue == NULL) { - /* Partial match */ - if (!save_ptr) { - current_replace_list = NULL; - } else { - save_ptr->next = NULL; - } - return -1; - } - if (r->src->lead_trail == CB_REPLACE_LEADING) { - /* Check leading text */ - size = strlen (lno->text); - if ((r->src->strict && strlen (queue->text) == size) - || strncasecmp (lno->text, queue->text, size)) { - /* No match */ - break; - } - save_queue = queue; - } else if (r->src->lead_trail == CB_REPLACE_TRAILING) { - /* Check trailing text */ - size = strlen (lno->text); - size2 = strlen (queue->text); - if (size2 < size - || (r->src->strict && size2 == size)) { - /* No match */ - break; - } - size2 -= size; - if (strncasecmp (lno->text, queue->text + size2, size)) { - /* No match */ - break; - } - save_queue = queue; - } else if (strcasecmp (lno->text, queue->text)) { - /* No match */ - break; - } - queue = queue->next; - } - if (lno == NULL) { - /* Match */ - if (r->src->lead_trail == CB_REPLACE_TRAILING - && save_queue /* <- silence warnings */) { - /* Non-matched part of original text */ - fprintf (ppout, "%*.*s", (int)size2, (int)size2, - save_queue->text); - if (cb_listing_file) { - temp_ptr = cobc_strdup (save_queue->text); - *(temp_ptr + size2) = 0; - check_listing (temp_ptr, 0); - cobc_free (temp_ptr); - } - } - for (lno = r->new_text; lno; lno = lno->next) { - ppecho_direct (lno->text, NULL); - } - if (r->src->lead_trail == CB_REPLACE_LEADING - && save_queue /* <- silence warnings */) { - /* Non-matched part of original text */ - ppecho_direct (save_queue->text + size, NULL); - } - check_partial_match = 0; - text_queue = queue; - continue; - } - } - return (save_ptr ? 1 : 0); + cb_ppecho_copy_replace (text, token); } static void @@ -2852,7 +2591,7 @@ display_finish (void) unput ('\n'); } -void ppecho_direct (const char *text, const char *token ) +void cb_ppecho_direct (const char *text, const char *token ) { fputs (text, ppout); if (cb_listing_file) { diff --git a/cobc/ppparse.y b/cobc/ppparse.y index a5d351176..ab0356f09 100644 --- a/cobc/ppparse.y +++ b/cobc/ppparse.y @@ -1633,11 +1633,11 @@ copy_replacing: replace_statement: REPLACE _also replacing_list { - pp_set_replace_list ($3, $2); + cb_set_replace_list ($3, $2); } | REPLACE _last OFF { - pp_set_replace_list (NULL, $2); + cb_set_replace_list (NULL, $2); } ; diff --git a/cobc/replace.c b/cobc/replace.c new file mode 100644 index 000000000..7439f6114 --- /dev/null +++ b/cobc/replace.c @@ -0,0 +1,316 @@ +/* + Copyright (C) 2003-2022 Free Software Foundation, Inc. + + Authors: + Keisuke Nishida, Roger While, Ron Norman, Simon Sobisch, Brian Tiffin, + Edward Hart, Dave Pitts + + This file is part of GnuCOBOL. + + The GnuCOBOL compiler is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + GnuCOBOL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GnuCOBOL. If not, see . +*/ + +#include "tarstamp.h" +#include "config.h" + +#include +#include +#include +#include +#include +#ifdef HAVE_STRINGS_H +#include +#endif +#include +#include +#include + +#include "cobc.h" +#include "tree.h" +#include "replace.h" + +static struct cb_replace_list *current_replace_list = NULL; +static struct cb_replace_list *save_current_replace = NULL; +static struct cb_replace_list *base_replace_list = NULL; + +struct cb_token_list { + struct cb_token_list *next; /* next pointer */ + struct cb_token_list *last; + const char *text; + const char *token; +}; + +static struct cb_token_list *text_queue = NULL; +static size_t check_partial_match = 0; + +static int ppecho_replace (struct cb_replace_list *); + +static struct cb_token_list * +pp_token_list_add (struct cb_token_list *list, + const char *text, + const char *token) +{ + struct cb_token_list *p; + void *tp; + int text_size = strlen (text); + + p = cobc_plex_malloc (sizeof (struct cb_token_list)); + if (token == NULL) { + tp = cobc_plex_malloc (text_size + 1); + p->token = NULL; + } else { + int token_size = strlen (token); + tp = cobc_plex_malloc( text_size + token_size + 2); + memcpy (tp+text_size+1, token, token_size); + p->token = tp+text_size+1; + } + memcpy (tp, text, text_size); + p->text = tp; + if (!list) { + p->last = p; + return p; + } + list->last->next = p; + list->last = p; + return list; +} + +void cb_free_replace( void ) +{ + current_replace_list = NULL; + base_replace_list = NULL; + save_current_replace = NULL; + text_queue = NULL; +} + +struct cb_replace_list *cb_get_copy_replacing_list (void) +{ + return current_replace_list; +} + +void cb_set_copy_replacing_list (struct cb_replace_list *list) +{ + current_replace_list = list; +} + +void +cb_ppecho_copy_replace (const char *text, const char *token) +{ + /* performance note (last verified with GnuCOBOL 2.2): + while this function used 5% (according to callgrind) + of the complete time spent in a sample run with + -fsyntax-only on 880 production code files (2,500,000 LOC), + 3.8% of this time is spent in fwrite, therefore not much potential + for optimization */ + + struct cb_replace_list *save_ptr; + struct cb_token_list *save_ptr_text_queue; + int status, save_status; + +#if 0 /* Simon: disabled until found necessary, as this takes together with frwite + a big part of the parsing phase of cobc, increasing the IO cost by numbers */ + /* ensure nothing is in the stream buffer */ + fflush (ppout); +#endif + + if (text_queue == NULL && (text[0] == ' ' || text[0] == '\n')) { + cb_ppecho_direct (text, token); + return; + } + if (!current_replace_list && !base_replace_list) { + /* Output queue */ + for (; text_queue; text_queue = text_queue->next) { + cb_ppecho_direct(text_queue->text, text_queue->token); + } + cb_ppecho_direct(text, token); + return; + } + if (!current_replace_list) { + current_replace_list = base_replace_list; + save_ptr = NULL; + } else { + current_replace_list->last->next = base_replace_list; + save_ptr = current_replace_list->last; + } + + /* Do replacement */ + text_queue = pp_token_list_add (text_queue, text, token); + + save_ptr_text_queue = text_queue; + status = ppecho_replace (save_ptr); + /* Search another replacement when have a Partial Match in the last ppecho call */ + if (check_partial_match && status != -1) { + save_status = status; + text_queue = save_ptr_text_queue; + while (text_queue && check_partial_match) { + if (is_space_or_nl (text_queue->text[0])) { + cb_ppecho_direct (text_queue->text, + text_queue->token); + text_queue = text_queue->next; + continue; + } + status = ppecho_replace (save_ptr); + if (status > save_status) { + save_status = status; + } + if (text_queue) { + /* Write text_queue if is not replaced */ + if (status != -1 && check_partial_match) { + cb_ppecho_direct (text_queue->text, + text_queue->token); + } + text_queue = text_queue->next; + } + } + status = save_status; + } + /* Manage Partial Match */ + if (status == -1) { + check_partial_match = save_ptr_text_queue != NULL; + return; + } + if (!status) { + current_replace_list = NULL; + } else { + save_ptr->next = NULL; + } + + /* No match */ + for (; text_queue; text_queue = text_queue->next) { + cb_ppecho_direct (text_queue->text, text_queue->token); + } +} + +/* handle all kinds of COPY REPLACING and REPLACE */ +static int +ppecho_replace (struct cb_replace_list *save_ptr) +{ + char *temp_ptr; + size_t size; + size_t size2; + struct cb_token_list *queue; + struct cb_token_list *save_queue; + const struct cb_text_list *lno; + struct cb_replace_list *r; + + save_queue = NULL; + size = 0; + size2 = 0; + for (r = current_replace_list; r; r = r->next) { + queue = text_queue; + /* The LEADING/TRAILING code looks peculiar as we use */ + /* variables after breaking out of the loop BUT */ + /* ppparse.y guarantees that we have only one token */ + /* and therefore only one iteration of this loop */ + for (lno = r->src->text_list; lno; lno = lno->next) { + if (is_space_or_nl (lno->text[0])) { + continue; + } + while (queue && is_space_or_nl (queue->text[0])) { + queue = queue->next; + } + if (queue == NULL) { + /* Partial match */ + if (!save_ptr) { + current_replace_list = NULL; + } else { + save_ptr->next = NULL; + } + return -1; + } + if (r->src->lead_trail == CB_REPLACE_LEADING) { + /* Check leading text */ + size = strlen (lno->text); + if ((r->src->strict && strlen (queue->text) == size) + || strncasecmp (lno->text, queue->text, size)) { + /* No match */ + break; + } + save_queue = queue; + } else if (r->src->lead_trail == CB_REPLACE_TRAILING) { + /* Check trailing text */ + size = strlen (lno->text); + size2 = strlen (queue->text); + if (size2 < size + || (r->src->strict && size2 == size)) { + /* No match */ + break; + } + size2 -= size; + if (strncasecmp (lno->text, queue->text + size2, size)) { + /* No match */ + break; + } + save_queue = queue; + } else if (strcasecmp (lno->text, queue->text)) { + /* No match */ + break; + } + queue = queue->next; + } + if (lno == NULL) { + /* Match */ + if (r->src->lead_trail == CB_REPLACE_TRAILING + && save_queue /* <- silence warnings */) { + /* Non-matched part of original text */ + temp_ptr = cobc_strdup (save_queue->text); + *(temp_ptr + size2) = 0; + cb_ppecho_direct (temp_ptr, NULL); + cobc_free (temp_ptr); + } + for (lno = r->new_text; lno; lno = lno->next) { + cb_ppecho_direct (lno->text, NULL); + } + if (r->src->lead_trail == CB_REPLACE_LEADING + && save_queue /* <- silence warnings */) { + /* Non-matched part of original text */ + cb_ppecho_direct (save_queue->text + size, NULL); + } + check_partial_match = 0; + text_queue = queue; + continue; + } + } + return (save_ptr ? 1 : 0); +} + + +void +cb_set_replace_list (struct cb_replace_list *list, const int is_pushpop) +{ + /* Handle REPLACE verb */ + if (!list) { + /* REPLACE [LAST] OFF */ + if (!is_pushpop) { + base_replace_list = NULL; + return; + } + if (!base_replace_list) { + return; + } + base_replace_list = base_replace_list->prev; + return; + } + /* REPLACE [ALSO] ... */ + if (base_replace_list && is_pushpop) { + list->last->next = base_replace_list; + list->prev = base_replace_list; + } else { + list->prev = NULL; + } + base_replace_list = list; + if (cb_src_list_file) { + cb_set_print_replace_list (list); + } +} diff --git a/cobc/replace.h b/cobc/replace.h new file mode 100644 index 000000000..25d02c78d --- /dev/null +++ b/cobc/replace.h @@ -0,0 +1,45 @@ +/* + Copyright (C) 2023-2023 Free Software Foundation, Inc. + Written by Fabrice Le Fessant + + This file is part of GnuCOBOL. + + The GnuCOBOL compiler is free software: you can redistribute it + and/or modify it under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + GnuCOBOL is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GnuCOBOL. If not, see . +*/ + +#ifndef CB_REPLACE_H +#define CB_REPLACE_H + +// defined in pplex.l +extern void cb_ppecho_direct (const char *text, const char *token ); +extern struct cb_text_list *cb_pp_text_list_add (struct cb_text_list *, + const char *, const size_t); + +extern void cb_ppecho_copy_replace (const char *text, const char *token ); +extern void cb_free_replace (void); + +/* For COPY-REPLACING */ +extern void cb_set_copy_replacing_list (struct cb_replace_list *list); +extern struct cb_replace_list * cb_get_copy_replacing_list (void); + +extern void +cb_set_print_replace_list (struct cb_replace_list *); + +static COB_INLINE COB_A_INLINE int +is_space_or_nl (const char c) +{ + return c == ' ' || c == '\n'; +} + +#endif // CB_REPLACE_H diff --git a/cobc/tree.h b/cobc/tree.h index df31751a5..829726890 100644 --- a/cobc/tree.h +++ b/cobc/tree.h @@ -1643,8 +1643,8 @@ struct cb_replace_list { const struct cb_text_list *new_text; }; -extern void pp_set_replace_list (struct cb_replace_list *, - const cob_u32_t); +extern void cb_set_replace_list (struct cb_replace_list *, + const int); /* List of error messages */ struct list_error {