📄 cdecl2.c
字号:
/****************************************************************************
*
* Open Watcom Project
*
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
* ========================================================================
*
* This file contains Original Code and/or Modifications of Original
* Code as defined in and that are subject to the Sybase Open Watcom
* Public License version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
* provided with the Original Code and Modifications, and is also
* available at www.sybase.com/developer/opensource.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
* NON-INFRINGEMENT. Please see the License for the specific language
* governing rights and limitations under the License.
*
* ========================================================================
*
* Description: WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
* DESCRIBE IT HERE!
*
****************************************************************************/
#include "cvars.h"
#include "toggle.h"
#include "pragdefn.h"
#include "cgswitch.h"
TYPEPTR *MakeParmList( struct parm_list *, int, int );
struct parm_list *NewParm( TYPEPTR, struct parm_list * );
static TYPEPTR DeclPart2( TYPEPTR typ, type_modifiers mod );
static TYPEPTR DeclPart3( TYPEPTR typ, type_modifiers mod );
static void AbsDecl( SYMPTR sym, type_modifiers mod, TYPEPTR typ );
local void FreeParmList( void );
local void GetFuncParmList( void );
static int ThreadSeg;
void Chk_Struct_Union_Enum( TYPEPTR typ )
{
while( typ->decl_type == TYPE_TYPEDEF ) { /* 24-nov-94 */
if( !(typ->type_flags & TF2_DUMMY_TYPEDEF) ) break;
typ = typ->object;
}
switch( typ->decl_type ) {
case TYPE_STRUCT:
case TYPE_UNION:
if( typ->u.tag->name[0] == '\0' ) {
InvDecl();
}
break;
case TYPE_ENUM:
break;
default:
InvDecl();
}
}
local void FlushBadCode()
{
int count;
CErr1( ERR_STMT_MUST_BE_INSIDE_FUNCTION );
count = 0;
for(;;) {
NextToken();
if( CurToken == T_EOF ) return;
if( CurToken == T_LEFT_BRACE ) ++count;
if( CurToken == T_RIGHT_BRACE ) {
if( count == 0 ) break;
--count;
}
}
NextToken();
}
static int SCSpecifier()
{
stg_classes stg_class;
stg_class = SC_NULL; /* assume no storage class specified */
if( TokenClass[ CurToken ] == TC_STG_CLASS ) {
switch( CurToken ) {
case T_EXTERN: stg_class = SC_EXTERN; break;
case T_STATIC: stg_class = SC_STATIC; break;
case T_TYPEDEF: stg_class = SC_TYPEDEF; break;
case T_AUTO: stg_class = SC_AUTO; break;
case T_REGISTER:stg_class = SC_REGISTER;break;
default:
break;
}
NextToken();
}
return( stg_class );
}
void InvDecl( void )
{
CErr1( ERR_INVALID_DECLARATOR );
}
#define FUNC_MASK (~(FLAG_INLINE | FLAG_LOADDS | FLAG_EXPORT | FLAG_LANGUAGES))
local void CmpFuncDecls( SYMPTR new_sym, SYMPTR old_sym )
{
TYPEPTR type_new, type_old;
if( (new_sym->attrib & FUNC_MASK) != (old_sym->attrib & FUNC_MASK)){
CErr2p( ERR_MODIFIERS_DISAGREE, new_sym->name );
}
/* check for conflicting information */
/* skip over TYPEDEF's 29-aug-89 */
type_new = new_sym->sym_type;
while( type_new->decl_type == TYPE_TYPEDEF ) type_new = type_new->object;
type_old = old_sym->sym_type;
while( type_old->decl_type == TYPE_TYPEDEF ) type_old = type_old->object;
SetDiagType2( type_new->object, type_old->object );
if( ! IdenticalType( type_new->object, type_old->object ) ) {
TYPEPTR ret_new, ret_old;
ret_new = type_new->object; /* save return types */
ret_old = type_old->object;
// skip over typedef's 18-may-95
while( ret_new->decl_type == TYPE_TYPEDEF ) ret_new = ret_new->object;
while( ret_old->decl_type == TYPE_TYPEDEF ) ret_old = ret_old->object;
/* don't reorder this expression */
if( old_sym->stg_class != SC_FORWARD ){
CErr2p( ERR_INCONSISTENT_TYPE, new_sym->name );
}else if( ret_new->decl_type != TYPE_VOID
|| (old_sym->flags & SYM_TYPE_GIVEN ) ){ //return value used in forward
CErr2p( ERR_INCONSISTENT_TYPE, new_sym->name );
}
}
SetDiagPop();
/* check types of parms, including promotion */
ChkCompatibleFunction(type_new, type_old, 1);
}
local SYM_HANDLE FuncDecl( SYMPTR sym, stg_classes stg_class, decl_state *state )
{
SYM_HANDLE sym_handle;
SYM_HANDLE old_sym_handle;
auto SYM_ENTRY old_sym;
auto struct enum_info ei;
auto SYM_ENTRY sym_typedef;
TYPEPTR old_typ;
SYM_NAMEPTR sym_name;
char *name;
int sym_len;
PrevProtoType = NULL; /* 12-may-91 */
// Warn if assuming 'int' return type - should be an error in strict C99 mode
if( *state & DECL_STATE_NOTYPE ) {
CWarn( WARN_NO_RET_TYPE_GIVEN, ERR_NO_RET_TYPE_GIVEN, sym->name );
}
sym->rent = FALSE; //Assume not override aka re-entrant
if( CompFlags.rent && (sym->declspec == DECLSPEC_DLLIMPORT) ){
sym->rent = TRUE;
}
if( stg_class == SC_REGISTER ||
stg_class == SC_AUTO ||
stg_class == SC_TYPEDEF ) {
CErr1( ERR_INVALID_STG_CLASS_FOR_FUNC );
stg_class = SC_NULL;
}
old_sym_handle = SymLook( sym->info.hash_value, sym->name );
if( old_sym_handle == 0 ) {
EnumLookup( sym->info.hash_value, sym->name, &ei );/* 22-dec-88 */
if( ei.level >= 0 ) { /* if enum was found */
CErr2p( ERR_SYM_ALREADY_DEFINED, sym->name );
}
sym_handle = SymAddL0( sym->info.hash_value, sym );
} else {
SymGet( &old_sym, old_sym_handle );
SetDiagSymbol( &old_sym, old_sym_handle );
if( (old_sym.flags & SYM_FUNCTION) == 0 ) {
CErr2p( ERR_SYM_ALREADY_DEFINED_AS_VAR, sym->name );
//02-jun-89 sym_handle = old_sym_handle; /* 05-apr-89 */
sym_handle = SymAddL0( sym->info.hash_value, sym );/* 02-jun-89 */
} else {
CmpFuncDecls( sym, &old_sym );
PrevProtoType = old_sym.sym_type; /* 12-may-91 */
if( (old_sym.flags & SYM_DEFINED) == 0 ) {
if( sym->sym_type->u.parms != NULL || /* 11-jul-89 */
( CurToken != T_COMMA && /* 18-jul-89 */
CurToken != T_SEMI_COLON ) ) {
old_typ = old_sym.sym_type;
if( old_typ->decl_type == TYPE_TYPEDEF &&
old_typ->object->decl_type == TYPE_FUNCTION ) {
SymGet( &sym_typedef, old_typ->u.typedefn );
sym_name = SymName( &sym_typedef,
old_typ->u.typedefn );
sym_len = far_strlen_plus1( sym_name );
name = CMemAlloc( sym_len );
far_memcpy( name, sym_name, sym_len );
XferPragInfo( name, sym->name );
CMemFree( name );
}
old_sym.sym_type = sym->sym_type;
old_sym.d.defn_line = sym->d.defn_line;
old_sym.defn_file_index = sym->defn_file_index;
}
}
if( (sym->attrib & FLAG_LANGUAGES) !=( old_sym.attrib & FLAG_LANGUAGES)){
// just inherit old lang flags
// if new != 0 then it's possible someone saw a different prototype
if( (sym->attrib & FLAG_LANGUAGES) != 0 ){
CErr2p( ERR_MODIFIERS_DISAGREE, sym->name );
}
}
if((sym->attrib & FLAG_INLINE) != (old_sym.attrib & FLAG_INLINE) ){
old_sym.attrib |= FLAG_INLINE; //either is inline
}
if( sym->declspec != old_sym.declspec ){
switch( sym->declspec ){
case DECLSPEC_DLLIMPORT:
case DECLSPEC_THREAD:
CErr2p( ERR_MODIFIERS_DISAGREE, sym->name );
break;
case DECLSPEC_DLLEXPORT:
if( old_sym.declspec == DECLSPEC_DLLIMPORT ){
old_sym.declspec = DECLSPEC_DLLEXPORT;
}else{
CErr2p( ERR_MODIFIERS_DISAGREE, sym->name );
}
break;
}
}
CMemFree( sym->name );
if( stg_class == SC_NULL && old_sym.stg_class != SC_FORWARD ){ /* 05-jul-89 */
stg_class = old_sym.stg_class;
}
memcpy( sym, &old_sym, sizeof( SYM_ENTRY ) );
sym_handle = old_sym_handle;
}
SetDiagPop();
}
sym->flags |= SYM_FUNCTION;
if( (sym->flags & SYM_DEFINED) == 0 ) {
if( sym->attrib & FLAG_INLINE ){
sym->flags |= SYM_IGNORE_UNREFERENCE;
stg_class = SC_STATIC;
}else if( stg_class == SC_NULL ){
stg_class = SC_EXTERN; /* SC_FORWARD; */
}
sym->stg_class = stg_class;
}
return( sym_handle );
}
TYPEPTR SkipDummyTypedef( TYPEPTR typ ) /* 25-nov-94 */
{
while( typ->decl_type == TYPE_TYPEDEF &&
(typ->type_flags & TF2_DUMMY_TYPEDEF) ) {
typ = typ->object;
}
return( typ );
}
#define QUAL_FLAGS (FLAG_CONST|FLAG_VOLATILE|FLAG_UNALIGNED)
#define ATTRIB_MASK (~(FLAG_INLINE | FLAG_LOADDS | FLAG_EXPORT | FLAG_LANGUAGES))
local SYM_HANDLE VarDecl( SYMPTR sym, stg_classes stg_class, decl_state *state )
{
int which;
TYPEPTR typ;
SYM_HANDLE sym_handle;
SYM_HANDLE old_sym_handle;
SYM_ENTRY old_sym;
SYM_ENTRY sym2;
// Warn if neither type nor storage class were given; this should probably be
// an error in strict C89 (and naturally C99) mode
if( (stg_class == SC_NULL) && (*state & DECL_STATE_NOTYPE) && !(*state & DECL_STATE_NOSTWRN) ) {
CWarn( WARN_NO_STG_OR_TYPE, ERR_NO_STG_OR_TYPE );
*state |= DECL_STATE_NOSTWRN; // Only warn once for each declarator list
}
// Additionally warn if assuming 'int' type - should be an error in strict C99 mode
if( *state & DECL_STATE_NOTYPE ) {
CWarn( WARN_NO_DATA_TYPE_GIVEN, ERR_NO_DATA_TYPE_GIVEN, sym->name );
}
if( CompFlags.rent ) {
sym->rent = TRUE; //Assume instance data
} else {
sym->rent = FALSE;//Assume non instance data
}
if( sym->naked ) { /* 25-jul-95 */
CErr1( ERR_INVALID_DECLSPEC );
}
if( SymLevel == 0 )
{
/*
// SymLevel == 0 is global scope (SymLevel is the count of nested {'s)
*/
if( stg_class == SC_AUTO || stg_class == SC_REGISTER ) {
CErr1( ERR_INV_STG_CLASS_FOR_GLOBAL );
stg_class = SC_STATIC;
} else if( stg_class == SC_NULL ) {
CompFlags.external_defn_found = 1;
}
if( sym->declspec == DECLSPEC_THREAD ) { /* 25-jul-95 */
if( !CompFlags.thread_data_present ){
ThreadSeg = DefThreadSeg();
CompFlags.thread_data_present = 1;
}
sym->u.var.segment = ThreadSeg;
}
}
else
{
/*
// SymLevel != 0 is function scoped (SymLevel is the count of nested {'s)
*/
if( stg_class == SC_NULL ) {
stg_class = SC_AUTO;
}
if( stg_class == SC_AUTO || stg_class == SC_REGISTER ) {
if( sym->attrib & FLAG_LANGUAGES ){
CErr1( ERR_INVALID_DECLARATOR );
}
if( sym->declspec != DECLSPEC_NONE ) { /* 25-jul-95 */
CErr1( ERR_INVALID_DECLSPEC );
}
/*
// Local variables in stack will be far when SS != DS (/zu)
// (applies only to auto vars, functions params are handled
// NOT here but in "cexpr2.c" [OPR_PUSHADDR])
*/
if( TargetSwitches & FLOATING_SS ) {
sym->attrib |= FLAG_FAR;
}
}
/*
// static class variables can be thread local also
*/
if( (stg_class == SC_STATIC) && (sym->declspec == DECLSPEC_THREAD) ) { /* 06-JAN-03 */
if( !CompFlags.thread_data_present ){
ThreadSeg = DefThreadSeg();
CompFlags.thread_data_present = 1;
}
sym->u.var.segment = ThreadSeg;
}
}
if( (Toggles & TOGGLE_UNREFERENCED) == 0 ) {
sym->flags |= SYM_IGNORE_UNREFERENCE; /* 25-apr-91 */
}
old_sym_handle = SymLook( sym->info.hash_value, sym->name );
if( old_sym_handle != 0 ) { /* 28-feb-94 */
SymGet( &old_sym, old_sym_handle );
if( old_sym.level == SymLevel ) {
if( old_sym.stg_class == SC_EXTERN && stg_class == SC_EXTERN ) {
SetDiagSymbol( &old_sym, old_sym_handle );
if( ! IdenticalType( old_sym.sym_type, sym->sym_type ) ) {
CErr2p( ERR_TYPE_DOES_NOT_AGREE, sym->name );
}
SetDiagPop();
}
}
}
if( stg_class == SC_EXTERN ) { /* 27-oct-88 */
old_sym_handle = Sym0Look( sym->info.hash_value, sym->name );
}
if( old_sym_handle != 0 ) {
SymGet( &old_sym, old_sym_handle );
SetDiagSymbol( &old_sym, old_sym_handle );
if( old_sym.level == SymLevel /* 28-mar-88 */
|| stg_class == SC_EXTERN ) { /* 12-dec-88 */
if( (sym->attrib & ATTRIB_MASK) !=
(old_sym.attrib & ATTRIB_MASK) ) {
CErr2p( ERR_MODIFIERS_DISAGREE, sym->name );
}
if( (sym->attrib & FLAG_LANGUAGES) !=( old_sym.attrib & FLAG_LANGUAGES)){
// just inherit old lang flags
// if new != 0 then it's possible someone saw a different prototype
if( (sym->attrib & FLAG_LANGUAGES) != 0 ){
CErr2p( ERR_MODIFIERS_DISAGREE, sym->name );
}
}
if( sym->declspec != old_sym.declspec ){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -