diff --git a/gcc/cobol/parse.y b/gcc/cobol/parse.y index c7851ba1a361f903d55c4795c184239aa90154d4..e3380a01caa9bc1d0bba62acdba579217b596546 100644 --- a/gcc/cobol/parse.y +++ b/gcc/cobol/parse.y @@ -306,6 +306,8 @@ // https://savannah.gnu.org/forum/forum.php?forum_id=9735 %token YYEOF 0 "end of file" +%type <number> sentence sentences statements statement + %type <number> star_cbl_opt close_how %type <number> test_before usage_clause1 might_be @@ -784,36 +786,7 @@ %precedence NEG %right POW -%{ -const char * keyword_str( int token ); - -static YYLTYPE current_location; - -const YYLTYPE& cobol_location() { return current_location; } - -static void -location_set( const YYLTYPE& loc ) { - current_location = loc; -} -static int prior_statement; - -static void -statement_begin( const YYLTYPE& loc, int token ) { - // The following statement generates a message at run-time - // parser_print_string("statement_begin()\n"); - location_set(loc); - prior_statement = token; - - if( enabled_exceptions.size() ) { - current.declaratives_evaluate(ec_none_e); - cbl_enabled_exceptions_array_t enabled(enabled_exceptions); - parser_exception_prepare( keyword_str(token), &enabled ); - } - if( getenv(__func__) ) symbol_temporaries_free(); -} - -%} %{ static cbl_field_type_t @@ -4010,8 +3983,14 @@ declaratives: %empty { $$ = NULL; } } ; -sentences: sentence - | sentences sentence +sentences: sentence { + if( $1 != PARAGRAPH ) + symbol_temporaries_free(); + } + | sentences sentence { + if( $1 != PARAGRAPH ) + symbol_temporaries_free(); + } ; sentence: statements '.' @@ -4057,7 +4036,7 @@ sentence: statements '.' ; statements: statement - | statements statement + | statements statement { $$ = $2; } ; statement: error { @@ -4070,49 +4049,49 @@ statement: error { YYABORT; } } - | cdf - | accept - | add - | allocate - | alter - | call - | cancel - | close - | compute - | CONTINUE - | delete - | display - | divide - | entry - | evaluate - | exit - | free - | go_to - | if_stmt - | initialize - | inspect - | merge - | move - | multiply - | open - | return_stmt - | paragraph - | perform - | raise - | read - | release - | resume - | rewrite - | search - | section - | set - | sort - | start - | stop - | string - | subtract - | unstring - | write + | cdf { $$ = CDF_IF; } + | accept { $$ = ACCEPT; } + | add { $$ = ADD; } + | allocate { $$ = ALLOCATE; } + | alter { $$ = ALTER; } + | call { $$ = CALL; } + | cancel { $$ = CANCEL; } + | close { $$ = CLOSE; } + | compute { $$ = COMPUTE; } + | CONTINUE { $$ = CONTINUE; } + | delete { $$ = DELETE; } + | display { $$ = DISPLAY; } + | divide { $$ = DIVIDE; } + | entry { $$ = ENTRY; } + | evaluate { $$ = EVALUATE; } + | exit { $$ = EXIT; } + | free { $$ = FREE; } + | go_to { $$ = GOTO; } + | if_stmt { $$ = IF; } + | initialize { $$ = INITIALIZE; } + | inspect { $$ = INSPECT; } + | merge { $$ = MERGE; } + | move { $$ = MOVE; } + | multiply { $$ = MULTIPLY; } + | open { $$ = OPEN; } + | return_stmt { $$ = RETURN; } + | paragraph { $$ = PARAGRAPH; } + | perform { $$ = PERFORM; } + | raise { $$ = RAISE; } + | read { $$ = READ; } + | release { $$ = RELEASE; } + | resume { $$ = RESUME; } + | rewrite { $$ = REWRITE; } + | search { $$ = SEARCH; } + | section { $$ = SECTION; } + | set { $$ = SET; } + | sort { $$ = SORT; } + | start { $$ = START; } + | stop { $$ = STOP; } + | string { $$ = STRING_kw; } + | subtract { $$ = SUBTRACT; } + | unstring { $$ = UNSTRING; } + | write { $$ = WRITE; } ; accept: accept_body end_accept @@ -6328,11 +6307,6 @@ subtract_impl: SUBTRACT subtract_body[body] statement_begin(@1, SUBTRACT); $$ = $body; } - | SUBTRACT subtract_body[body] END_SUBTRACT - { - statement_begin(@1, SUBTRACT); - $$ = $body; - } ; subtract_cond: SUBTRACT subtract_body[body] arith_errs[err] { diff --git a/gcc/cobol/parse_ante.h b/gcc/cobol/parse_ante.h index 70eacc18dbe31cc9bda04549c8a80f23cb37a07d..ca292b322d85caa8f50494f30922a9192ea00df1 100644 --- a/gcc/cobol/parse_ante.h +++ b/gcc/cobol/parse_ante.h @@ -2971,3 +2971,32 @@ goodnight_gracie() { return true; } +const char * keyword_str( int token ); + +static YYLTYPE current_location; + +const YYLTYPE& cobol_location() { return current_location; } + +static void +location_set( const YYLTYPE& loc ) { + current_location = loc; +} + +static int prior_statement; + +static size_t + statement_begin( const YYLTYPE& loc, int token ) { + // The following statement generates a message at run-time + // parser_print_string("statement_begin()\n"); + location_set(loc); + prior_statement = token; + + if( enabled_exceptions.size() ) { + current.declaratives_evaluate(ec_none_e); + cbl_enabled_exceptions_array_t enabled(enabled_exceptions); + parser_exception_prepare( keyword_str(token), &enabled ); + } + if( getenv(__func__) ) symbol_temporaries_free(); + return 0; +} + diff --git a/gcc/cobol/symbols.cc b/gcc/cobol/symbols.cc index 7a94b0d245b8f20554d1d34715a1b0fe25ea6151..a09f4c011988e1d478c84c3cd6b3fb1277a19016 100644 --- a/gcc/cobol/symbols.cc +++ b/gcc/cobol/symbols.cc @@ -3090,13 +3090,40 @@ temporaries_t::acquire( cbl_field_type_t type ) { return field; } +size_t +temporaries_t::keep() { + keepers.push(used); + used.clear(); + return keepers.size(); +} + +void +temporaries_t::release( size_t keeper ) { + if( keepers.size() != keeper ) { + warnx("%s: logic error: releasing %zu of %zu kept temporaries:", + __func__, keeper, keepers.size() ); + } + assert( ! keepers.empty() ); + assert( keepers.size() == keeper ); + fieldmap_t& used( keepers.top() ); + + for( auto& elem : used ) { + const cbl_field_type_t& type(elem.first); + temporaries_t::fieldset_t& used(elem.second); + + auto freer = std::inserter(freed[type], + freed[type].begin()); + std::copy( used.begin(), used.end(), freer ); + } + keepers.pop(); +} + void symbol_temporaries_free() { for( auto& elem : temporaries.used ) { const cbl_field_type_t& type(elem.first); temporaries_t::fieldset_t& used(elem.second); - if( type == FldConditional ) continue; - + auto freed = std::inserter(temporaries.freed[type], temporaries.freed[type].begin()); std::copy( used.begin(), used.end(), freed ); @@ -3104,16 +3131,15 @@ symbol_temporaries_free() { } } -#if 0 +size_t +symbol_temporaries_push() { + return temporaries.keep(); +} + void -temporaries_t::release( cbl_field_type_t type ) { - fieldset_t& used[type]; - auto freed = std::inserter(freed[type], - freed[type].begin()); - std::copy( used.begin(), used.end(), freed ); - used.clear(); +symbol_temporaries_pop( size_t kept ) { + return temporaries.release( kept ); } -#endif cbl_field_t * new_temporary( enum cbl_field_type_t type ) { diff --git a/gcc/cobol/symbols.h b/gcc/cobol/symbols.h index 5f4b5a56b879b98180b12b314e7f3f678afd0916..ed4263e3b55350155a0f799b80a440f8aa44cb57 100644 --- a/gcc/cobol/symbols.h +++ b/gcc/cobol/symbols.h @@ -41,6 +41,7 @@ #include <list> #include <map> #include <set> +#include <stack> #include <string> #define COUNT_OF(X) (sizeof(X) / sizeof(X[0])) @@ -1217,14 +1218,20 @@ class temporaries_t { std::map<literal_an, cbl_field_t *> literals; typedef std::set<cbl_field_t *> fieldset_t; - std::map<cbl_field_type_t, fieldset_t> used, freed; + typedef std::map<cbl_field_type_t, fieldset_t> fieldmap_t; + fieldmap_t used, freed; + std::stack<fieldmap_t> keepers; public: cbl_field_t * literal( const char value[], uint32_t len, cbl_field_attr_t attr = none_e ); cbl_field_t * acquire( cbl_field_type_t type ); + size_t keep(); + void release( size_t kept); void add( cbl_field_t *field ); }; +size_t symbol_temporaries_push(); +void symbol_temporaries_pop( size_t kept ); static inline bool is_table( const cbl_field_t *field ) { return field && field->occurs.ntimes() > 0;