Skip to content

Commit 08e9df2

Browse files
author
James K. Lowden
committed
cobol: Introduce vendor-compatibility layer as user-defined functions.
Install COBOL UDFs in a target directory that includes the GCC version in its path, to permit side-by-side installation. Support compat library with COBOL POSIX bindings; support those binding with C functions in libgcobol as needed. Changes to the compiler to support POSIX binding and testing. Include developer conveniences -- Makefiles, bin/ and t/ directories -- to ensure UDFs compile and return reasonable results. These are not installed and do not affect how libgcobol is built. gcc/cobol/ChangeLog: * cdf.y: Install literals in symbol table. * genapi.cc (parser_alphabet): Use std::string for currency. (initialize_the_data): Rely on constructor. (parser_file_add): Better #pragma message. (parser_exception_file): Return early if not generating code. * parse.y: Allow library programs to act as functions. * parse_ante.h (dialect_proscribed): Standardize message. (intrinsic_call_2): Correct s/fund/func/ misspelling. * scan.l: Comment. * symbols.cc (symbols_update): Add unreachable assertion. (symbol_field_parent_set): Reduce error to debug message. (cdf_literalize): Declare. (symbol_table_init): Insert CDF constants as literals. * symbols.h (cbl_dialect_str): Provide string values for enum. (is_working_storage): Remove function. (struct cbl_field_data_t): Add manhandle_initial for Numeric Edited. (struct cbl_field_t): Initialize name to zeros. (struct cbl_section_t): Delete unused attr() function. (symbol_unique_index): Declare. * token_names.h: Regenerate. * util.cc (cdf_literalize): Construct a cbl_field_t from a CDF literal. (symbol_unique_index): Supply "globally" unique number for a program. libgcobol/ChangeLog: * Makefile.am: Move UDF-support to posix/shim, add install targets * Makefile.in: Regenerate * charmaps.cc (__gg__currency_signs): Use std::string. * charmaps.h: Include string and vector headers. (class charmap_t): Use std::string and vector for currency. * config.h.in: Regenerate. * configure: Regenerate. * configure.ac: Check for libxml2. * intrinsic.cc (numval_c): Constify. * libgcobol.cc (struct program_state): Use std::string and vector. (__gg__inspect_format_2): Add debug messages. * libgcobol.h (__gg__get_default_currency_string): Constify. * valconv.cc (expand_picture): Use std::string and vector. (__gg__string_to_numeric_edited): Use std::string and vector. (__gg__currency_sign_init): Use std::string and vector. (__gg__currency_sign): Use std::string and vector. * xmlparse.cc (xml_push_parse): Reformat. * posix/stat.cc: Removed. * posix/stat.h: Removed. * .gitignore: New file. * compat/README.md: New file. * compat/lib/gnu/CBL_ALLOC_MEM.cbl: New file. * compat/lib/gnu/CBL_CHECK_FILE_EXIST.cbl: New file. * compat/lib/gnu/CBL_DELETE_FILE.cbl: New file. * compat/lib/gnu/CBL_FREE_MEM.cbl: New file. * compat/t/Makefile: New file. * compat/t/smoke.cbl: New file. * posix/README.md: New file. * posix/bin/Makefile: New file for UDF-developer. * posix/bin/headers: New file. * posix/bin/scrape.awk: New file. * posix/bin/sizeofs.c: New file. * posix/bin/udf-gen: New file. * posix/cpy/posix-errno.cbl: New file. * posix/cpy/statbuf.cpy: New file. * posix/cpy/tm.cpy: New file. * posix/errno.cc: Removed. * posix/localtime.cc: Removed. * posix/shim/stat.cc: New file. * posix/shim/stat.h: New file. * posix/t/Makefile: New file. * posix/t/errno.cbl: New file. * posix/t/exit.cbl: New file. * posix/t/localtime.cbl: New file. * posix/t/stat.cbl: New file. * posix/tm.h: Removed. * posix/udf/posix-exit.cbl: New file. * posix/udf/posix-localtime.cbl: New file. * posix/udf/posix-mkdir.cbl: New file. * posix/udf/posix-stat.cbl: New file. * posix/udf/posix-unlink.cbl: New file.
1 parent a784ed8 commit 08e9df2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+2211
-657
lines changed

gcc/cobol/cdf.y

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,9 @@ void input_file_status_notify();
151151
cdfval_t operator/( const cdfval_base_t& lhs, const cdfval_base_t& rhs );
152152
cdfval_t negate( cdfval_base_t lhs );
153153

154+
cbl_field_t
155+
cdf_literalize( const std::string& name, const cdfval_t& value );
156+
154157
}
155158

156159
%{
@@ -353,6 +356,11 @@ cdf_define: CDF_DEFINE cdf_constant NAME as cdf_expr[value] override
353356
}
354357
YYERROR;
355358
}
359+
if( symbols_begin() < symbols_end() ) {
360+
cbl_field_t field = cdf_literalize($NAME, $value);
361+
symbol_field_add(current_program_index(), &field);
362+
}
363+
356364
}
357365
| CDF_DEFINE cdf_constant NAME '=' cdf_expr[value] override
358366
{ /* accept, but as error */
@@ -952,3 +960,5 @@ cdfval_base_t::operator()( const YDFLTYPE& loc ) {
952960
// cppcheck-suppress returnTempReference
953961
return verify_integer(loc, *this) ? *this : zero;
954962
}
963+
964+

gcc/cobol/genapi.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5145,8 +5145,8 @@ parser_alphabet( const cbl_alphabet_t& alphabet )
51455145

51465146
case custom_encoding_e:
51475147
{
5148-
#pragma message "Use program-id to disambiguate"
5149-
size_t alphabet_index = symbol_index(symbol_elem_of(&alphabet));
5148+
#pragma message "Verify program-id is disambiguated"
5149+
size_t alphabet_index = symbol_unique_index(symbol_elem_of(&alphabet));
51505150

51515151
unsigned char ach[256];
51525152

@@ -7166,7 +7166,6 @@ initialize_the_data()
71667166
build_int_cst_type(INT, current_encoding(national_encoding_e)),
71677167
NULL_TREE);
71687168

7169-
__gg__currency_signs = __gg__ct_currency_signs;
71707169
// We initialize currency both at compile time and run time
71717170
__gg__currency_sign_init();
71727171
gg_call(VOID,
@@ -9911,8 +9910,8 @@ parser_file_add(struct cbl_file_t *file)
99119910
__func__);
99129911
}
99139912

9914-
#pragma message "Use program-id to disambiguate"
9915-
size_t symbol_table_index = symbol_index(symbol_elem_of(file));
9913+
#pragma message "Verify program-id is disambiguated"
9914+
size_t symbol_table_index = symbol_unique_index(symbol_elem_of(file));
99169915

99179916
gg_call(VOID,
99189917
"__gg__file_init",
@@ -14608,6 +14607,7 @@ void
1460814607
parser_exception_file( cbl_field_t *tgt, cbl_file_t *file)
1460914608
{
1461014609
Analyze();
14610+
RETURN_IF_PARSE_ONLY;
1461114611
gg_call(VOID,
1461214612
"__gg__func_exception_file",
1461314613
gg_get_address_of(tgt->var_decl_node),

gcc/cobol/parse.y

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2397,7 +2397,7 @@ config_paragraph:
23972397
| SOURCE_COMPUTER '.' NAME '.'
23982398
| SOURCE_COMPUTER '.' NAME with_debug '.'
23992399
| OBJECT_COMPUTER '.'
2400-
| OBJECT_COMPUTER '.' NAME[computer] collations '.'
2400+
| OBJECT_COMPUTER '.' NAME[computer] object_computer '.'
24012401
| REPOSITORY dot
24022402
| REPOSITORY dot repo_members '.'
24032403
;
@@ -2528,7 +2528,7 @@ with_debug: with DEBUGGING MODE {
25282528
}
25292529
;
25302530

2531-
collations: %empty
2531+
object_computer: %empty
25322532
| char_classification
25332533
| collating_sequence
25342534
| char_classification collating_sequence
@@ -4842,13 +4842,15 @@ value_clause: VALUE all LITERAL[lit] {
48424842
}
48434843
if( $value != NULLS ) {
48444844
auto fig = constant_of(constant_index($value));
4845-
current_field()->data.initial = fig->data.initial;
4845+
cbl_field_t *field = current_field();
4846+
field->data.initial = fig->data.initial;
48464847
}
48474848
}
48484849
| /* VALUE is */ NULLPTR
48494850
{
48504851
auto fig = constant_of(constant_index(NULLS));
4851-
current_field()->data.initial = fig->data.initial;
4852+
cbl_field_t *field = current_field();
4853+
field->data.initial = fig->data.initial;
48524854
}
48534855
| VALUE error
48544856
{
@@ -4938,10 +4940,13 @@ any_length: ANY LENGTH
49384940
if( field->attr & any_length_e ) {
49394941
error_msg(@1, "ANY LENGTH already set");
49404942
}
4943+
const char *prog_name = current.program()->name;
4944+
bool is_compat = 0 < compat_programs.count(prog_name);
49414945
if( ! (field->level == 1 &&
49424946
current_data_section == linkage_datasect_e &&
49434947
(1 < current.program_level() ||
4944-
current.program()->is_function())) ) {
4948+
current.program()->is_function() ||
4949+
is_compat)) ) {
49454950
error_msg(@1, "ANY LENGTH valid only for 01 "
49464951
"in LINKAGE SECTION of a function or contained program");
49474952
YYERROR;
@@ -10338,11 +10343,13 @@ go_to: GOTO labels[args]
1033810343
resume: RESUME NEXT STATEMENT
1033910344
{
1034010345
statement_begin(@1, RESUME);
10346+
if( dialect_proscribed( @1, dialect_ibm_e, "RESUME") ) YYERROR;
1034110347
parser_clear_exception();
1034210348
}
1034310349
| RESUME label_1[tgt]
1034410350
{
1034510351
statement_begin(@1, RESUME);
10352+
if( dialect_proscribed( @1, dialect_ibm_e, "RESUME") ) YYERROR;
1034610353
parser_clear_exception();
1034710354
$tgt->used = @1.first_line;
1034810355
parser_goto( cbl_refer_t(), 1, &$tgt );
@@ -10708,11 +10715,10 @@ function_udf: FUNCTION_UDF '(' arg_list[args] ')' {
1070810715
const auto returning = cbl_field_of(symbol_at(L->returning));
1070910716
$$ = new_temporary_clone(returning);
1071010717
$$->data.initial = returning->name; // user's name for the field
10711-
cbl_field_attr_t call_attr
10712-
= (cbl_field_attr_t)(quoted_e|hex_encoded_e);
10713-
cbl_field_t *name = new_literal(strlen(L->name),
10714-
L->name,
10715-
call_attr);
10718+
10719+
// Pretend hex-encoded because that means use verbatim.
10720+
auto attr = cbl_field_attr_t(quoted_e | hex_encoded_e);
10721+
auto name = new_literal(strlen(L->name), L->name, attr);
1071610722
ast_call( @1, name, $$, narg, args, NULL, NULL, true );
1071710723
}
1071810724
;
@@ -12083,6 +12089,7 @@ void ast_call( const YYLTYPE& loc, cbl_refer_t name, const cbl_refer_t& returnin
1208312089
name.field->data, 77 };
1208412090
called.attr |= name.field->attr;
1208512091
snprintf(called.name, sizeof(called.name), "_%s", name.field->data.initial);
12092+
called.attr |= name.field->attr;
1208612093
name.field = cbl_field_of(symbol_field_add(PROGRAM, &called));
1208712094
symbol_field_location(field_index(name.field), loc);
1208812095
parser_symbol_add(name.field);

gcc/cobol/parse_ante.h

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,15 @@ extern int yydebug;
111111

112112
#include <cstdarg>
113113

114+
// These programs in libgcobol/compat are allowed to use ANY LENGTH even though
115+
// they look like top-level programs.
116+
static const std::set<std::string> compat_programs {
117+
"CBL_ALLOC_MEM",
118+
"CBL_CHECK_FILE_EXIST",
119+
"CBL_DELETE_FILE",
120+
"CBL_FREE_MEM",
121+
};
122+
114123
const char *
115124
consistent_encoding_check( const YYLTYPE& loc, const char input[] ) {
116125
cbl_field_t faux = {};
@@ -180,6 +189,15 @@ has_clause( int data_clauses, data_clause_t clause ) {
180189
return clause == (data_clauses & clause);
181190
}
182191

192+
static bool
193+
dialect_proscribed( const YYLTYPE& loc, cbl_dialect_t dialect, const char msg[] ) {
194+
if( dialect == cbl_dialects ) {
195+
error_msg(loc, "dialect %s does not allow syntax: %qs",
196+
cbl_dialect_str(dialect), msg);
197+
return true;
198+
}
199+
return false;
200+
}
183201

184202
static bool
185203
is_cobol_charset( const char name[] ) {
@@ -2521,9 +2539,9 @@ intrinsic_call_2( cbl_field_t *tgt, int token, const cbl_refer_t *r1, cbl_refer_
25212539
error_msg(args[n].loc, "invalid parameter '%s'", args[n].field->name);
25222540
return false;
25232541
}
2524-
const char *fund = intrinsic_cname(token);
2525-
if( !fund ) return false;
2526-
parser_intrinsic_call_2( tgt, fund, args[0], args[1] );
2542+
const char *func = intrinsic_cname(token);
2543+
if( !func ) return false;
2544+
parser_intrinsic_call_2( tgt, func, args[0], args[1] );
25272545
return true;
25282546
}
25292547

gcc/cobol/scan.l

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -572,7 +572,7 @@ REVERSED { return REVERSED; }
572572
RETURN { return RETURN; }
573573
RESTRICTED { return RESTRICTED; }
574574

575-
RESUME {
575+
RESUME { // RESUME is ISO syntax, not IBM.
576576
if( ! dialect_ibm() ) return RESUME;
577577
yylval.string = xstrdup(yytext);
578578
return typed_name(yytext);

gcc/cobol/symbols.cc

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1862,6 +1862,7 @@ symbols_update( size_t first, bool parsed_ok ) {
18621862
__func__,
18631863
3 + cbl_field_type_str(field->type),
18641864
(fmt_size_t)isym, field->name, field->data.capacity);
1865+
gcc_unreachable();
18651866
}
18661867
}
18671868
return 0;
@@ -2187,12 +2188,9 @@ symbol_field_parent_set( cbl_field_t *field )
21872188
return NULL;
21882189
}
21892190
prior->type = FldGroup;
2190-
prior->codeset.set();
2191-
//// if( ! prior->codeset.set() ) { // maybe just ignore?
2192-
//// Dubner sez: Ignore. This was triggering with -finternal-ebcdic
2193-
//// ERROR_FIELD(prior, "%qs is already National", prior->name);
2194-
//// return NULL;
2195-
//// }
2191+
if( ! prior->codeset.set() ) { // needs attention
2192+
dbgmsg("'%s' is already National", prior->name);
2193+
}
21962194
field->attr |= numeric_group_attrs(prior);
21972195
}
21982196
// verify level 88 domain value
@@ -2250,6 +2248,8 @@ add_token( symbol_elem_t sym ) {
22502248
return sym;
22512249
}
22522250

2251+
const std::list<cbl_field_t> cdf_literalize();
2252+
22532253
/*
22542254
* When adding special registers, be sure to create the actual cblc_field_t
22552255
* in libgcobol/constants.cc.
@@ -2455,6 +2455,14 @@ symbol_table_init(void) {
24552455
table.nelem = p - table.elems;
24562456
assert(table.nelem < table.capacity);
24572457

2458+
// Add any CDF values already defined as literals.
2459+
// After symbols are ready, the CDF adds them directly.
2460+
const std::list<cbl_field_t> cdf_values = cdf_literalize();
2461+
table.nelem += cdf_values.size();
2462+
assert(table.nelem < table.capacity);
2463+
2464+
p = std::transform(cdf_values.begin(), cdf_values.end(), p, elementize);
2465+
24582466
// Initialize symbol table.
24592467
symbols = table;
24602468

gcc/cobol/symbols.h

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,17 @@ enum cbl_dialect_t {
5757
dialect_gnu_e = 0x04,
5858
};
5959

60+
static inline const char *
61+
cbl_dialect_str(cbl_dialect_t dialect) {
62+
switch(dialect) {
63+
case dialect_gcc_e: return "gcc";
64+
case dialect_ibm_e: return "ibm";
65+
case dialect_mf_e: return "mf";
66+
case dialect_gnu_e: return "gnu";
67+
}
68+
return "???";
69+
};
70+
6071
// Dialects may be combined.
6172
extern unsigned int cbl_dialects;
6273
void cobol_dialect_set( cbl_dialect_t dialect );
@@ -143,11 +154,6 @@ const char * cbl_field_attr_str( cbl_field_attr_t attr );
143154

144155
cbl_field_attr_t literal_attr( const char prefix[] );
145156

146-
static inline bool
147-
is_working_storage(uint32_t attr) {
148-
return 0 == (attr & (linkage_e | local_e));
149-
}
150-
151157
int cbl_figconst_tok( const char *value );
152158
enum cbl_figconst_t cbl_figconst_of( const char *value );
153159
const char * cbl_figconst_str( cbl_figconst_t fig );
@@ -391,6 +397,26 @@ struct cbl_field_data_t {
391397
return valify();
392398
}
393399

400+
// If initial (of Numeric Edited) has any length but capacity, adjust it.
401+
bool manhandle_initial() {
402+
assert(capacity > 0);
403+
assert(initial != nullptr);
404+
if( capacity < strlen(initial) ) {
405+
char *p = const_cast<char*>(initial);
406+
p[capacity] = '\0';
407+
return true;
408+
}
409+
if( strlen(initial) < capacity ) {
410+
auto tgt = reinterpret_cast<char *>( xmalloc(capacity + 1) );
411+
auto pend = tgt + capacity;
412+
auto p = std::copy(initial, initial + strlen(initial), tgt);
413+
std::fill(p, pend, 0x20);
414+
p = pend - 1;
415+
*p = '\0';
416+
initial = tgt;
417+
}
418+
return false;
419+
}
394420
bool initial_within_capacity() const {
395421
return initial[capacity] == '\0'
396422
|| initial[capacity] == '!';
@@ -630,7 +656,7 @@ struct cbl_field_t {
630656
uint32_t level = 0, const cbl_name_t name = "", int line = 0 )
631657
: offset(0), type(type), usage(FldInvalid), attr(attr)
632658
, parent(0), our_index(0), level(level)
633-
, line(line), file(0), data(data)
659+
, line(line), name(""), file(0), data(data)
634660
, var_decl_node(nullptr), data_decl_node(nullptr)
635661
{
636662
gcc_assert(strlen(name) < sizeof this->name);
@@ -1539,15 +1565,6 @@ struct cbl_section_t {
15391565
}
15401566
gcc_unreachable();
15411567
}
1542-
uint32_t attr() const {
1543-
switch(type) {
1544-
case file_sect_e:
1545-
case working_sect_e: return 0;
1546-
case linkage_sect_e: return linkage_e;
1547-
case local_sect_e: return local_e;
1548-
}
1549-
gcc_unreachable();
1550-
}
15511568
};
15521569

15531570
struct cbl_locale_t {
@@ -2273,6 +2290,8 @@ struct cbl_until_addresses_t {
22732290

22742291
size_t symbol_index(); // nth after first program symbol
22752292
size_t symbol_index( const symbol_elem_t *e );
2293+
size_t symbol_unique_index( const struct symbol_elem_t *e );
2294+
22762295
struct symbol_elem_t * symbol_at( size_t index );
22772296

22782297
struct cbl_options_t {

0 commit comments

Comments
 (0)