mirror of
https://github.com/NishiOwO/JWasm.git
synced 2025-04-21 08:44:38 +00:00
1345 lines
50 KiB
C
1345 lines
50 KiB
C
/****************************************************************************
|
|
*
|
|
* This code is Public Domain.
|
|
*
|
|
* ========================================================================
|
|
*
|
|
* Description: STRUCT, UNION, RECORD and TYPEDEF directives.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include <ctype.h>
|
|
|
|
#include "globals.h"
|
|
#include "memalloc.h"
|
|
#include "parser.h"
|
|
#include "segment.h"
|
|
#include "proc.h"
|
|
#include "input.h"
|
|
#include "tokenize.h"
|
|
#include "types.h"
|
|
#include "expreval.h"
|
|
#include "label.h"
|
|
#include "listing.h"
|
|
#include "fastpass.h"
|
|
#include "myassert.h"
|
|
|
|
/* v2.04: changed to 0 */
|
|
//#define ANYNAME 1 /* fixme: this probably should be changed to 0 */
|
|
#define ANYNAME 0
|
|
#define TYPEOPT 0
|
|
|
|
#if AMD64_SUPPORT
|
|
#define MAXRECBITS ( ModuleInfo.Ofssize == USE64 ? 64 : 32 )
|
|
#else
|
|
#define MAXRECBITS 32
|
|
#endif
|
|
|
|
struct dsym *CurrStruct;
|
|
static struct dsym *redef_struct;
|
|
/* text constants for 'Non-benign <x> redefinition' error msg */
|
|
static const char szStructure[] = "structure";
|
|
static const char szRecord[] = "record";
|
|
|
|
static const char szNonUnique[] = "NONUNIQUE";
|
|
|
|
void TypesInit( void )
|
|
/********************/
|
|
{
|
|
CurrStruct = NULL;
|
|
redef_struct = NULL;
|
|
}
|
|
|
|
/* create a SYM_TYPE symbol.
|
|
* <sym> must be NULL or of state SYM_UNDEFINED.
|
|
* <name> and <global> are only used if <sym> is NULL.
|
|
* <name> might be an empty string.
|
|
*/
|
|
|
|
struct asym *CreateTypeSymbol( struct asym *sym, const char *name, bool global )
|
|
/******************************************************************************/
|
|
{
|
|
struct struct_info *si;
|
|
|
|
if ( sym )
|
|
sym_remove_table( &SymTables[TAB_UNDEF], (struct dsym *)sym );
|
|
else
|
|
sym = ( global ? SymCreate( name ) : SymAlloc( name ) );
|
|
|
|
if ( sym ) {
|
|
sym->state = SYM_TYPE;
|
|
sym->typekind = TYPE_NONE;
|
|
((struct dsym *)sym)->e.structinfo = si = LclAlloc( sizeof( struct struct_info ) );
|
|
si->head = NULL;
|
|
si->tail = NULL;
|
|
si->alignment = 0;
|
|
si->flags = 0;
|
|
}
|
|
return( sym );
|
|
}
|
|
|
|
/* search a name in a struct's fieldlist */
|
|
|
|
struct asym *SearchNameInStruct( const struct asym *tstruct, const char *name, uint_32 *poffset, int level )
|
|
/**********************************************************************************************************/
|
|
{
|
|
int len = strlen( name );
|
|
struct sfield *fl = ((struct dsym *)tstruct)->e.structinfo->head;
|
|
struct asym *sym = NULL;
|
|
|
|
//if (ModuleInfo.oldstructs == TRUE) {
|
|
// return( SymSearch( name ) );
|
|
//}
|
|
if ( level >= MAX_STRUCT_NESTING ) {
|
|
EmitError( NESTING_LEVEL_TOO_DEEP );
|
|
return( NULL );
|
|
}
|
|
level++;
|
|
for ( ; fl; fl = fl->next ) {
|
|
/* recursion: if member has no name, check if it is a structure
|
|
and scan this structure's fieldlist then */
|
|
if ( *( fl->sym.name ) == NULLC ) {
|
|
/* there are 2 cases: an anonymous inline struct ... */
|
|
if ( fl->sym.state == SYM_TYPE ) {
|
|
if ( (sym = SearchNameInStruct( &fl->sym, name, poffset, level )) != NULL ) {
|
|
*poffset += fl->sym.offset;
|
|
break;
|
|
}
|
|
/* or an anonymous structured field */
|
|
} else if ( fl->sym.mem_type == MT_TYPE ) {
|
|
if ( (sym = SearchNameInStruct( fl->sym.type, name, poffset, level )) != NULL ) {
|
|
*poffset += fl->sym.offset;
|
|
break;
|
|
}
|
|
}
|
|
} else if ( len == fl->sym.name_size && SymCmpFunc( name, fl->sym.name, len ) == 0 ) {
|
|
DebugMsg(("SearchNameInStruct: '%s' found in struct %s\n", name, tstruct->name ));
|
|
sym = &fl->sym;
|
|
break;
|
|
}
|
|
}
|
|
return( sym );
|
|
}
|
|
|
|
/* check if a struct has changed */
|
|
|
|
static bool AreStructsEqual( const struct dsym *newstr, const struct dsym *oldstr )
|
|
/*********************************************************************************/
|
|
{
|
|
struct sfield *fold = oldstr->e.structinfo->head;
|
|
struct sfield *fnew = newstr->e.structinfo->head;
|
|
|
|
DebugMsg(("AreStructsEqual(%s) enter\n", oldstr->sym.name ));
|
|
|
|
/* kind of structs must be identical */
|
|
if ( oldstr->sym.typekind != newstr->sym.typekind )
|
|
return( FALSE );
|
|
|
|
for ( ; fold; fold = fold->next, fnew = fnew->next ) {
|
|
if ( !fnew ) {
|
|
DebugMsg(("AreStructsEqual: fields don't match\n"));
|
|
return( FALSE );
|
|
}
|
|
/* for global member names, don't check the name if it's "" */
|
|
if ( ModuleInfo.oldstructs && *fnew->sym.name == NULLC )
|
|
;
|
|
else if ( 0 != strcmp( fold->sym.name, fnew->sym.name ) ) {
|
|
DebugMsg(("AreStructsEqual: type name of field changed\n"));
|
|
return( FALSE );
|
|
}
|
|
if ( fold->sym.offset != fnew->sym.offset ) {
|
|
DebugMsg(("AreStructsEqual: offset of field %s changed: %u - %u\n", fold->sym.name, fold->sym.offset, fnew->sym.offset));
|
|
return( FALSE );
|
|
}
|
|
if ( fold->sym.total_size != fnew->sym.total_size ) {
|
|
DebugMsg(("AreStructsEqual: total_size of field changed\n"));
|
|
return( FALSE );
|
|
}
|
|
}
|
|
if ( fnew )
|
|
return( FALSE );
|
|
return( TRUE );
|
|
}
|
|
|
|
/* handle STRUCT, STRUC, UNION directives
|
|
* i = index of directive token
|
|
*/
|
|
ret_code StructDirective( int i, struct asm_tok tokenarray[] )
|
|
/************************************************************/
|
|
{
|
|
char *name;
|
|
unsigned alignment;
|
|
uint_32 offset;
|
|
uint_8 typekind = ( tokenarray[i].tokval == T_UNION ? TYPE_UNION : TYPE_STRUCT );
|
|
//unsigned int size;
|
|
struct asym *sym;
|
|
struct dsym *dir;
|
|
|
|
DebugMsg1(("StructDirective(%s) enter, i=%u, CurrStruct=%s\n", tokenarray[i].string_ptr, i, CurrStruct ? CurrStruct->sym.name : "NULL" ));
|
|
|
|
/* top level structs/unions must have an identifier at pos 0.
|
|
* for embedded structs, the directive must be at pos 0,
|
|
* an identifier is optional then.
|
|
*/
|
|
if (( CurrStruct == NULL && i != 1 ) ||
|
|
( CurrStruct != NULL && i != 0 ) ) {
|
|
DebugMsg(("StructDirective(%s): error: either currstruct or i must be 0\n", tokenarray[i].string_ptr ));
|
|
return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) );
|
|
}
|
|
|
|
alignment = ( 1 << ModuleInfo.fieldalign );
|
|
|
|
i++; /* go past STRUCT/UNION */
|
|
|
|
if ( i == 1 ) { /* embedded struct? */
|
|
/* scan for the optional name */
|
|
#if ANYNAME
|
|
/* the name might be a reserved word!
|
|
* Masm won't allow those.
|
|
*/
|
|
//if ( tokenarray[i].token != T_FINAL && is_valid_id_first_char(*(tokenarray[i].string_ptr) ) ) {
|
|
#else
|
|
if ( tokenarray[i].token == T_ID ) {
|
|
#endif
|
|
name = tokenarray[i].string_ptr;
|
|
i++;
|
|
} else {
|
|
name = "";
|
|
}
|
|
} else {
|
|
name = tokenarray[0].string_ptr;
|
|
}
|
|
|
|
/* get an optional alignment argument: 1,2,4,8,16 or 32 */
|
|
if ( CurrStruct == NULL && tokenarray[i].token != T_FINAL ) {
|
|
int power;
|
|
struct expr opndx;
|
|
/* get the optional alignment parameter.
|
|
* forward references aren't accepted, but EXPF_NOUNDEF isn't used here!
|
|
*/
|
|
if ( EvalOperand( &i, tokenarray, Token_Count, &opndx, 0 ) != ERROR ) {
|
|
/* an empty expression is accepted */
|
|
if ( opndx.kind == EXPR_EMPTY ) {
|
|
;
|
|
} else if ( opndx.kind != EXPR_CONST ) {
|
|
/* v2.09: better error msg */
|
|
if ( opndx.sym && opndx.sym->state == SYM_UNDEFINED )
|
|
EmitErr( SYMBOL_NOT_DEFINED, opndx.sym->name );
|
|
else
|
|
EmitError( CONSTANT_EXPECTED );
|
|
} else if( opndx.value > MAX_STRUCT_ALIGN ) {
|
|
EmitError( STRUCT_ALIGN_TOO_HIGH );
|
|
} else {
|
|
for( power = 1; power < opndx.value; power <<= 1 );
|
|
if( power != opndx.value ) {
|
|
EmitErr( POWER_OF_2, opndx.value );
|
|
} else
|
|
alignment = opndx.value;
|
|
}
|
|
DebugMsg1(("StructDirective(%s) alignment=%u\n", name, alignment));
|
|
}
|
|
/* there might also be the NONUNIQUE parameter */
|
|
if ( tokenarray[i].token == T_COMMA ) {
|
|
i++;
|
|
if ( tokenarray[i].token == T_ID &&
|
|
(_stricmp( tokenarray[i].string_ptr, szNonUnique ) == 0 ) ) {
|
|
/* currently NONUNIQUE is ignored */
|
|
EmitWarn( 2, TOKEN_IGNORED, szNonUnique );
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
if ( tokenarray[i].token != T_FINAL ) {
|
|
DebugMsg(("StructDirective(%s): error: unexpected token %u >%s<\n", tokenarray[i].token, tokenarray[i].tokpos ));
|
|
return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].tokpos ) );
|
|
}
|
|
|
|
/* does struct have a name? */
|
|
if ( *name ) {
|
|
if ( CurrStruct == NULL ) {
|
|
/* the "top-level" struct is part of the global namespace */
|
|
sym = SymSearch( name );
|
|
DebugMsg1(("StructDirective: SymSearch (%s)=%X (curr struct=%X)\n", name, sym, CurrStruct ));
|
|
} else {
|
|
sym = SearchNameInStruct( (struct asym *)CurrStruct, name, &offset, 0 );
|
|
DebugMsg1(("StructDirective(%s): SearchNameInStruc()=%X\n", name, sym));
|
|
}
|
|
} else {
|
|
sym = NULL; /* anonymous struct */
|
|
}
|
|
|
|
if ( ModuleInfo.list ) {
|
|
if ( CurrStruct )
|
|
LstWrite( LSTTYPE_STRUCT, CurrStruct->sym.total_size, NULL );
|
|
else
|
|
LstWrite( LSTTYPE_STRUCT, 0, NULL );
|
|
}
|
|
|
|
/* if pass is > 1, update struct stack + CurrStruct.offset and exit */
|
|
if ( Parse_Pass > PASS_1 ) {
|
|
/* v2.04 changed. the previous implementation was insecure.
|
|
* See also change in data.c, behind CreateStructField().
|
|
*/
|
|
if ( CurrStruct ) {
|
|
sym = CurrStruct->e.structinfo->tail->sym.type;
|
|
/**/myassert( sym );
|
|
CurrStruct->e.structinfo->tail = CurrStruct->e.structinfo->tail->next;
|
|
}
|
|
/**/myassert( sym );
|
|
dir = (struct dsym *)sym;
|
|
dir->e.structinfo->tail = dir->e.structinfo->head;
|
|
sym->offset = 0;
|
|
sym->isdefined = TRUE;
|
|
((struct dsym *)sym)->next = CurrStruct;
|
|
CurrStruct = (struct dsym *)sym;
|
|
return( NOT_ERROR );
|
|
}
|
|
|
|
if( sym == NULL ) {
|
|
|
|
/* embedded or global STRUCT? */
|
|
if ( CurrStruct == NULL )
|
|
sym = CreateTypeSymbol( NULL, name, TRUE );
|
|
else {
|
|
/* an embedded struct is split in an anonymous STRUCT type
|
|
* and a struct field with/without name
|
|
*/
|
|
sym = CreateTypeSymbol( NULL, name, FALSE );
|
|
/* v2: don't create the struct field here. First the
|
|
* structure must be read in ( because of alignment issues
|
|
*/
|
|
// sym = CreateStructField( name_loc, -1, MT_TYPE, dir, 0 );
|
|
|
|
alignment = CurrStruct->e.structinfo->alignment;
|
|
}
|
|
|
|
} else if( sym->state == SYM_UNDEFINED ) {
|
|
|
|
/* forward reference */
|
|
CreateTypeSymbol( sym, NULL, CurrStruct == NULL );
|
|
|
|
} else if( sym->state == SYM_TYPE && CurrStruct == NULL ) {
|
|
|
|
switch ( sym->typekind ) {
|
|
case TYPE_STRUCT:
|
|
case TYPE_UNION:
|
|
/* if a struct is redefined as a union ( or vice versa )
|
|
* do accept the directive and just check if the redefinition
|
|
* is compatible (usually it isn't) */
|
|
redef_struct = (struct dsym *)sym;
|
|
sym = CreateTypeSymbol( NULL, name, FALSE );
|
|
break;
|
|
case TYPE_NONE: /* TYPE_NONE is forward reference */
|
|
break;
|
|
default:
|
|
return( EmitErr( SYMBOL_REDEFINITION, sym->name ) );
|
|
}
|
|
|
|
} else {
|
|
return( EmitErr( SYMBOL_REDEFINITION, sym->name ) );
|
|
}
|
|
|
|
sym->offset = 0;
|
|
sym->typekind = typekind;
|
|
dir = (struct dsym *)sym;
|
|
dir->e.structinfo->alignment = alignment;
|
|
dir->e.structinfo->isOpen = TRUE;
|
|
if ( CurrStruct )
|
|
dir->e.structinfo->isInline = TRUE;
|
|
|
|
dir->next = CurrStruct;
|
|
CurrStruct = dir;
|
|
|
|
#if 0 //def DEBUG_OUT
|
|
{
|
|
struct dsym *struc;
|
|
for ( struc = CurrStruct; struc; struc = struc->next ) {
|
|
DebugMsg(("StructDirective stack: %X, name=>%s<\n", struc, struc->sym.name ));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return( NOT_ERROR );
|
|
}
|
|
|
|
/* handle ENDS directive when a struct/union definition is active */
|
|
|
|
ret_code EndstructDirective( int i, struct asm_tok tokenarray[] )
|
|
/***************************************************************/
|
|
{
|
|
//char *name;
|
|
//unsigned int offset;
|
|
unsigned int size;
|
|
//struct asym *sym;
|
|
//memtype mem_type;
|
|
struct dsym *dir;
|
|
|
|
dir = CurrStruct; /* cannot be NULL */
|
|
|
|
DebugMsg1(("EndstructDirective(%s), ofs=%" I32_SPEC "u, struct size=%" I32_SPEC "u, max_mbr=%" I32_SPEC "u, alignment=%u\n",
|
|
dir->sym.name,
|
|
dir->sym.offset,
|
|
dir->sym.total_size,
|
|
dir->sym.max_mbr_size,
|
|
dir->e.structinfo->alignment));
|
|
|
|
/* if pass is > 1 just do minimal work */
|
|
if ( Parse_Pass > PASS_1 ) {
|
|
CurrStruct->sym.offset = 0;
|
|
size = CurrStruct->sym.total_size;
|
|
CurrStruct = CurrStruct->next;
|
|
if ( CurrStruct )
|
|
UpdateStructSize( (struct asym *)dir );
|
|
if ( CurrFile[LST] )
|
|
LstWrite( LSTTYPE_STRUCT, size, dir );
|
|
return( NOT_ERROR );
|
|
}
|
|
|
|
/* syntax is either "<name> ENDS" (i=1) or "ENDS" (i=0).
|
|
* first case must be top level (next=NULL), latter case must NOT be top level (next!=NULL)
|
|
*/
|
|
if ( ( i == 1 && dir->next == NULL ) ||
|
|
( i == 0 && dir->next != NULL ) ) {
|
|
;
|
|
} else {
|
|
/* v2.04: error msg improved */
|
|
//EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr );
|
|
return( EmitErr( UNMATCHED_BLOCK_NESTING, i == 1 ? tokenarray[0].string_ptr : "" ) );
|
|
}
|
|
|
|
if ( i == 1 ) { /* an global struct ends with <name ENDS> */
|
|
if ( SymCmpFunc( tokenarray[0].string_ptr, dir->sym.name, dir->sym.name_size ) != 0 ) {
|
|
/* names don't match */
|
|
DebugMsg(("EndstructDirective: names don't match, i=%u, name=%s - %s\n", i, tokenarray[0].string_ptr, dir->sym.name));
|
|
return( EmitErr( UNMATCHED_BLOCK_NESTING, tokenarray[0].string_ptr ) );
|
|
}
|
|
}
|
|
|
|
i++; /* go past ENDS */
|
|
|
|
/* v2.07: if ORG was used inside the struct, the struct's size
|
|
* has to be calculated now - there may exist negative offsets.
|
|
*/
|
|
if ( dir->e.structinfo->OrgInside ) {
|
|
struct sfield *f;
|
|
int_32 min = 0;
|
|
for ( f = dir->e.structinfo->head; f; f = f->next )
|
|
if ( f->sym.offset < min )
|
|
min = f->sym.offset;
|
|
dir->sym.total_size = dir->sym.total_size - min;
|
|
}
|
|
|
|
/* Pad bytes at the end of the structure. */
|
|
#if 1
|
|
/* v2.02: this is to be done in any case, whether -Zg is set or not */
|
|
//if ( dir->e.structinfo->alignment > 1 && Options.masm_compat_gencode == FALSE ) {
|
|
if ( dir->e.structinfo->alignment > 1 ) {
|
|
size = dir->sym.max_mbr_size;
|
|
if ( size == 0 )
|
|
size++;
|
|
if ( size > dir->e.structinfo->alignment )
|
|
size = dir->e.structinfo->alignment;
|
|
dir->sym.total_size = (dir->sym.total_size + size - 1) & (-size);
|
|
DebugMsg1(("EndstructDirective:, struct size after final alignment=%" I32_SPEC "u\n", dir->sym.total_size));
|
|
}
|
|
#endif
|
|
dir->e.structinfo->isOpen = FALSE;
|
|
dir->sym.isdefined = TRUE;
|
|
|
|
/* if there's a negative offset, size will be wrong! */
|
|
size = dir->sym.total_size;
|
|
|
|
/* reset offset, it's just used during the definition */
|
|
dir->sym.offset = 0;
|
|
|
|
CurrStruct = dir->next;
|
|
/* v2.0: add the embedded struct AFTER it has been parsed! */
|
|
if ( i == 1 ) {
|
|
struct asym *sym;
|
|
/* v2.06: the struct name is needed for checks */
|
|
sym = CreateStructField( -1, NULL, *dir->sym.name ? dir->sym.name : NULL, MT_TYPE, &dir->sym, dir->sym.total_size );
|
|
/* the member name was stored in the type name */
|
|
//sym->name = dir->sym.name;
|
|
//sym->name_size = strlen( dir->sym.name );
|
|
sym->total_size = dir->sym.total_size;
|
|
dir->sym.name = ""; /* the type becomes anonymous */
|
|
dir->sym.name_size = 0;
|
|
}
|
|
|
|
if ( CurrFile[LST] ) {
|
|
LstWrite( LSTTYPE_STRUCT, size, dir );
|
|
}
|
|
#if 1
|
|
/* to allow direct structure access */
|
|
switch ( dir->sym.total_size ) {
|
|
case 1: dir->sym.mem_type = MT_BYTE; break;
|
|
case 2: dir->sym.mem_type = MT_WORD; break;
|
|
case 4: dir->sym.mem_type = MT_DWORD; break;
|
|
case 6: dir->sym.mem_type = MT_FWORD; break;
|
|
case 8: dir->sym.mem_type = MT_QWORD; break;
|
|
//case 16: dir->sym.mem_type = MT_OWORD; break;
|
|
default: dir->sym.mem_type = MT_EMPTY;
|
|
}
|
|
#endif
|
|
/* reset redefine */
|
|
if ( CurrStruct == NULL ) {
|
|
if ( redef_struct ) {
|
|
if ( AreStructsEqual( dir, redef_struct) == FALSE ) {
|
|
EmitErr( NON_BENIGN_XXX_REDEFINITION, szStructure, dir->sym.name );
|
|
}
|
|
DebugMsg(("EndstructDirective: delete the redefinition of %s\n", dir->sym.name ));
|
|
SymFree( (struct asym *)dir );
|
|
redef_struct = NULL;
|
|
}
|
|
} else {
|
|
|
|
if ( dir->sym.max_mbr_size > CurrStruct->sym.max_mbr_size )
|
|
CurrStruct->sym.max_mbr_size = dir->sym.max_mbr_size;
|
|
|
|
UpdateStructSize( (struct asym *)dir );
|
|
DebugMsg1(("EndstructDirective: new size of restored structure=%u\n", CurrStruct->sym.total_size));
|
|
}
|
|
//dir->sym.max_mbr_size = 0;
|
|
if ( tokenarray[i].token != T_FINAL ) {
|
|
return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) );
|
|
}
|
|
return( NOT_ERROR );
|
|
}
|
|
|
|
/* v2.06: new function to check fields of anonymous struct members */
|
|
|
|
static ret_code CheckAnonymousStruct( struct dsym *type )
|
|
/*******************************************************/
|
|
{
|
|
uint_32 disp;
|
|
struct asym *sym;
|
|
struct sfield *f;
|
|
|
|
for ( f = type->e.structinfo->head; f; f = f->next ) {
|
|
if ( *f->sym.name ) {
|
|
sym = SearchNameInStruct((struct asym *)CurrStruct, f->sym.name, &disp, 0 );
|
|
if ( sym ) {
|
|
return( EmitErr( SYMBOL_REDEFINITION, sym->name ) );
|
|
}
|
|
} else if ( f->sym.type ) {
|
|
struct dsym *stype = (struct dsym *)f->sym.type;
|
|
if ( stype->sym.typekind == TYPE_STRUCT ||
|
|
stype->sym.typekind == TYPE_UNION ) {
|
|
if ( CheckAnonymousStruct( stype ) == ERROR )
|
|
return( ERROR );
|
|
}
|
|
}
|
|
}
|
|
return( NOT_ERROR );
|
|
}
|
|
|
|
/* CreateStructField() - creates a symbol of state SYM_STRUCT_FIELD.
|
|
* this function is called in pass 1 only.
|
|
* - loc: initializer index location, -1 means no initializer (is an embedded struct)
|
|
* - name: field name, may be NULL
|
|
* - mem_type: mem_type of item
|
|
* - vartype: user-defined type of item if memtype is MT_TYPE
|
|
* - size: size of type - used for alignment only
|
|
*/
|
|
struct asym *CreateStructField( int loc, struct asm_tok tokenarray[], const char *name, enum memtype mem_type, struct asym *vartype, uint_32 size )
|
|
/*************************************************************************************************************************************************/
|
|
{
|
|
int_32 offset;
|
|
//int count;
|
|
int i;
|
|
int len;
|
|
uint_32 disp;
|
|
char *init;
|
|
struct struct_info *si;
|
|
struct sfield *f;
|
|
struct asym *gsym;
|
|
|
|
si = CurrStruct->e.structinfo;
|
|
offset = CurrStruct->sym.offset;
|
|
|
|
DebugMsg1(("CreateStructField(%s): name=%s, curr ofs=%" I32_SPEC "u, vartype=%s, size=%" I32_SPEC "u\n",
|
|
CurrStruct->sym.name, name ? name : "<anonymous>", offset,
|
|
vartype ? vartype->name : "NULL", size ));
|
|
|
|
if ( name ) {
|
|
struct asym *sym;
|
|
len = strlen( name );
|
|
if( len > MAX_ID_LEN ) {
|
|
EmitError( IDENTIFIER_TOO_LONG );
|
|
return( NULL );
|
|
}
|
|
sym = SearchNameInStruct((struct asym *)CurrStruct, name, &disp, 0 );
|
|
if ( sym ) {
|
|
EmitErr( SYMBOL_ALREADY_DEFINED, sym->name );
|
|
return( NULL );
|
|
}
|
|
} else {
|
|
/* v2.06: check fields of anonymous struct member */
|
|
if ( vartype &&
|
|
( vartype->typekind == TYPE_STRUCT ||
|
|
vartype->typekind == TYPE_UNION ) ) {
|
|
CheckAnonymousStruct( (struct dsym *)vartype );
|
|
}
|
|
name = "";
|
|
len = 0;
|
|
}
|
|
|
|
if ( loc != -1 ) {
|
|
|
|
//i = strlen( tokenarray[loc].string_ptr ) + 1;
|
|
//DebugMsg1(("CreateStructField(%s): type=>%s<\n", CurrStruct->sym.name, tokenarray[loc].string_ptr ));
|
|
//f->init_dir = LclAlloc( i );
|
|
//memcpy( f->init_dir, tokenarray[loc].string_ptr, i );
|
|
|
|
/* now add the value to initialize the struct to */
|
|
|
|
/* v2.03: the initializer value may contain assembly time
|
|
* variables ( $ inside structs is also one ). It's crucial that
|
|
* the variable's CURRENT value is used then.
|
|
* v2.08: modified. avoid usage of token->string_ptr,
|
|
* and prefer to use token->tokpos.
|
|
*/
|
|
init = StringBufferEnd;
|
|
for ( i = loc+1; tokenarray[i].token != T_FINAL; i++ ) {
|
|
if ( tokenarray[i].token == T_ID ) {
|
|
struct asym *sym2 = SymSearch( tokenarray[i].string_ptr );
|
|
if ( sym2 && sym2->variable ) {
|
|
if ( sym2->predefined && sym2->sfunc_ptr )
|
|
sym2->sfunc_ptr( sym2, NULL );
|
|
myltoa( sym2->uvalue, init, ModuleInfo.radix, sym2->value3264 < 0, TRUE );
|
|
init += strlen( init );
|
|
*init++= ' ';
|
|
continue;
|
|
}
|
|
}
|
|
memcpy( init, tokenarray[i].tokpos, tokenarray[i+1].tokpos - tokenarray[i].tokpos );
|
|
init += tokenarray[i+1].tokpos - tokenarray[i].tokpos;
|
|
}
|
|
*init = NULLC;
|
|
f = LclAlloc( sizeof( struct sfield ) + ( init - StringBufferEnd ) );
|
|
//f->value = LclAlloc( init - StringBufferEnd + 1 );
|
|
memset( f, 0, sizeof( struct sfield ) );
|
|
strcpy( f->ivalue, StringBufferEnd );
|
|
DebugMsg1(("CreateStructField(%s): initializer=>%s<\n", CurrStruct->sym.name, f->ivalue ));
|
|
|
|
} else {
|
|
f = LclAlloc( sizeof( struct sfield ) );
|
|
memset( f, 0, sizeof( struct sfield ) );
|
|
DebugMsg1(("CreateStructField(%s): no initializer<\n", CurrStruct->sym.name ));
|
|
//f->init_dir = NULL;
|
|
f->ivalue[0] = NULLC;
|
|
}
|
|
|
|
/* create the struct field symbol */
|
|
|
|
//sym = SymAlloc( name );
|
|
f->sym.name_size = len;
|
|
if ( len ) {
|
|
f->sym.name = LclAlloc( len + 1 );
|
|
memcpy( f->sym.name, name, len );
|
|
f->sym.name[len] = NULLC;
|
|
} else
|
|
f->sym.name = "";
|
|
f->sym.state = SYM_STRUCT_FIELD;
|
|
f->sym.list = ModuleInfo.cref;
|
|
f->sym.isdefined = TRUE;
|
|
f->sym.mem_type = mem_type;
|
|
f->sym.type = vartype;
|
|
/* fields total/first_size, total/first_length are set in data_item() */
|
|
// sym->total_size = SizeFromMemtype( mem_type, ModuleInfo.Ofssize );
|
|
|
|
f->next = NULL;
|
|
//f->sym = sym;
|
|
|
|
if( si->head == NULL ) {
|
|
si->head = si->tail = f;
|
|
} else {
|
|
si->tail->next = f;
|
|
si->tail = f;
|
|
}
|
|
|
|
#if 1
|
|
/* v2.0: for STRUCTs, don't use the struct's size for alignment calculations,
|
|
* instead use the size of the "max" member!
|
|
*/
|
|
if ( mem_type == MT_TYPE &&
|
|
( vartype->typekind == TYPE_STRUCT ||
|
|
vartype->typekind == TYPE_UNION ) ) {
|
|
size = vartype->max_mbr_size;
|
|
}
|
|
#endif
|
|
/* align the field if an alignment argument was given */
|
|
if ( si->alignment > 1 ) {
|
|
//enum memtype mt;
|
|
//struct dsym *tdir;
|
|
DebugMsg1(("CreateStructField(%s): align=%u, size=%u, ofs=%u\n", CurrStruct->sym.name, si->alignment, size, offset ));
|
|
/* if it's the first field to add, use offset of the parent's current field */
|
|
#if 0
|
|
/* v2: removed. An embedded struct is now added AFTER it has
|
|
* been parsed. */
|
|
if ( offset == 0 && CurrStruct->next ) {
|
|
struct dsym *parent = CurrStruct->next;
|
|
if ( si->alignment < size )
|
|
parent->e.structinfo->tail->sym->offset =
|
|
(parent->e.structinfo->tail->sym->offset + (si->alignment - 1)) & ( - si->alignment);
|
|
else if ( size )
|
|
parent->e.structinfo->tail->sym->offset =
|
|
(parent->e.structinfo->tail->sym->offset + (size - 1)) & (-size);
|
|
} else
|
|
#endif
|
|
{
|
|
if ( si->alignment < size )
|
|
offset = (offset + (si->alignment - 1)) & ( - si->alignment);
|
|
else if ( size )
|
|
offset = (offset + (size - 1)) & (-size);
|
|
}
|
|
/* adjust the struct's current offset + size.
|
|
The field's size is added in UpdateStructSize()
|
|
*/
|
|
if ( CurrStruct->sym.typekind != TYPE_UNION ) {
|
|
CurrStruct->sym.offset = offset;
|
|
if ( offset > CurrStruct->sym.total_size )
|
|
CurrStruct->sym.total_size = offset;
|
|
}
|
|
}
|
|
/* v2.0: for padding, save the max member size */
|
|
if ( size > CurrStruct->sym.max_mbr_size ) {
|
|
DebugMsg1(("CreateStructField(%s): max_mbr_size set to %u\n", CurrStruct->sym.name, size ));
|
|
CurrStruct->sym.max_mbr_size = size;
|
|
}
|
|
f->sym.offset = offset;
|
|
|
|
/* if -Zm is on, create a global symbol */
|
|
if ( ModuleInfo.oldstructs == TRUE && *name != NULLC ) {
|
|
DebugMsg(("CreateStructField(%s): Masm51 compat on, lookup %s in global symbol table\n", CurrStruct->sym.name, name ));
|
|
gsym = SymLookup( name );
|
|
/* v2.11: cannot fail */
|
|
//if ( gsym ) {
|
|
if ( gsym->state == SYM_UNDEFINED )
|
|
gsym->state = SYM_STRUCT_FIELD;
|
|
if ( gsym->state == SYM_STRUCT_FIELD ) {
|
|
struct dsym *dir;
|
|
gsym->mem_type = mem_type;
|
|
gsym->type = vartype;
|
|
gsym->offset = offset; /* added v2.0 */
|
|
/* v2.01: must be the full offset.
|
|
* (there's still a problem if alignment is > 1!)
|
|
*/
|
|
for ( dir = CurrStruct->next; dir; dir = dir->next )
|
|
gsym->offset += dir->sym.offset;
|
|
gsym->isdefined = TRUE;
|
|
}
|
|
//}
|
|
}
|
|
|
|
return( &f->sym );
|
|
}
|
|
|
|
/* called by AlignDirective() if ALIGN/EVEN has been found inside
|
|
* a struct. It's already verified that <value> is a power of 2.
|
|
*/
|
|
ret_code AlignInStruct( int value )
|
|
/*********************************/
|
|
{
|
|
if ( CurrStruct->sym.typekind != TYPE_UNION ) {
|
|
int offset;
|
|
offset = CurrStruct->sym.offset;
|
|
offset = (offset + (value - 1)) & (-value);
|
|
CurrStruct->sym.offset = offset;
|
|
if ( offset > CurrStruct->sym.total_size )
|
|
CurrStruct->sym.total_size = offset;
|
|
}
|
|
return( NOT_ERROR );
|
|
}
|
|
|
|
/* called by data_dir() when a structure field has been created.
|
|
*/
|
|
void UpdateStructSize( struct asym *sym )
|
|
/***************************************/
|
|
{
|
|
if ( CurrStruct->sym.typekind == TYPE_UNION ) {
|
|
//if ( no_of_bytes > CurrStruct->sym.total_size )
|
|
// CurrStruct->sym.total_size = no_of_bytes;
|
|
if ( sym->total_size > CurrStruct->sym.total_size )
|
|
CurrStruct->sym.total_size = sym->total_size;
|
|
} else {
|
|
CurrStruct->sym.offset += sym->total_size;
|
|
if ( CurrStruct->sym.offset > (int_32)CurrStruct->sym.total_size )
|
|
CurrStruct->sym.total_size = CurrStruct->sym.offset;
|
|
}
|
|
DebugMsg1(("UpdateStructSize(%s.%s): %s, curr mbr size=%u curr struc/union size=%u\n",
|
|
CurrStruct->sym.name,
|
|
sym->name,
|
|
CurrStruct->sym.typekind == TYPE_UNION ? "union" : "struct",
|
|
sym->total_size,
|
|
CurrStruct->sym.total_size));
|
|
return;
|
|
}
|
|
|
|
/* called if ORG occurs inside STRUCT/UNION definition */
|
|
|
|
ret_code SetStructCurrentOffset( int_32 offset )
|
|
/**********************************************/
|
|
{
|
|
if ( CurrStruct->sym.typekind == TYPE_UNION ) {
|
|
return( EmitError( ORG_NOT_ALLOWED_IN_UNIONS ) );
|
|
}
|
|
CurrStruct->sym.offset = offset;
|
|
/* if an ORG is inside the struct, it cannot be instanced anymore */
|
|
CurrStruct->e.structinfo->OrgInside = TRUE;
|
|
if ( offset > (int_32)CurrStruct->sym.total_size )
|
|
CurrStruct->sym.total_size = offset;
|
|
|
|
return( NOT_ERROR );
|
|
}
|
|
|
|
/* get a qualified type.
|
|
* Used by
|
|
* - TYPEDEF
|
|
* - PROC/PROTO params and LOCALs
|
|
* - EXTERNDEF
|
|
* - EXTERN
|
|
* - LABEL
|
|
* - ASSUME for GPRs
|
|
*/
|
|
ret_code GetQualifiedType( int *pi, struct asm_tok tokenarray[], struct qualified_type *pti )
|
|
/*******************************************************************************************/
|
|
{
|
|
int type;
|
|
int tmp;
|
|
enum memtype mem_type;
|
|
int i = *pi;
|
|
int distance = FALSE;
|
|
struct asym *sym;
|
|
|
|
/* convert PROC token to a type qualifier */
|
|
for ( tmp = i; tokenarray[tmp].token != T_FINAL && tokenarray[tmp].token != T_COMMA; tmp++ )
|
|
if ( tokenarray[tmp].token == T_DIRECTIVE && tokenarray[tmp].tokval == T_PROC ) {
|
|
tokenarray[tmp].token = T_STYPE;
|
|
/* v2.06: avoid to use ST_PROC */
|
|
tokenarray[tmp].tokval = ( ( SIZE_CODEPTR & ( 1 << ModuleInfo.model ) ) ? T_FAR : T_NEAR );
|
|
}
|
|
/* with NEAR/FAR, there are several syntax variants allowed:
|
|
* 1. NEARxx | FARxx
|
|
* 2. PTR NEARxx | FARxx
|
|
* 3. NEARxx | FARxx PTR [<type>]
|
|
*/
|
|
/* read qualified type */
|
|
for ( type = ERROR; tokenarray[i].token == T_STYPE || tokenarray[i].token == T_BINARY_OPERATOR; i++ ) {
|
|
if ( tokenarray[i].token == T_STYPE ) {
|
|
tmp = tokenarray[i].tokval;
|
|
if ( type == ERROR )
|
|
type = tmp;
|
|
mem_type = GetMemtypeSp( tmp );
|
|
if ( mem_type == MT_FAR || mem_type == MT_NEAR ) {
|
|
if ( distance == FALSE ) {
|
|
uint_8 Ofssize = GetSflagsSp( tmp );
|
|
pti->is_far = ( mem_type == MT_FAR );
|
|
if ( Ofssize != USE_EMPTY )
|
|
pti->Ofssize = Ofssize;
|
|
distance = TRUE;
|
|
} else if ( tokenarray[i-1].tokval != T_PTR )
|
|
break;
|
|
} else {
|
|
if ( pti->is_ptr )
|
|
pti->ptr_memtype = mem_type;
|
|
i++;
|
|
break;
|
|
}
|
|
} else if ( tokenarray[i].tokval == T_PTR ) {
|
|
/* v2.06: avoid to use ST_PTR */
|
|
//type = ST_PTR;
|
|
type = EMPTY;
|
|
pti->is_ptr++;
|
|
} else
|
|
break;
|
|
}
|
|
|
|
/* v2.06: don't use ST_PTR anymore! */
|
|
//if ( type == ST_PTR ) {
|
|
if ( type == EMPTY ) {
|
|
if ( tokenarray[i].token == T_ID && tokenarray[i-1].tokval == T_PTR ) {
|
|
pti->symtype = SymSearch( tokenarray[i].string_ptr );
|
|
if ( pti->symtype == NULL || pti->symtype->state == SYM_UNDEFINED )
|
|
pti->symtype = CreateTypeSymbol( pti->symtype, tokenarray[i].string_ptr, TRUE );
|
|
else if ( pti->symtype->state != SYM_TYPE ) {
|
|
return( EmitErr( INVALID_QUALIFIED_TYPE, tokenarray[i].string_ptr ) );
|
|
} else {
|
|
sym = pti->symtype;
|
|
/* if it's a typedef, simplify the info */
|
|
if ( sym->typekind == TYPE_TYPEDEF ) {
|
|
pti->is_ptr += sym->is_ptr;
|
|
if ( sym->is_ptr == 0 ) {
|
|
/* v2.06b: alias types have MT_TYPE, dont use for ptr_memtype! */
|
|
//pti->ptr_memtype = sym->mem_type;
|
|
pti->ptr_memtype = ( sym->mem_type != MT_TYPE ? sym->mem_type : MT_EMPTY );
|
|
if ( distance == FALSE && pti->is_ptr == 1 &&
|
|
( sym->mem_type == MT_NEAR ||
|
|
sym->mem_type == MT_PROC ||
|
|
sym->mem_type == MT_FAR ) )
|
|
pti->is_far = sym->isfar;
|
|
if ( sym->Ofssize != USE_EMPTY )
|
|
pti->Ofssize = sym->Ofssize;
|
|
} else {
|
|
pti->ptr_memtype = sym->ptr_memtype;
|
|
if ( distance == FALSE && pti->is_ptr == 1 ) {
|
|
pti->is_far = sym->isfar;
|
|
if ( sym->Ofssize != USE_EMPTY )
|
|
pti->Ofssize = sym->Ofssize;
|
|
}
|
|
}
|
|
if ( sym->mem_type == MT_TYPE )
|
|
pti->symtype = sym->type;
|
|
else {
|
|
DebugMsg1(("GetQualifiedType: memtype=%X, symtype set by target_type\n", sym->mem_type ));
|
|
pti->symtype = sym->target_type;
|
|
}
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if( type == ERROR ) {
|
|
if ( tokenarray[i].token != T_ID ) {
|
|
if ( tokenarray[i].token == T_FINAL || tokenarray[i].token == T_COMMA )
|
|
EmitError( QUALIFIED_TYPE_EXPECTED );
|
|
else {
|
|
EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr );
|
|
i++;
|
|
}
|
|
return( ERROR );
|
|
}
|
|
pti->symtype = SymSearch( tokenarray[i].string_ptr );
|
|
if( pti->symtype == NULL || pti->symtype->state != SYM_TYPE ) {
|
|
DebugMsg(("GetQualifiedType: invalid type : %s\n", tokenarray[i].string_ptr ));
|
|
if ( pti->symtype == NULL || pti->symtype ->state == SYM_UNDEFINED )
|
|
EmitErr( SYMBOL_NOT_DEFINED, tokenarray[i].string_ptr );
|
|
else
|
|
EmitErr( INVALID_QUALIFIED_TYPE, tokenarray[i].string_ptr );
|
|
return( ERROR );
|
|
}
|
|
sym = pti->symtype;
|
|
if ( sym->typekind == TYPE_TYPEDEF ) {
|
|
pti->mem_type = sym->mem_type;
|
|
pti->is_far = sym->isfar;
|
|
pti->is_ptr = sym->is_ptr;
|
|
pti->Ofssize = sym->Ofssize;
|
|
pti->size = sym->total_size;
|
|
pti->ptr_memtype = sym->ptr_memtype;
|
|
if ( sym->mem_type == MT_TYPE )
|
|
pti->symtype = sym->type;
|
|
else {
|
|
DebugMsg1(("GetQualifiedType: memtype=%X, symtype set by target_type\n", sym->mem_type ));
|
|
pti->symtype = sym->target_type;
|
|
}
|
|
} else {
|
|
pti->mem_type = MT_TYPE;
|
|
pti->size = sym->total_size;
|
|
}
|
|
i++;
|
|
} else {
|
|
if ( pti->is_ptr )
|
|
pti->mem_type = MT_PTR;
|
|
else
|
|
pti->mem_type = GetMemtypeSp( type );
|
|
if ( pti->mem_type == MT_PTR )
|
|
pti->size = SizeFromMemtype( pti->is_far ? MT_FAR : MT_NEAR, pti->Ofssize, NULL );
|
|
else
|
|
pti->size = SizeFromMemtype( pti->mem_type, pti->Ofssize, NULL );
|
|
}
|
|
*pi = i;
|
|
DebugMsg1(("GetQualifiedType: i=%u, memtype=%Xh, ptr=%u, far=%u, ofssize=%d, arbtype=%s:%X\n",
|
|
i, pti->mem_type, pti->is_ptr, pti->is_far, pti->Ofssize,
|
|
pti->symtype ? pti->symtype->name : "NULL",
|
|
pti->symtype ? pti->symtype->mem_type : 0 ));
|
|
return( NOT_ERROR );
|
|
}
|
|
|
|
/* TYPEDEF directive. Syntax is:
|
|
* <type name> TYPEDEF [proto|[far|near [ptr]]<qualified type>]
|
|
*/
|
|
ret_code TypedefDirective( int i, struct asm_tok tokenarray[] )
|
|
/*************************************************************/
|
|
{
|
|
struct asym *sym;
|
|
char *name;
|
|
struct qualified_type ti;
|
|
|
|
DebugMsg1(("TypedefDirective(%d) enter\n", i));
|
|
|
|
if( i != 1 ) {
|
|
return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) );
|
|
}
|
|
name = tokenarray[0].string_ptr;
|
|
|
|
i++; /* go past TYPEDEF */
|
|
|
|
sym = SymSearch( name );
|
|
if ( sym == NULL || sym->state == SYM_UNDEFINED ) {
|
|
sym = CreateTypeSymbol( sym, name, TRUE );
|
|
if ( sym == NULL )
|
|
return( ERROR );
|
|
#if TYPEOPT
|
|
/* release the structinfo data extension */
|
|
LclFree( ((struct dsym *)sym)->e.structinfo );
|
|
((struct dsym *)sym)->e.structinfo = NULL;
|
|
#endif
|
|
} else {
|
|
/* MASM allows to have the TYPEDEF included multiple times */
|
|
/* but the types must be identical! */
|
|
if ( ( sym->state != SYM_TYPE ) ||
|
|
( sym->typekind != TYPE_TYPEDEF &&
|
|
sym->typekind != TYPE_NONE ) ) {
|
|
return( EmitErr( SYMBOL_REDEFINITION, sym->name ) );
|
|
}
|
|
}
|
|
|
|
sym->isdefined = TRUE;
|
|
if ( Parse_Pass > PASS_1 )
|
|
return( NOT_ERROR );
|
|
sym->typekind = TYPE_TYPEDEF;
|
|
|
|
/* PROTO is special */
|
|
if ( tokenarray[i].token == T_DIRECTIVE && tokenarray[i].tokval == T_PROTO ) {
|
|
struct dsym *proto; /* create a PROTOtype item without name */
|
|
/* v2.04: added check if prototype is set already */
|
|
if ( sym->target_type == NULL && sym->mem_type == MT_EMPTY ) {
|
|
proto = (struct dsym *)CreateProc( NULL, "", SYM_TYPE );
|
|
DebugMsg1(("TypedefDirective PROTO, created new unnamed prototype %p\n", proto ));
|
|
} else if ( sym->mem_type == MT_PROC ) {
|
|
proto = (struct dsym *)sym->target_type;
|
|
} else {
|
|
return( EmitErr( SYMBOL_TYPE_CONFLICT, sym->name ) );
|
|
}
|
|
i++;
|
|
DebugMsg1(("TypedefDirective PROTO, call ParseProc(sym=%p i=%d, 0)\n", proto, i));
|
|
if( ParseProc( proto, i, tokenarray, FALSE, ModuleInfo.langtype ) == ERROR )
|
|
return ( ERROR );
|
|
DebugMsg1(("TypedefDirective PROTO, ParseProc() returned status ok\n"));
|
|
sym->mem_type = MT_PROC;
|
|
/* v2.11: member isproc was set inside ParseProc() */
|
|
//proto->sym.isproc = TRUE; /* v2.05: added */
|
|
sym->Ofssize = proto->sym.seg_ofssize;
|
|
/* v2.03: set value of field total_size (previously was 0) */
|
|
sym->total_size = ( 2 << sym->Ofssize );
|
|
if( proto->sym.mem_type != MT_NEAR ) {
|
|
sym->isfar = TRUE; /* v2.04: added */
|
|
sym->total_size += 2;
|
|
}
|
|
sym->target_type = (struct asym *)proto;
|
|
DebugMsg1(("TypedefDirective(%s) ok, mem_type=%Xh, ofssize=%u\n", sym->name, sym->mem_type, sym->Ofssize ));
|
|
return( NOT_ERROR );
|
|
}
|
|
ti.size = 0;
|
|
ti.is_ptr = 0;
|
|
ti.is_far = FALSE;
|
|
ti.mem_type = MT_EMPTY;
|
|
ti.ptr_memtype = MT_EMPTY;
|
|
ti.symtype = NULL;
|
|
ti.Ofssize = ModuleInfo.Ofssize;
|
|
|
|
/* "empty" type is ok for TYPEDEF */
|
|
if ( tokenarray[i].token == T_FINAL || tokenarray[i].token == T_COMMA )
|
|
;
|
|
else if ( GetQualifiedType( &i, tokenarray, &ti ) == ERROR )
|
|
return( ERROR );
|
|
|
|
/* if type did exist already, check for type conflicts
|
|
* v2.05: this code has been rewritten */
|
|
if ( sym->mem_type != MT_EMPTY ) {
|
|
struct asym *to;
|
|
struct asym *tn;
|
|
char oo;
|
|
char on;
|
|
for( tn = ti.symtype; tn && tn->type; tn = tn->type );
|
|
to = ( sym->mem_type == MT_TYPE ) ? sym->type : sym->target_type;
|
|
for( ; to && to->type; to = to->type );
|
|
oo = ( sym->Ofssize != USE_EMPTY ) ? sym->Ofssize : ModuleInfo.Ofssize;
|
|
on = ( ti.Ofssize != USE_EMPTY ) ? ti.Ofssize : ModuleInfo.Ofssize;
|
|
if ( ti.mem_type != sym->mem_type ||
|
|
( ti.mem_type == MT_TYPE && tn != to ) ||
|
|
( ti.mem_type == MT_PTR &&
|
|
( ti.is_far != sym->isfar ||
|
|
on != oo ||
|
|
ti.ptr_memtype != sym->ptr_memtype ||
|
|
tn != to ))) {
|
|
DebugMsg(("TypedefDirective: old-new memtype=%X-%X type=%X(%s)-%X(%s) far=%u-%u ind=%u-%u ofss=%d-%d pmt=%X-%X\n",
|
|
sym->mem_type, ti.mem_type,
|
|
(sym->mem_type == MT_TYPE) ? sym->type : sym->target_type,
|
|
(sym->mem_type == MT_TYPE) ? sym->type->name : sym->target_type ? sym->target_type->name : "",
|
|
ti.symtype, ti.symtype ? ti.symtype->name : "",
|
|
sym->isfar, ti.is_far,
|
|
sym->is_ptr, ti.is_ptr,
|
|
sym->Ofssize, ti.Ofssize,
|
|
sym->ptr_memtype, ti.ptr_memtype ));
|
|
return( EmitErr( SYMBOL_TYPE_CONFLICT, name ) );
|
|
}
|
|
}
|
|
|
|
sym->mem_type = ti.mem_type;
|
|
sym->Ofssize = ti.Ofssize;
|
|
sym->total_size = ti.size;
|
|
sym->is_ptr = ti.is_ptr;
|
|
sym->isfar = ti.is_far;
|
|
if ( ti.mem_type == MT_TYPE )
|
|
sym->type = ti.symtype;
|
|
else
|
|
sym->target_type = ti.symtype;
|
|
sym->ptr_memtype = ti.ptr_memtype;
|
|
DebugMsg1(("TypedefDirective(%s) ok, mem_type=MT_TYPE, size=%" I32_SPEC "u, type=%p type.memtype=%X\n",
|
|
sym->name, sym->total_size, sym->type, ti.symtype ? ti.symtype->mem_type : 0 ));
|
|
|
|
DebugMsg1(("TypedefDirective(%s) ok, mem_type=%Xh, size=%u, indirection=%u target=%p\n", sym->name, sym->mem_type, ti.size, ti.is_ptr, ti.symtype ));
|
|
|
|
if ( tokenarray[i].token != T_FINAL ) {
|
|
DebugMsg(("TypedefDirective: unexpected token %u, idx=%u\n", tokenarray[i].token, i));
|
|
return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) );
|
|
}
|
|
|
|
return( NOT_ERROR );
|
|
}
|
|
|
|
/* RECORD directive
|
|
* syntax: <label> RECORD <bitfield_name>:<size>[,...]
|
|
* defines a RECORD type (state=SYM_TYPE).
|
|
* the memtype will be MT_BYTE, MT_WORD, MT_DWORD [, MT_QWORD in 64-bit].
|
|
*/
|
|
|
|
ret_code RecordDirective( int i, struct asm_tok tokenarray[] )
|
|
/************************************************************/
|
|
{
|
|
char *name;
|
|
struct asym *sym;
|
|
struct dsym *newr;
|
|
struct dsym *oldr = NULL;
|
|
struct sfield *f;
|
|
int cntBits;
|
|
int define;
|
|
int len;
|
|
int redef_err;
|
|
int count;
|
|
//int value;
|
|
int name_loc;
|
|
int init_loc;
|
|
struct expr opndx;
|
|
|
|
DebugMsg1(("RecordDirective(%d) enter\n", i));
|
|
if ( i != 1 ) {
|
|
return( EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr ) );
|
|
}
|
|
|
|
name = tokenarray[0].string_ptr;
|
|
sym = SymSearch( name );
|
|
if ( sym == NULL || sym->state == SYM_UNDEFINED ) {
|
|
sym = CreateTypeSymbol( sym, name, TRUE );
|
|
} else if ( sym->state == SYM_TYPE &&
|
|
( sym->typekind == TYPE_RECORD ||
|
|
sym->typekind == TYPE_NONE ) ) {
|
|
/* v2.04: allow redefinition of record and forward references.
|
|
* the record redefinition may have different initial values,
|
|
* but those new values are IGNORED! ( Masm bug? )
|
|
*/
|
|
if ( Parse_Pass == PASS_1 && sym->typekind == TYPE_RECORD ) {
|
|
oldr = (struct dsym *)sym;
|
|
sym = CreateTypeSymbol( NULL, name, FALSE );
|
|
redef_err = 0;
|
|
}
|
|
} else {
|
|
return( EmitErr( SYMBOL_REDEFINITION, name ) );
|
|
}
|
|
sym->isdefined = TRUE;
|
|
|
|
if ( Parse_Pass > PASS_1 )
|
|
return( NOT_ERROR );
|
|
|
|
newr = (struct dsym *)sym;
|
|
newr->sym.typekind = TYPE_RECORD;
|
|
|
|
i++; /* go past RECORD */
|
|
|
|
cntBits = 0; /* counter for total of bits in record */
|
|
/* parse bitfields */
|
|
do {
|
|
if ( tokenarray[i].token != T_ID ) {
|
|
EmitErr( SYNTAX_ERROR_EX, tokenarray[i].string_ptr );
|
|
break;
|
|
}
|
|
len = strlen( tokenarray[i].string_ptr );
|
|
if( len > MAX_ID_LEN ) {
|
|
EmitError( IDENTIFIER_TOO_LONG );
|
|
break;
|
|
}
|
|
name_loc = i;
|
|
i++;
|
|
if ( tokenarray[i].token != T_COLON ) {
|
|
EmitError( COLON_EXPECTED );
|
|
break;
|
|
}
|
|
i++;
|
|
/* get width */
|
|
if ( EvalOperand( &i, tokenarray, Token_Count, &opndx, 0 ) == ERROR )
|
|
break;
|
|
if ( opndx.kind != EXPR_CONST ) {
|
|
EmitError( CONSTANT_EXPECTED );
|
|
opndx.value = 1;
|
|
}
|
|
if ( opndx.value == 0 ) {
|
|
EmitErr( TOO_FEW_BITS_IN_RECORD, tokenarray[name_loc].string_ptr );
|
|
break;
|
|
} else if ( ( opndx.value + cntBits ) > MAXRECBITS ) {
|
|
EmitErr( TOO_MANY_BITS_IN_RECORD, tokenarray[name_loc].string_ptr );
|
|
break;
|
|
}
|
|
count = 0;
|
|
/* is there an initializer? ('=') */
|
|
if ( tokenarray[i].token == T_DIRECTIVE &&
|
|
tokenarray[i].dirtype == DRT_EQUALSGN ) {
|
|
i++;
|
|
for( init_loc = i; tokenarray[i].token != T_FINAL && tokenarray[i].token != T_COMMA; i++ );
|
|
/* no value? */
|
|
if ( init_loc == i ) {
|
|
EmitErr( SYNTAX_ERROR_EX, tokenarray[name_loc].tokpos );
|
|
break;
|
|
}
|
|
/* v2.09: initial values of record redefinitions are ignored! */
|
|
if ( oldr == NULL )
|
|
count = tokenarray[i].tokpos - tokenarray[init_loc].tokpos;
|
|
}
|
|
/* record field names are global! (Masm design flaw) */
|
|
sym = SymSearch( tokenarray[name_loc].string_ptr );
|
|
define = TRUE;
|
|
if ( oldr ) {
|
|
if ( sym == NULL ||
|
|
sym->state != SYM_STRUCT_FIELD ||
|
|
sym->mem_type != MT_BITS ||
|
|
sym->total_size != opndx.value ) {
|
|
EmitErr( NON_BENIGN_XXX_REDEFINITION, szRecord, tokenarray[name_loc].string_ptr );
|
|
redef_err++;
|
|
define = FALSE; /* v2.06: added */
|
|
}
|
|
} else {
|
|
if ( sym ) {
|
|
EmitErr( SYMBOL_REDEFINITION, sym->name );
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( define ) { /* v2.06: don't add field if there was an error */
|
|
cntBits += opndx.value;
|
|
f = LclAlloc( sizeof( struct sfield ) + count );
|
|
memset( f, 0, sizeof( struct sfield ) );
|
|
f->sym.name_size = len;
|
|
f->sym.name = LclAlloc( len + 1 );
|
|
memcpy( f->sym.name, tokenarray[name_loc].string_ptr, len + 1 );
|
|
f->sym.list = ModuleInfo.cref;
|
|
f->sym.state = SYM_STRUCT_FIELD;
|
|
f->sym.mem_type = MT_BITS;
|
|
f->sym.total_size = opndx.value;
|
|
if ( !oldr ) {
|
|
SymAddGlobal( &f->sym );
|
|
}
|
|
f->next = NULL;
|
|
//f->sym = sym;
|
|
f->ivalue[0] = NULLC;
|
|
//f->init_dir = NULL;
|
|
if( newr->e.structinfo->head == NULL ) {
|
|
newr->e.structinfo->head = newr->e.structinfo->tail = f;
|
|
} else {
|
|
newr->e.structinfo->tail->next = f;
|
|
newr->e.structinfo->tail = f;
|
|
}
|
|
if ( count ) {
|
|
//f->value = LclAlloc( count + 1 );
|
|
memcpy( f->ivalue, tokenarray[init_loc].tokpos, count );
|
|
f->ivalue[count] = NULLC;
|
|
}
|
|
}
|
|
|
|
if ( i < Token_Count ) {
|
|
if ( tokenarray[i].token != T_COMMA || tokenarray[i+1].token == T_FINAL ) {
|
|
EmitErr( SYNTAX_ERROR_EX, tokenarray[i].tokpos );
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
} while ( i < Token_Count );
|
|
|
|
/* now calc size in bytes and set the bit positions */
|
|
|
|
if ( cntBits > 16 ) {
|
|
#if AMD64_SUPPORT
|
|
if ( cntBits > 32 ) {
|
|
newr->sym.total_size = sizeof( uint_64 );
|
|
newr->sym.mem_type = MT_QWORD;
|
|
} else {
|
|
#endif
|
|
newr->sym.total_size = sizeof( uint_32 );
|
|
newr->sym.mem_type = MT_DWORD;
|
|
#if AMD64_SUPPORT
|
|
}
|
|
#endif
|
|
} else if ( cntBits > 8 ) {
|
|
newr->sym.total_size = sizeof( uint_16 );
|
|
newr->sym.mem_type = MT_WORD;
|
|
} else {
|
|
newr->sym.total_size = sizeof( uint_8 );
|
|
newr->sym.mem_type = MT_BYTE;
|
|
}
|
|
/* if the BYTE/WORD/DWORD isn't used fully, shift bits to the right! */
|
|
// cntBits = dir->sym.total_size * 8;
|
|
|
|
/* set the bit position */
|
|
for ( f = newr->e.structinfo->head; f; f = f->next ) {
|
|
cntBits = cntBits - f->sym.total_size;
|
|
f->sym.offset = cntBits;
|
|
}
|
|
if ( oldr ) {
|
|
if ( redef_err > 0 ||
|
|
AreStructsEqual( newr, oldr ) == FALSE )
|
|
EmitErr( NON_BENIGN_XXX_REDEFINITION, szRecord, newr->sym.name );
|
|
/* record can be freed, because the record's fields are global items.
|
|
* And initial values of the new definition are ignored!
|
|
*/
|
|
SymFree( (struct asym *)newr );
|
|
}
|
|
DebugMsg(("RecordDirective(%s) exit, no error\n", name ));
|
|
return( NOT_ERROR );
|
|
}
|
|
|
|
void DeleteType( struct dsym *dir )
|
|
/*********************************/
|
|
{
|
|
struct sfield *curr;
|
|
struct sfield *next;
|
|
|
|
DebugMsg(("DeleteType(%s) enter, typekind=%u, memtype=%Xh\n", dir->sym.name, dir->sym.typekind, dir->sym.mem_type ));
|
|
#if FASTMEM==0
|
|
/* release prototype in target_type if typedef is PROTO */
|
|
if ( dir->sym.mem_type == MT_PROC ) {
|
|
/* v2.11: change the prototype type to an external, because SymFree()
|
|
* doesn't expect a prototype in a type.
|
|
*/
|
|
dir->sym.target_type->state = SYM_EXTERNAL;
|
|
SymFree( dir->sym.target_type );
|
|
}
|
|
#endif
|
|
#if TYPEOPT
|
|
if ( dir->sym.typekind == TYPE_TYPEDEF )
|
|
return;
|
|
#endif
|
|
/* bitfields field names are global, don't free them here! */
|
|
if ( dir->sym.typekind != TYPE_RECORD )
|
|
for( curr = dir->e.structinfo->head; curr != NULL; curr = next ) {
|
|
next = curr->next;
|
|
#if FASTMEM==0
|
|
if ( curr->sym.name_size ) LclFree( curr->sym.name );
|
|
#endif
|
|
LclFree( curr );
|
|
}
|
|
LclFree( dir->e.structinfo );
|
|
return;
|
|
}
|
|
|