/*******************************************************************
** FedEx parser output module for generating C++ class definitions
** December 5, 1989
** release 2 17-Feb-1992
** release 3 March 1993
** release 4 December 1993
** K. C. Morris
**
** Development of FedEx was funded by the United States Government,
** and is not subject to copyright.
*******************************************************************
The conventions used in this binding follow the proposed specification
for the STEP Standard Data Access Interface as defined in document
N350 ( August 31, 1993 ) of ISO 10303 TC184/SC4/WG7.
*******************************************************************/
extern int multiple_inheritance;
/**************************************************************************
******** The functions in this file generate C++ code for representing
******** EXPRESS SELECT types.
**************************************************************************/
#include
#include "classes.h"
#include
bool is_python_keyword( char * word );
int isAggregateType( const Type t );
char * generate_attribute_name( Variable a, char * out );
void ATTRsign_access_methods( Variable a, FILE * file );
char * generate_attribute_func_name( Variable a, char * out );
void ATTRprint_access_methods_get_head( const char * classnm, Variable a, FILE * file );
void ATTRprint_access_methods_put_head( const char * entnm, Variable a, FILE * file );
#define BASE_SELECT "SCLP23(Select)"
#define TYPEis_primitive(t) ( !( TYPEis_entity(t) || \
TYPEis_select (t) || \
TYPEis_aggregate(t) ) )
#define TYPEis_numeric(t) ( ((t)->u.type->body->type == real_) || \
((t)->u.type->body->type == integer_) || \
((t)->u.type->body->type == number_) )
#define PRINT_BUG_REPORT \
fprintf( f, " std::cerr << __FILE__ << \":\" << __LINE__ << \": ERROR" \
" in schema library: \\n\" \n\t<< _POC_ << \"\\n\\n\";\n");
#define PRINT_SELECTBUG_WARNING(f) \
fprintf( (f), "\n severity( SEVERITY_WARNING );\n" ); \
fprintf( (f), " std::cerr << __FILE__ << \":\" << __LINE__ << \": "); \
fprintf( (f), "WARNING: possible misuse of\"\n << \" SELECT "); \
fprintf( (f), "TYPE from schema library.\\n\";\n"); \
fprintf( (f), " Error( \"Mismatch in underlying type.\" );\n" );
#define print_error_msg() \
fprintf( f, "\n severity( SEVERITY_BUG );\n" ); \
PRINT_BUG_REPORT \
fprintf( f, " Error( \"This 'argument' is of the incorrect type\" );\n" );
#define TRUE 1
#define FALSE 0
const char *
SEL_ITEMget_enumtype( Type t ) {
return StrToUpper( TYPEget_name( t ) );
}
/** FIXME implement for python or remove
** \returns type used to represent the underlying type in a select class
*/
const char * TYPEget_utype( Type t ) {
(void) t; /* unused */
return NULL;
}
/*******************
LISTmember
determines if the given entity is a member of the list.
RETURNS the member if it is a member; otherwise 0 is returned.
*******************/
void *
LISTmember( const Linked_List list, void *e ) {
Link node;
for( node = list->mark->next; node != list->mark; node = node->next )
if( e == node -> data ) {
return e;
}
return ( 0 );
}
/*******************
compareOrigTypes
Specialized function to catch if two enumerations, two selects, or two aggrs
of either, are of the same type. The issue is that e.g. select B may be a
rename of sel A (i.e., TYPE B = A;). Such renamed types are implemented by
exp2python with typedefs, so that they are in fact the same type. TYPEget_-
ctype() is used for most type comparisons and does not consider renamed types
equivalent. This function is called in instances when they should be consi-
dered equivalent. One such case is the generation of duplicate lists.
*******************/
static int
compareOrigTypes( Type a, Type b ) {
Type t, u;
if( ( TYPEis_select( a ) && TYPEis_select( b ) )
|| ( TYPEis_enumeration( a ) && TYPEis_enumeration( b ) ) ) {
t = a;
u = b;
} else if( TYPEis_aggregate( a ) && TYPEis_aggregate( b ) ) {
t = TYPEget_base_type( a );
u = TYPEget_base_type( b );
if( !( ( TYPEis_select( t ) && TYPEis_select( u ) )
|| ( TYPEis_enumeration( t ) && TYPEis_enumeration( u ) ) ) ) {
return FALSE;
/* Only go further with 1D aggregates of sels or enums. Note that
// for 2D aggrs and higher we do not continue. These are all recog-
// nized to be the same type ("GenericAggregate") by TYPEget_ctype(),
// and do not have to be handled specially here. */
}
} else {
return FALSE;
}
if( TYPEget_head( t ) ) {
t = TYPEget_ancestor( t );
}
if( TYPEget_head( u ) ) {
u = TYPEget_ancestor( u );
}
return ( !strcmp( TYPEget_name( t ), TYPEget_name( u ) ) );
}
/*******************
utype_member
determines if the given "link's" underlying type is a member of the list.
RETURNS the underlying type if it is a member; otherwise 0 is returned.
If "rename" is TRUE, we also consider check to match in certain cases where
list already has an item that check is a renaming of (see header comments to
compareOrigTypes() above).
*******************/
const char *
utype_member( const Linked_List list, const Type check, int rename ) {
static char r [BUFSIZ+1];
LISTdo( list, t, Type )
strncpy( r, TYPEget_utype( t ), BUFSIZ );
if( strcmp( r, TYPEget_utype( check ) ) == 0 ) {
return r;
}
if( rename && compareOrigTypes( check, t ) ) {
return r;
}
LISTod;
return 0;
}
/**
*** SELgetnew_dmlist (const Type type)
*** Returns a list of types which have unique underlying types
*** The returned list includes all the types which have a data members
*** in the select type.
***
*** The list that is returned needs to be freed by the caller.
***/
Linked_List
SELgetnew_dmlist( const Type type ) {
Linked_List complete = SEL_TYPEget_items( type );
Linked_List newlist = LISTcreate();
LISTdo( complete, t, Type )
/* if t\'s underlying type is not already in newlist, */
if( ! utype_member( newlist, t, 0 ) ) {
LISTadd_last( newlist, t );
}
LISTod;
return newlist;
}
const char *
SEL_ITEMget_dmtype( Type t, const Linked_List l ) {
const char * r = utype_member( l, t, 0 );
return StrToLower( r ? r : TYPEget_utype( t ) );
}
/*******************
duplicate_in_express_list
determines if the given "link's" underlying type is a multiple member
of the list.
RETURNS 1 if true, else 0.
*******************/
int
duplicate_in_express_list( const Linked_List list, const Type check ) {
if( TYPEis_entity( check ) ) {
return FALSE;
}
/* entities are never the same */
LISTdo( list, t, Type )
if( t == check ) {
; /* don\'t compare check to itself */
} else {
return TRUE; /* other things in the list conflict */
}
LISTod;
return FALSE;
}
/*******************
unique_types ( const Linked_List list )
determines if any of the types in a select type resolve to the same
underlying Express type.
RETURNS 1 if true, else 0.
*******************/
int
unique_types( const Linked_List list ) {
LISTdo( list, t, Type )
if( duplicate_in_express_list( list, t ) ) {
return FALSE;
}
LISTod;
return TRUE;
}
/*******************
duplicate_utype_member
determines if the given "link's" C++ representation is used again in the list.
RETURNS 1 if true, else 0.
*******************/
int
duplicate_utype_member( const Linked_List list, const Type check ) {
char b [BUFSIZ+1];
if( TYPEis_entity( check ) ) {
return FALSE;
}
/* entities are never the same */
LISTdo( list, t, Type )
if( t == check ) {
;
}
/* don\'t compare check to itself */
else { /* continue looking */
strncpy( b, TYPEget_utype( t ), BUFSIZ );
if( ( !strcmp( b, TYPEget_utype( check ) ) )
|| ( compareOrigTypes( t, check ) ) )
/* if the underlying types are the same */
{
return TRUE;
}
if( ! strcmp( b, "SCLP23(Integer)" ) &&
( ! strcmp( TYPEget_utype( check ), "SCLP23(Real)" ) ) )
/* integer\'s and real\'s are not unique */
{
return TRUE;
}
}
LISTod;
return FALSE;
}
/*******************
any_duplicates_in_select
determines if any of the types in a select type resolve to the same
C++ representation for the underlying Express type.
RETURNS 1 if true, else 0.
*******************/
int
any_duplicates_in_select( const Linked_List list ) {
LISTdo( list, t, Type )
if( duplicate_utype_member( list, t ) ) {
return TRUE;
}
LISTod;
return FALSE;
}
/*******************
find_duplicate_list
finds an instance of each kind of duplicate type found in the given list.
This list is returned as dup_list. If a duplicate exists, the function
returns TRUE, else FALSE.
list should be unbound before calling, and freed afterwards.
*******************/
int
find_duplicate_list( const Type type, Linked_List * duplicate_list ) {
Linked_List temp; /** temporary list for comparison **/
*duplicate_list = LISTcreate();
if( any_duplicates_in_select( SEL_TYPEget_items( type ) ) ) {
/** if there is a dup somewhere **/
temp = LISTcreate();
LISTdo( SEL_TYPEget_items( type ), u, Type )
if( !utype_member( *duplicate_list, u, 1 ) ) {
/** if not already a duplicate **/
if( utype_member( temp, u, 1 ) ) {
LISTadd_first( *duplicate_list, u );
} else {
LISTadd_first( temp, u );
}
}
LISTod;
LISTfree( temp );
return TRUE;
}
return FALSE;
}
/*******************
non_unique_types_string ( const Type type )
returns a string containing the non-unique EXPRESS types deriveable
from a select. the returned string is in the form (TYPE | TYPE |...)
*******************/
/* In the functions below, we use a vector of ints to count paths in the
select-graph to base types. The names in this enum correspond to the
indices in the vector, i.e., tvec[treal] == tvec[1], and contains the
number of paths to REAL in the graph
*/
enum __types {
tint = 0, /* INTEGER */
treal, /* REAL */
tstring, /* STRING */
tbinary, /* BINARY */
tenum, /* ENUMERATION, also LOGICAL, BOOLEAN */
tselect, /* SELECT */
tentity, /* ENTITY */
taggr, /* AGGREGATE, also ARRAY, BAG, SET, LIST */
tnumber /* NUMBER */
};
/* This function gets called recursively, to follow a select-graph to its
leaves. It passes around the vector described above, to track paths to
the leaf nodes.
*/
void
non_unique_types_vector( const Type type, int * tvec ) {
LISTdo( SEL_TYPEget_items( type ), t, Type )
switch( TYPEget_body( t )->type ) {
case integer_:
tvec[tint]++;
break;
case real_:
tvec[treal]++;
break;
case string_:
tvec[tstring]++;
break;
case binary_:
tvec[tbinary]++;
break;
case enumeration_:
case logical_:
case boolean_:
tvec[tenum]++;
break;
case select_:
/* SELECT, ergo recurse! */
non_unique_types_vector( t, tvec );
break;
case entity_:
tvec[tentity]++;
break;
case aggregate_:
case array_:
case list_:
case bag_:
case set_:
tvec[taggr]++;
break;
case number_:
tvec[tnumber]++;
break;
default:
fprintf( stderr, "Error at %s:%d - type %d not handled by switch statement.", __FILE__, __LINE__, TYPEget_body( t )->type );
abort();
}
LISTod;
}
/* Uses non_unique_types_vector on the select to get a vector of base-type
reference counts, then uses that to make a string of types, of the form
(FOO_TYPE | BAR_TYPE | BAZ_TYPE), where FOO, BAR, and BAZ are EXPRESS
types. If all types are unique, the string (0) is generated.
*/
char *
non_unique_types_string( const Type type ) {
int tvec[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
char * typestr;
int first = 1;
int i;
non_unique_types_vector( type, tvec );
/* build type string from vector */
typestr = ( char * )malloc( BUFSIZ+1 );
typestr[0] = '\0';
strcat( typestr, ( char * )"(" );
for( i = 0; i <= tnumber; i++ ) {
if( tvec[i] < 2 ) {
continue; /* skip, this one is unique */
}
if( !first ) {
strcat( typestr, ( char * )" | " );
} else {
first = 0;
}
switch( i ) {
case tint :
strcat( typestr, ( char * )"sdaiINTEGER" );
break;
case treal :
strcat( typestr, ( char * )"sdaiREAL" );
break;
case tstring:
strcat( typestr, ( char * )"sdaiSTRING" );
break;
case tbinary:
strcat( typestr, ( char * )"sdaiBINARY" );
break;
case tenum :
strcat( typestr, ( char * )"sdaiENUMERATION" );
break;
case tentity:
strcat( typestr, ( char * )"sdaiINSTANCE" );
break;
case taggr :
strcat( typestr, ( char * )"sdaiAGGR" );
break;
case tnumber:
strcat( typestr, ( char * )"sdaiNUMBER" );
break;
}
}
if( first ) {
strcat( typestr, ( char * )"0" );
}
strcat( typestr, ( char * )")" );
return typestr;
}
/******************************************************************
** Procedure: ATTR_LISTmember
** Parameters: Linked_List l, Variable check
** Returns: the attribute if an attribute with the same name as "check"
** is on the list, 0 otherwise
** Description: checks to see if an attribute is a member of the list
** Side Effects:
** Status: 26-Oct-1993 done
******************************************************************/
Variable
ATTR_LISTmember( Linked_List l, Variable check ) {
char nm [BUFSIZ+1];
char cur [BUFSIZ+1];
generate_attribute_name( check, nm );
LISTdo( l, a, Variable )
generate_attribute_name( a, cur );
if( ! strcmp( nm, cur ) ) {
return check;
}
LISTod;
return ( 0 );
}
/******************************************************************
** Procedure: SEL_TYPEgetnew_attribute_list
** Parameters: const Type type
** Returns: Returns a list of all the attributes for a select type.
** The list is the union of all the attributes of the underlying types.
** Description:
** Side Effects:
*** The list that is returned needs to be freed by the caller.
** Status:
******************************************************************/
Linked_List
SEL_TYPEgetnew_attribute_list( const Type type ) {
Linked_List complete = SEL_TYPEget_items( type );
Linked_List newlist = LISTcreate();
Linked_List attrs;
Entity cur;
LISTdo( complete, t, Type )
if( TYPEis_entity( t ) ) {
cur = ENT_TYPEget_entity( t );
attrs = ENTITYget_all_attributes( cur );
LISTdo_n( attrs, a, Variable, b )
if( ! ATTR_LISTmember( newlist, a ) ) {
LISTadd_first( newlist, a );
}
LISTod;
}
LISTod;
return newlist;
}
Linked_List
ENTITYget_expanded_entities( Entity e, Linked_List l ) {
Linked_List supers;
Entity super;
if( ! LISTmember( l, e ) ) {
LISTadd_first( l, e );
}
if( multiple_inheritance ) {
int super_cnt = 0;
supers = ENTITYget_supertypes( e );
LISTdo( supers, s, Entity )
/* ignore the more than one supertype
since multiple inheritance isn\'t implemented */
if( super_cnt == 0 ) {
ENTITYget_expanded_entities( s, l );
}
++ super_cnt;
LISTod;
} else {
/* ignore the more than one supertype
since multiple inheritance isn\'t implemented */
super = ENTITYget_superclass( e );
ENTITYget_expanded_entities( super, l );
}
return l;
}
Linked_List
SELget_entity_itemlist( const Type type ) {
Linked_List complete = SEL_TYPEget_items( type );
Linked_List newlist = LISTcreate();
Entity cur;
LISTdo( complete, t, Type )
if( TYPEis_entity( t ) ) {
cur = ENT_TYPEget_entity( t );
ENTITYget_expanded_entities( cur, newlist );
}
LISTod;
return newlist;
}
/*******************
TYPEselect_lib_print prints the member functions (definitions) of a select
class.
*******************/
void
TYPEselect_lib_print( const Type type, FILE * f ) {
int nbr_select = 0;
int num = 0;
fprintf( f, "# SELECT TYPE %s\n", TYPEget_name( type ) );
/* create the SELECT */
if( is_python_keyword( TYPEget_name( type ) ) ) {
fprintf( f, "%s_ = SELECT(", TYPEget_name( type ) );
} else {
fprintf( f, "%s = SELECT(", TYPEget_name( type ) );
}
/* first compute the number of types (necessary to insert commas) */
nbr_select = 0;
LISTdo( SEL_TYPEget_items( type ), t, Type )
(void) t; /* unused */
nbr_select++;
LISTod;
/* then write types */
num = 0;
LISTdo( SEL_TYPEget_items( type ), t, Type )
if( is_python_keyword( TYPEget_name( t ) ) ) {
fprintf( f, "\n\t'%s_'", TYPEget_name( t ) );
} else {
fprintf( f, "\n\t'%s'", TYPEget_name( t ) );
}
if( num < nbr_select - 1 ) {
fprintf( f, "," );
}
num++;
LISTod;
fprintf( f, ",\n\tscope = schema_scope)\n" );
}
#undef BASE_SELECT
/**************************************************************************
******** END of SELECT TYPE
**************************************************************************/