gcc/libgcobol/common-defs.h
James K. Lowden a075418727 COBOL: libgcobol
libgcobol/
	* Makefile.am: New file.
	* Makefile.in: Autogenerate.
	* acinclude.m4: Likewise.
	* aclocal.m4: Likewise.
	* configure.ac: New file.
	* configure: Autogenerate.
	* configure.tgt: New file.
	* README: New file.
	* charmaps.cc: New file.
	* config.h.in: New file.
	* constants.cc: New file.
	* gfileio.cc: New file.
	* gmath.cc: New file.
	* io.cc: New file.
	* valconv.cc: New file.
	* charmaps.h: New file.
	* common-defs.h: New file.
	* ec.h: New file.
	* exceptl.h: New file.
	* gcobolio.h: New file.
	* gfileio.h: New file.
	* gmath.h: New file.
	* io.h: New file.
	* libgcobol.h: New file.
	* valconv.h: New file.
	* libgcobol.cc: New file.
	* intrinsic.cc: New file.
2025-03-11 07:48:15 +01:00

504 lines
16 KiB
C++

/*
* Copyright (c) 2021-2025 Symas Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of the Symas Corporation nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef COMMON_DEFS_H_
#define COMMON_DEFS_H_
#include <stdint.h>
#include <list>
#define COUNT_OF(X) (sizeof(X) / sizeof(X[0]))
// This constant establishes the maximum number of digits in a fixed point
// number. We are using 37 digits as a maximum because a full-size 37-digit
// number (10**37) takes 123 bits, and a full-size 38-digit number (10**38)
// takes 127 bits. By using a maximum of 37, that gives us an additional digit
// of headroom in order to accomplish rounding.
// You should keep in mind that the _Float128 binary floating point numbers that
// we use can reliably reproduce numbers of 33 decimal digits when going to
// binary and back.
#define MAX_FIXED_POINT_DIGITS (37)
// COBOL tables can have up to seven subscripts
#define MAXIMUM_TABLE_DIMENSIONS 7
// This bit gets turned on in the first or last byte (depending on the leading_e attribute
// phrase) of a NumericDisplay to indicate that the value is negative.
// When running the EBCDIC character set, the meaning of this bit is flipped,
// because an EBCDIC zero is 0xF0, while ASCII is 0x30
#define NUMERIC_DISPLAY_SIGN_BIT 0x40
#define LEVEL01 (1)
#define LEVEL49 (49)
#define LEVEL77 (77)
// In the __gg__move_literala() call, we piggyback this bit onto the
// cbl_round_t parameter, just to cut down on the number of parameters passed
#define REFER_ALL_BIT 0x80
/*
* User-defined names in IBM COBOL can have at most 30 characters.
* For DBCS, the maximum is 14.
*
* Per ISO/IEC 1989:2023(E), 8.3.2 COBOL words,
* "A COBOL word is a character-string of not more than 63 characters"
*/
typedef char cbl_name_t[64];
// Note that the field_type enum is duplicated in the source code for the
// COBOL-aware GDB, and so any changes here (or there) have to be reflected
// there (or here)
// Note further that if this list changes, then the valid_move() matrix has to
// change as will. Currently that matrix is in util.cc.
enum cbl_field_type_t {
FldInvalid, // uninitialized
FldGroup,
FldAlphanumeric, // For X(n).
FldNumericBinary, // For 999v9 comp big-endian, 1 to 16 bytes
FldFloat, // 4-, 8-, and 16-byte floating point. See ieeedec_e and big_endian_e flags
FldPacked, // For 999v9 comp-3 internal decimal, packed decimal representation;
FldNumericBin5, // For 999v9 comp-5 little-endian, 1 to 16 bytes. (Native binary)
FldNumericDisplay, // For 999v9 one decimal character per byte
FldNumericEdited, // For 999.9 PIC BPVZ90/,.+-CRDB*cs; must have one of B/Z0,.*+-CRDBcs
FldAlphaEdited, // PIC AX9B0/; must have at least one A or X, and at least one B0/
FldLiteralA, // Alphanumeric literal
FldLiteralN, // Numeric literal
FldClass,
FldConditional, // Target for parser_relop()
FldForward,
FldIndex,
FldSwitch,
FldDisplay,
FldPointer,
FldBlob,
};
/* BINARY, COMP, COMPUTATIONAL, COMP-4, COMPUTATIONAL-4 are the same:
* Storage, by default, is big-endian.
* PIC 9(1 to 4) is 2 bytes
* PIC 9(5 to 9) is 4 bytes
* PIC 9(10 to 18) is 8 bytes
* PIC 9(19-37) is 16 bytes
* COMP-1, COMPUTATIONAL-1
* 4-byte floating point (single)
* COMP-2, COMPUTATIONAL-2
* 8-byte floating point (double)
* PACKED-DECIMAL, COMP-3, COMPUTATIONAL-3
* Packed decimal. Final nybble is 0xF for unsigned numbers. For signable
* values, it is 0xD for negative, and 0xC for non-negative
* COMP-5, COMPUTATIONAL-5
* Native binary. The maximum number of digits is implied by
* the 2, 4, or 8 bytes of data storage. By "native", little-endian
* is implied on Intel processors.
*/
/*
* Enumerated bit mask of variable attributes.
* A field as either left- or right-justified.
* A field is padded (in the unjustified direction) either with 0 or SPC.
* (But maybe the fill character should just be an explicit character.)
*/
enum cbl_field_attr_t : size_t {
none_e = 0x0000000000,
figconst_1_e = 0x0000000001, // This needs to be 1 - don't change the position
figconst_2_e = 0x0000000002, // This needs to be 2
figconst_4_e = 0x0000000004, // This needs to be 4
rjust_e = 0x0000000008, // justify right
ljust_e = 0x0000000010, // justify left
zeros_e = 0x0000000020, // zero fill
signable_e = 0x0000000040,
constant_e = 0x0000000080, // pre-assigned constant
function_e = 0x0000000100,
quoted_e = 0x0000000200,
filler_e = 0x0000000400,
_spare_e = 0x0000000800, //
intermediate_e = 0x0000001000, // Compiler-defined temporary variable
embiggened_e = 0x0000002000, // redefined numeric made 64-bit by USAGE POINTER
all_alpha_e = 0x0000004000, // FldAlphanumeric, but all A's
all_x_e = 0x0000008000, // picture is all X's
all_ax_e = 0x000000a000, // picture is all A's or all X's
prog_ptr_e = 0x0000010000, // FUNCTION-POINTER or PROGRAM-POINTER
scaled_e = 0x0000020000,
refmod_e = 0x0000040000, // Runtime; indicates a refmod is active
based_e = 0x0000080000, // pointer capacity, for ADDRESS OF or ALLOCATE
any_length_e = 0x0000100000, // inferred length of linkage in nested program
global_e = 0x0000200000, // field has global scope
external_e = 0x0000400000, // field has external scope
blank_zero_e = 0x0000800000, // BLANK WHEN ZERO
// data division uses 2 low bits of high byte
linkage_e = 0x0001000000, // field is in linkage section
local_e = 0x0002000000, // field is in local section
leading_e = 0x0004000000, // leading sign (signable_e alone means trailing)
separate_e = 0x0008000000, // separate sign
envar_e = 0x0010000000, // names an environment variable
dnu_1_e = 0x0020000000, // unused: this attribute bit is available
bool_encoded_e = 0x0040000000, // data.initial is a boolean string
hex_encoded_e = 0x0080000000, // data.initial is a hex-encoded string
depends_on_e = 0x0100000000, // A group hierachy contains a DEPENDING_ON
initialized_e = 0x0200000000, // Don't call parser_initialize from parser_symbol_add
has_value_e = 0x0400000000, // Flag to hierarchical descendents to ignore .initial
ieeedec_e = 0x0800000000, // Indicates a FldFloat is IEEE 754 decimal, rather than binary
big_endian_e = 0x1000000000, // Indicates a value is big-endian
same_as_e = 0x2000000000, // Field produced by SAME AS (cannot take new members)
record_key_e = 0x4000000000,
typedef_e = 0x8000000000, // IS TYPEDEF
strongdef_e = typedef_e + intermediate_e, // STRONG TYPEDEF (not temporary)
};
// The separate_e value does double-duty for FldPacked/COMP-6, which is not
// the same as FldPacked COMP-3. A COMP-3 can have signable_e, meaning that the
// final nybble is 0x0D for negative, and 0x0C for non-negative. When a COMP-3
// has no sign, then the final nybble is 0x0F. The packed_no_sign_e bit means
// that there is no sign nybble.
#define packed_no_sign_e separate_e
enum cbl_figconst_t
{
normal_value_e = 0, // This one must be zero
low_value_e = 1, // The order is important, because
null_value_e = 2,
zero_value_e = 3, // at times we compare, for example, low_value_e to
space_value_e = 4,
quote_value_e = 5, //
high_value_e = 6, // high_value_e to determine that low is less than high
};
#define FIGCONST_MASK (figconst_1_e|figconst_2_e|figconst_4_e)
#define DATASECT_MASK (linkage_e | local_e)
enum cbl_file_org_t {
file_disorganized_e,
file_sequential_e,
file_line_sequential_e,
file_indexed_e,
file_relative_e,
};
enum cbl_file_access_t {
file_inaccessible_e,
file_access_seq_e,
file_access_rnd_e,
file_access_dyn_e,
};
enum cbl_file_mode_t {
file_mode_none_e,
file_mode_input_e = 'r',
file_mode_output_e = 'w',
file_mode_extend_e = 'a',
file_mode_io_e = '+',
};
enum cbl_round_t {
away_from_zero_e,
nearest_toward_zero_e,
toward_greater_e,
toward_lesser_e,
nearest_away_from_zero_e,
nearest_even_e,
prohibited_e,
truncation_e,
};
#define RELOP_START 0
enum relop_t {
lt_op = RELOP_START,
le_op,
eq_op,
ne_op,
ge_op,
gt_op,
};
#define LOGOP_START 100
enum logop_t {
not_op = LOGOP_START,
and_op,
or_op,
xor_op,
xnor_op,
true_op,
false_op,
};
#define SETOP_START 200
enum setop_t {
is_op = SETOP_START,
};
enum bitop_t {
bit_set_op, // set bit on
bit_clear_op, // set bit off
bit_on_op, // true if bit is on
bit_off_op, // true if bit is off
bit_and_op,
bit_or_op,
bit_xor_op,
};
enum file_close_how_t {
file_close_no_how_e = 0x00,
file_close_removal_e = 0x01,
file_close_no_rewind_e = 0x02,
file_close_with_lock_e = 0x04,
file_close_reel_unit_e = 0x08,
};
enum cbl_compute_error_code_t {
compute_error_none = 0x0000,
compute_error_truncate = 0x0001,
compute_error_divide_by_zero = 0x0002,
compute_error_exp_zero_by_zero = 0x0004,
compute_error_exp_zero_by_minus = 0x0008,
compute_error_exp_minus_by_frac = 0x0010,
compute_error_overflow = 0x0020,
compute_error_underflow = 0x0040,
};
enum cbl_arith_format_t {
not_expected_e,
no_giving_e, giving_e,
corresponding_e };
enum cbl_encoding_t {
ASCII_e, // STANDARD-1 (in caps to avoid conflict with ascii_e in libgcobol.cc)
iso646_e, // STANDARD-2
EBCDIC_e, // NATIVE or EBCDIC
custom_encoding_e,
};
enum cbl_truncation_mode {
trunc_std_e,
trunc_opt_e,
trunc_bin_e,
};
enum cbl_inspect_bound_t {
bound_characters_e,
bound_all_e,
bound_first_e,
bound_leading_e,
bound_trailing_e,
};
// a SPECIAL-NAME
enum special_name_t {
SYSIN_e, SYSIPT_e, SYSOUT_e,
SYSLIST_e, SYSLST_e,
SYSPUNCH_e, SYSPCH_e,
CONSOLE_e,
C01_e, C02_e, C03_e, C04_e, C05_e, C06_e,
C07_e, C08_e, C09_e, C10_e, C11_e, C12_e,
CSP_e,
S01_e, S02_e, S03_e, S04_e, S05_e,
AFP_5A_e,
STDIN_e, STDOUT_e, STDERR_e, SYSERR_e,
ARG_NUM_e, ARG_VALUE_e, ENV_NAME_e, ENV_VALUE_e,
};
enum classify_t {
ClassInvalidType,
ClassNumericType,
ClassAlphabeticType,
ClassLowerType,
ClassUpperType,
ClassDbcsType,
ClassKanjiType,
};
static inline const char *
classify_str( enum classify_t classify ) {
switch(classify) {
case ClassInvalidType: return "ClassInvalidType";
case ClassNumericType: return "ClassNumericType";
case ClassAlphabeticType: return "ClassAlphabeticType";
case ClassLowerType: return "ClassLowerType";
case ClassUpperType: return "ClassUpperType";
case ClassDbcsType: return "ClassDbcsType";
case ClassKanjiType: return "ClassKanjiType";
};
return "(unknown classification)";
}
static inline const char *
cbl_file_mode_str( cbl_file_mode_t mode ) {
switch(mode) {
case file_mode_none_e: return "file_mode_none_e";
case file_mode_input_e: return "file_mode_input_e: 'r'";
case file_mode_output_e: return "file_mode_output_e: 'w'";
case file_mode_io_e: return "file_mode_io_e: '+'";
case file_mode_extend_e: return "file_mode_extend_e: 'a'";
}
return "???";
};
enum module_type_t {
module_activating_e,
module_current_e,
module_nested_e,
module_stack_e,
module_toplevel_e,
};
static inline bool
ec_cmp( ec_type_t raised, ec_type_t mask )
{
if( raised == mask ) return true;
// Do not match on only the low byte.
if( 0 < (~EC_ALL_E & static_cast<uint32_t>(mask)) ) return false;
return 0 != ( static_cast<uint32_t>(raised)
&
static_cast<uint32_t>(mask) );
}
struct cbl_enabled_exception_t {
bool enabled, location;
ec_type_t ec;
size_t file;
cbl_enabled_exception_t()
: enabled(false)
, location(false)
, ec(ec_none_e)
, file(0)
{}
cbl_enabled_exception_t( bool enabled, bool location,
ec_type_t ec, size_t file = 0 )
: enabled(enabled)
, location(location)
, ec(ec)
, file(file)
{}
// sort by ec and file, not enablement
bool operator<( const cbl_enabled_exception_t& that ) const {
if( ec == that.ec ) return file < that.file;
return ec < that.ec;
}
// match on ec and file, not enablement
bool operator==( const cbl_enabled_exception_t& that ) const {
return ec == that.ec && file == that.file;
}
};
class cbl_enabled_exceptions_array_t;
class cbl_enabled_exceptions_t : protected std::set<cbl_enabled_exception_t>
{
friend cbl_enabled_exceptions_array_t;
void apply( const cbl_enabled_exception_t& elem ) {
auto inserted = insert( elem );
if( ! inserted.second ) {
erase(inserted.first);
insert(elem);
}
}
public:
bool turn_on_off( bool enabled, bool location, ec_type_t type,
std::set<size_t> files );
const cbl_enabled_exception_t * match( ec_type_t type, size_t file = 0 );
void dump() const;
void clear() { std::set<cbl_enabled_exception_t>::clear(); }
bool empty() const { return std::set<cbl_enabled_exception_t>::empty(); }
size_t size() const { return std::set<cbl_enabled_exception_t>::size(); }
cbl_enabled_exceptions_t& operator=( const cbl_enabled_exceptions_t& that ) {
std::set<cbl_enabled_exception_t>& self(*this);
self = that;
return *this;
}
};
extern cbl_enabled_exceptions_t enabled_exceptions;
/*
* This class is passed to the runtime function evaluating the raised exception.
* It is constructed in genapi.cc from the compile-time table.
*/
struct cbl_enabled_exceptions_array_t {
size_t nec;
cbl_enabled_exception_t *ecs;
cbl_enabled_exceptions_array_t( size_t nec, cbl_enabled_exception_t *ecs )
: nec(nec), ecs(ecs) {}
cbl_enabled_exceptions_array_t( const cbl_enabled_exceptions_t& input =
cbl_enabled_exceptions_t() )
: nec(input.size())
, ecs(NULL)
{
if( ! input.empty() ) {
ecs = new cbl_enabled_exception_t[nec];
std::copy(input.begin(), input.end(), ecs);
}
}
cbl_enabled_exceptions_array_t&
operator=( const cbl_enabled_exceptions_array_t& input);
bool match( ec_type_t ec, size_t file = 0 ) const;
size_t nbytes() const { return nec * sizeof(ecs[0]); }
};
template <typename T>
T enabled_exception_match( T beg, T end, ec_type_t type, size_t file ) {
cbl_enabled_exception_t input( true, true, // don't matter
type, file );
auto output = std::find(beg, end, input);
if( output == end ) {
output = std::find_if( beg, end, // match any file
[ec = type]( const cbl_enabled_exception_t& elem ) {
return
elem.file == 0 &&
ec_cmp(ec, elem.ec); } );
}
return output;
}
#endif