char *cpp_operator(int *poper,type **pt) { int i; type *typ_spec; char *s; *pt = NULL; stoken(); /* skip over operator keyword */ for (i = 0; i < arraysize(oparray); i++) { if (oparray[i].tokn == tok.TKval) goto L1; } /* Look for type conversion */ if (type_specifier(&typ_spec)) { type *t; t = ptr_operator(typ_spec); // parse ptr-operator fixdeclar(t); type_free(typ_spec); *pt = t; return cpp_typetostring(t,"?B"); } cpperr(EM_not_overloadable); // that token cannot be overloaded s = "_"; goto L2; L1: s = oparray[i].string; *poper = oparray[i].oper; switch (*poper) { case OPcall: if (stoken() != TKrpar) synerr(EM_rpar); /* ')' expected */ break; case OPbrack: if (stoken() != TKrbra) synerr(EM_rbra); /* ']' expected */ break; case OPnew: if (stoken() != TKlbra) goto Lret; *poper = OPanew; // operator new[] s = cpp_name_anew; goto L3; case OPdelete: if (stoken() != TKlbra) goto Lret; *poper = OPadelete; // operator delete[] s = cpp_name_adelete; L3: if (stoken() != TKrbra) synerr(EM_rbra); // ']' expected if (!(config.flags4 & CFG4anew)) { cpperr(EM_enable_anew); // throw -Aa to support this config.flags4 |= CFG4anew; } break; } L2: stoken(); Lret: return s; }
bool jmp( expr_list *opndx, int *flags ) /* determine the displacement of jmp; */ { int_32 addr; enum fixup_types fixup_type; enum fixup_options fixup_option; enum sym_state state; struct asm_sym *sym; #if defined( _STANDALONE_ ) dir_node *seg; #endif *flags = 0; Code->data[Opnd_Count] = opndx->value; sym = opndx->sym; if( sym == NULL ) { if( Code->info.token == T_CALL ) { Code->info.token = T_CALLF; } else if( Code->info.token == T_JMP ) { Code->info.token = T_JMPF; } if( Code->data[Opnd_Count] > USHRT_MAX ) Code->info.opnd_type[Opnd_Count] = OP_I32; else Code->info.opnd_type[Opnd_Count] = OP_I16; return( RC_OK ); } #if defined( _STANDALONE_ ) if( sym->mem_type == MT_ERROR ) { AsmError( LABEL_NOT_DEFINED ); return( RC_ERROR ); } #endif state = sym->state; #if defined( _STANDALONE_ ) seg = GetSeg( sym ); if( seg == NULL || CurrSeg == NULL || CurrSeg->seg != seg ) { /* jumps to another segment are just like to another file */ state = SYM_EXTERNAL; } #endif if( !Code->mem_type_fixed ) { Code->mem_type = MT_EMPTY; } fixup_option = OPTJ_NONE; fixup_type = FIX_RELOFF8; switch( state ) { case SYM_INTERNAL: #if defined( _STANDALONE_ ) case SYM_PROC: #endif if( ( Code->mem_type == MT_EMPTY || Code->mem_type == MT_SHORT || Code->mem_type == MT_NEAR ) && sym->mem_type != MT_WORD && sym->mem_type != MT_DWORD && sym->mem_type != MT_FWORD && !IS_JMPCALLF( Code->info.token ) ) { #if defined( _STANDALONE_ ) if( ( Code->info.token == T_CALL ) && ( Code->mem_type == MT_EMPTY ) && ( sym->mem_type == MT_FAR ) ) { FarCallToNear(); *flags = SCRAP_INSTRUCTION; return( RC_OK ); } addr = sym->offset; #else addr = sym->addr; #endif addr -= ( AsmCodeAddress + 2 ); // calculate the displacement addr += Code->data[Opnd_Count]; switch( Code->info.token ) { case T_JCXZ: case T_LOOPW: case T_LOOPEW: case T_LOOPZW: case T_LOOPNEW: case T_LOOPNZW: if( Code->use32 ) { // 1 extra byte for OPNSIZ addr--; } break; case T_JECXZ: case T_LOOPD: case T_LOOPED: case T_LOOPZD: case T_LOOPNED: case T_LOOPNZD: if( !Code->use32 ) { // 1 extra byte for OPNSIZ addr--; } break; } if( Code->info.token == T_CALL && Code->mem_type == MT_EMPTY ) { Code->mem_type = MT_NEAR; } if( Code->mem_type != MT_NEAR && Code->info.token != T_CALL && ( addr >= SCHAR_MIN && addr <= SCHAR_MAX ) ) { Code->info.opnd_type[Opnd_Count] = OP_I8; } else { /* near jmp */ if( Code->use32 ) { Code->info.opnd_type[Opnd_Count] = OP_I32; addr -= 3; // 32 bit displacement } else { Code->info.opnd_type[Opnd_Count] = OP_I16; addr -= 1; // 16 bit displacement } if( IS_JMP( Code->info.token ) ) { switch( Code->info.token ) { case T_JMP: case T_JMPF: case T_JCXZ: case T_JECXZ: break; default: // 1 extra byte for opcode ( 0F ) addr--; break; } } } /* store the displacement */ Code->data[Opnd_Count] = addr; switch( Code->info.token ) { case T_JCXZ: case T_JECXZ: case T_LOOP: case T_LOOPE: case T_LOOPNE: case T_LOOPNZ: case T_LOOPZ: case T_LOOPD: case T_LOOPED: case T_LOOPNED: case T_LOOPNZD: case T_LOOPZD: case T_LOOPW: case T_LOOPEW: case T_LOOPNEW: case T_LOOPNZW: case T_LOOPZW: #if defined( _STANDALONE_ ) if( !PhaseError && (Code->info.opnd_type[Opnd_Count] != OP_I8) ) { #else if( (Code->info.opnd_type[Opnd_Count] != OP_I8) ) { #endif AsmError( JUMP_OUT_OF_RANGE ); return( RC_ERROR ); } Code->info.opnd_type[Opnd_Count] = OP_I8; break; } if( (Code->info.cpu&P_CPU_MASK) < P_386 && IS_JMP( Code->info.token ) ) { /* look into jump extension */ switch( Code->info.token ) { case T_JMP: case T_JMPF: break; default: if( Code->info.opnd_type[Opnd_Count] != OP_I8 ) { #if defined( _STANDALONE_ ) if( Code->mem_type == MT_EMPTY ) { jumpExtend( 0 ); *flags = SCRAP_INSTRUCTION; return( RC_OK ); } else if( !PhaseError ) { AsmError( JUMP_OUT_OF_RANGE ); return( RC_ERROR ); } #else AsmError( JUMP_OUT_OF_RANGE ); return( RC_ERROR ); #endif } } } break; } /* otherwise fall through & get handled like external symbols */ case SYM_UNDEFINED: case SYM_EXTERNAL: /* forward ref, or external symbol */ if( Code->mem_type == MT_EMPTY && sym->mem_type != MT_EMPTY ) { switch( sym->mem_type ) { case MT_FAR: if( Code->info.token == T_CALL ) { Code->info.token = T_CALLF; } else if( Code->info.token == T_JMP ) { Code->info.token = T_JMPF; } // fall through case MT_SHORT: case MT_NEAR: Code->mem_type = sym->mem_type; break; #if defined( _STANDALONE_ ) case MT_PROC: if( IS_PROC_FAR() ) { Code->mem_type = MT_FAR; if( Code->info.token == T_CALL ) { Code->info.token = T_CALLF; } else if( Code->info.token == T_JMP ) { Code->info.token = T_JMPF; } } else { Code->mem_type = MT_NEAR; } break; #endif case MT_FWORD: if( ptr_operator( MT_FWORD, TRUE ) ) return( RC_ERROR ); break; default: Code->mem_type = sym->mem_type; } } if( Code->mem_type == MT_FAR ) { if( Code->info.token == T_CALL ) { Code->info.token = T_CALLF; } else if( Code->info.token == T_JMP ) { Code->info.token = T_JMPF; } } switch( Code->info.token ) { case T_CALLF: case T_JMPF: switch( Code->mem_type ) { case MT_SHORT: case MT_NEAR: if( Opnd_Count == OPND1 && Code->mem_type_fixed ) { AsmError( CANNOT_USE_SHORT_OR_NEAR ); return( RC_ERROR ); } /* fall through */ case MT_FAR: case MT_EMPTY: #if defined( _STANDALONE_ ) SET_OPSIZ( Code, SymIs32( sym )); find_frame( sym ); #endif if( Opnd_Count == OPND2 ) { if( IS_OPSIZ_32( Code ) ) { fixup_type = FIX_OFF32; Code->info.opnd_type[Opnd_Count] = OP_I32; } else { fixup_type = FIX_OFF16; Code->info.opnd_type[Opnd_Count] = OP_I16; } } else { if( IS_OPSIZ_32( Code ) ) { fixup_type = FIX_PTR32; Code->info.opnd_type[Opnd_Count] = OP_J48; } else { fixup_type = FIX_PTR16; Code->info.opnd_type[Opnd_Count] = OP_J32; } } break; case MT_BYTE: case MT_WORD: #if defined( _STANDALONE_ ) case MT_SBYTE: case MT_SWORD: #endif AsmError( INVALID_SIZE ); return( RC_ERROR ); case MT_DWORD: case MT_FWORD: #if defined( _STANDALONE_ ) case MT_SDWORD: #endif *flags = INDIRECT_JUMP; return( RC_OK ); case MT_QWORD: case MT_TBYTE: case MT_OWORD: AsmError( INVALID_SIZE ); return( RC_ERROR ); } break; case T_CALL: if( Code->mem_type == MT_SHORT ) { AsmError( CANNOT_USE_SHORT_WITH_CALL ); return( RC_ERROR ); } else if( Code->mem_type == MT_EMPTY ) { #if defined( _STANDALONE_ ) fixup_option = OPTJ_CALL; #else fixup_option = OPTJ_NONE; #endif if( Code->use32 ) { fixup_type = FIX_RELOFF32; Code->info.opnd_type[Opnd_Count] = OP_I32; } else { fixup_type = FIX_RELOFF16; Code->info.opnd_type[Opnd_Count] = OP_I16; } break; } /* fall through */ case T_JMP: switch( Code->mem_type ) { case MT_SHORT: fixup_option = OPTJ_EXPLICIT; fixup_type = FIX_RELOFF8; Code->info.opnd_type[Opnd_Count] = OP_I8; break; case MT_FAR: AsmError( SYNTAX_ERROR ); break; case MT_EMPTY: // forward reference // inline assembler jmp default distance is near // stand-alone assembler jmp default distance is short fixup_option = OPTJ_NONE; #if defined( _STANDALONE_ ) /* guess short if JMP, we will expand later if needed */ fixup_type = FIX_RELOFF8; Code->info.opnd_type[Opnd_Count] = OP_I8; #else if( Code->use32 ) { fixup_type = FIX_RELOFF32; Code->info.opnd_type[Opnd_Count] = OP_I32; } else { fixup_type = FIX_RELOFF16; Code->info.opnd_type[Opnd_Count] = OP_I16; } #endif break; case MT_NEAR: fixup_option = OPTJ_EXPLICIT; if( Code->use32 ) { fixup_type = FIX_RELOFF32; Code->info.opnd_type[Opnd_Count] = OP_I32; } else { fixup_type = FIX_RELOFF16; Code->info.opnd_type[Opnd_Count] = OP_I16; } break; case MT_DWORD: case MT_WORD: #if defined( _STANDALONE_ ) case MT_SDWORD: case MT_SWORD: #endif *flags = INDIRECT_JUMP; return( RC_OK ); #if defined( _STANDALONE_ ) case MT_SBYTE: #endif case MT_BYTE: case MT_FWORD: case MT_QWORD: case MT_TBYTE: case MT_OWORD: AsmError( INVALID_SIZE ); return( RC_ERROR ); } // check_assume( sym, PREFIX_EMPTY ); break; case T_JCXZ: case T_JECXZ: // JCXZ and JECXZ always require SHORT label case T_LOOP: case T_LOOPE: case T_LOOPNE: case T_LOOPNZ: case T_LOOPZ: case T_LOOPD: case T_LOOPED: case T_LOOPNED: case T_LOOPNZD: case T_LOOPZD: case T_LOOPW: case T_LOOPEW: case T_LOOPNEW: case T_LOOPNZW: case T_LOOPZW: #if defined( _STANDALONE_ ) if( ( Code->mem_type != MT_EMPTY ) && ( Code->mem_type != MT_SHORT ) && ( (Options.mode & MODE_IDEAL) == 0 ) ) { #else if( ( Code->mem_type != MT_EMPTY ) && ( Code->mem_type != MT_SHORT ) ) { #endif AsmError( ONLY_SHORT_DISPLACEMENT_IS_ALLOWED ); return( RC_ERROR ); } Code->info.opnd_type[Opnd_Count] = OP_I8; fixup_option = OPTJ_EXPLICIT; fixup_type = FIX_RELOFF8; break; default: if( (Code->info.cpu&P_CPU_MASK) >= P_386 ) { switch( Code->mem_type ) { case MT_SHORT: fixup_option = OPTJ_EXPLICIT; fixup_type = FIX_RELOFF8; Code->info.opnd_type[Opnd_Count] = OP_I8; break; case MT_EMPTY: // forward reference // inline assembler default distance is near // stand-alone assembler default distance is short #if defined( _STANDALONE_ ) fixup_option = OPTJ_JXX; fixup_type = FIX_RELOFF8; Code->info.opnd_type[Opnd_Count] = OP_I8; break; #endif case MT_NEAR: fixup_option = OPTJ_EXPLICIT; if( Code->use32 ) { fixup_type = FIX_RELOFF32; Code->info.opnd_type[Opnd_Count] = OP_I32; } else { fixup_type = FIX_RELOFF16; Code->info.opnd_type[Opnd_Count] = OP_I16; } break; case MT_FAR: #if defined( _STANDALONE_ ) jumpExtend( 1 ); *flags = SCRAP_INSTRUCTION; return( RC_OK ); #endif default: AsmError( ONLY_SHORT_AND_NEAR_DISPLACEMENT_IS_ALLOWED ); return( RC_ERROR ); } } else { // the only mode in 8086, 80186, 80286 is // Jxx SHORT switch( Code->mem_type ) { case MT_EMPTY: #if defined( _STANDALONE_ ) fixup_option = OPTJ_EXTEND; fixup_type = FIX_RELOFF8; Code->info.opnd_type[Opnd_Count] = OP_I8; break; #endif case MT_SHORT: fixup_option = OPTJ_EXPLICIT; fixup_type = FIX_RELOFF8; Code->info.opnd_type[Opnd_Count] = OP_I8; break; default: AsmError( ONLY_SHORT_DISPLACEMENT_IS_ALLOWED ); return( RC_ERROR ); } } } AddFixup( sym, fixup_type, fixup_option ); break; default: /* SYM_STACK */ AsmError( NO_JUMP_TO_AUTO ); return( RC_ERROR ); } return( RC_OK ); } bool ptr_operator( memtype mem_type, bool fix_mem_type ) /******************************************************/ /* determine what should be done with SHORT, NEAR, FAR, BYTE, WORD, DWORD, PTR operator; */ { /* new idea: * when we get a near/far/dword/etc, just set distance / mem_type * operator will be called again with PTR, then we set the opsiz, etc. */ if( Code->info.token == T_LEA ) return( RC_OK ); if( Code->info.token == T_SMSW ) return( RC_OK ); if( mem_type == MT_PTR ) { /* finish deciding what type to make the inst NOW * ie: decide size overrides etc. */ if( Code->use32 && MEM_TYPE( Code->mem_type, WORD ) ) { // if we are in use32 mode, we have to add OPSIZ prefix for // most of the 386 instructions ( except MOVSX and MOVZX ) // when we find WORD PTR if( !IS_BRANCH( Code->info.token ) ) { if( Code->info.opnd_type[OPND1] == OP_MMX ) { /* JBS 2001/02/19 no WORD operands for MMX instructions, only 64-bit or 128-bit so no WORD override needed */ } else { switch( Code->info.token ) { case T_MOVSX: case T_MOVZX: break; default: SET_OPSIZ_ON( Code ); break; } } } } else if( !Code->use32 && MEM_TYPE( Code->mem_type, DWORD ) ) { /* if we are not in use32 mode, we have to add OPSIZ * when we find DWORD PTR * unless we have a LXS ins. * which moves a DWORD ptr into SR:word reg * fixme - can this be done by breaking up the LXS instructions in * asmins.h, and then putting F_32 or F_16 to append * opsize bytes when necessary ? */ if( !IS_BRANCH( Code->info.token ) ) { if( Code->info.opnd_type[OPND1] == OP_MMX ) { /* JBS 2001/02/19 no WORD operands for MMX instructions, only 64-bit or 128-bit so no DWORD override needed */ } else { switch( Code->info.token ) { case T_LDS: case T_LES: case T_LFS: case T_LGS: case T_LSS: /* in these cases, opsize does NOT need to be changed */ break; default: // OPSIZ prefix SET_OPSIZ_ON( Code ); } } } } } else { if( ( mem_type != MT_EMPTY ) && ( Code->mem_type_fixed == FALSE ) ) { #if defined( _STANDALONE_ ) if( mem_type != MT_STRUCT ) { #endif Code->mem_type = mem_type; if( fix_mem_type ) { Code->mem_type_fixed = TRUE; if( mem_type == MT_FAR ) { if( Code->info.token == T_CALL ) { Code->info.token = T_CALLF; } else if( Code->info.token == T_JMP ) { Code->info.token = T_JMPF; } } } #if defined( _STANDALONE_ ) } #endif } } return( RC_OK ); }