/*
 * 68K/386 32-bit C compiler.
 *
 * copyright (c) 1997, David Lindauer
 * 
 * This compiler is intended for educational use.  It may not be used
 * for profit without the express written consent of the author.
 *
 * It may be freely redistributed, as long as this notice remains intact
 * and either the original sources or derived sources 
 * are distributed along with any executables derived from the originals.
 *
 * The author is not responsible for any damages that may arise from use
 * of this software, either idirect or consequential.
 *
 * V2.05 June 2002
 * David Lindauer, camille@bluegrass.net
 *
 * Credits to Mathew Brandt for original K&R C compiler
 *
 */
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include        "lists.h"
#include "expr.h"
#include "c.h"
#include "gen386.h"
#include "diag.h"
#include "lists.h"

extern LIST *libincludes;
extern int prm_nodos;
extern char outfile[];
extern int prm_flat, prm_optmult;
extern SYM *currentfunc;
extern int prm_cmangle;
extern HASHREC **gsyms;
extern int phiused;
extern long nextlabel;
extern FILE *outputFile;
extern int global_flag;
extern LIST *localfuncs ;
extern OPCODE popn_aaa; 
extern OPCODE popn_aad; 
extern OPCODE popn_aam; 
extern OPCODE popn_aas; 
extern OPCODE popn_add; 
extern OPCODE popn_adc; 
extern OPCODE popn_and; 
extern OPCODE popn_arpl; 
extern OPCODE popn_bound; 
extern OPCODE popn_bsf; 
extern OPCODE popn_bsr; 
extern OPCODE popn_bswap; 
extern OPCODE popn_btc; 
extern OPCODE popn_bt; 
extern OPCODE popn_btr; 
extern OPCODE popn_bts; 
extern OPCODE popn_call; 
extern OPCODE popn_cbw; 
extern OPCODE popn_cwde; 
extern OPCODE popn_cwd; 
extern OPCODE popn_cdq; 
extern OPCODE popn_clc; 
extern OPCODE popn_cld; 
extern OPCODE popn_cli; 
extern OPCODE popn_clts; 
extern OPCODE popn_cmc; 
extern OPCODE popn_cmp; 
extern OPCODE popn_cmps; 
extern OPCODE popn_cmpsb; 
extern OPCODE popn_cmpsw; 
extern OPCODE popn_cmpsd; 
extern OPCODE popn_daa; 
extern OPCODE popn_das; 
extern OPCODE popn_dec; 
extern OPCODE popn_div; 
extern OPCODE popn_enter; 
extern OPCODE popn_hlt; 
extern OPCODE popn_idiv; 
extern OPCODE popn_imul; 
extern OPCODE popn_in; 
extern OPCODE popn_inc; 
extern OPCODE popn_ins; 
extern OPCODE popn_insb; 
extern OPCODE popn_insw; 
extern OPCODE popn_insd; 
extern OPCODE popn_int; 
extern OPCODE popn_int3; 
extern OPCODE popn_into; 
extern OPCODE popn_invd; 
extern OPCODE popn_iret; 
extern OPCODE popn_iretd; 
extern OPCODE popn_jcxz; 
extern OPCODE popn_ja; 
extern OPCODE popn_jnbe; 
extern OPCODE popn_jae; 
extern OPCODE popn_jnb; 
extern OPCODE popn_jnc; 
extern OPCODE popn_jb; 
extern OPCODE popn_jc; 
extern OPCODE popn_jnae; 
extern OPCODE popn_jbe; 
extern OPCODE popn_jna; 
extern OPCODE popn_je; 
extern OPCODE popn_jz; 
extern OPCODE popn_jg; 
extern OPCODE popn_jnle; 
extern OPCODE popn_jl; 
extern OPCODE popn_jnge; 
extern OPCODE popn_jge; 
extern OPCODE popn_jnl; 
extern OPCODE popn_jle; 
extern OPCODE popn_jng; 
extern OPCODE popn_jne; 
extern OPCODE popn_jnz; 
extern OPCODE popn_jo; 
extern OPCODE popn_jno; 
extern OPCODE popn_jp; 
extern OPCODE popn_jnp; 
extern OPCODE popn_jpe; 
extern OPCODE popn_jpo; 
extern OPCODE popn_js; 
extern OPCODE popn_jns; 
extern OPCODE popn_jmp; 
extern OPCODE popn_lahf; 
extern OPCODE popn_lar; 
extern OPCODE popn_lds; 
extern OPCODE popn_les; 
extern OPCODE popn_lfs; 
extern OPCODE popn_lgs; 
extern OPCODE popn_lss; 
extern OPCODE popn_lea; 
extern OPCODE popn_leave; 
extern OPCODE popn_lgdt; 
extern OPCODE popn_lidt; 
extern OPCODE popn_lldt; 
extern OPCODE popn_lmsw; 
extern OPCODE popn_lock; 
extern OPCODE popn_lods; 
extern OPCODE popn_lodsb; 
extern OPCODE popn_lodsw; 
extern OPCODE popn_lodsd; 
extern OPCODE popn_loop; 
extern OPCODE popn_loope; 
extern OPCODE popn_loopz; 
extern OPCODE popn_loopne; 
extern OPCODE popn_loopnz; 
extern OPCODE popn_lsl; 
extern OPCODE popn_ltr; 
extern OPCODE popn_mov; 
extern OPCODE popn_movs; 
extern OPCODE popn_movsb; 
extern OPCODE popn_movsw; 
extern OPCODE popn_movsd; 
extern OPCODE popn_movsx; 
extern OPCODE popn_movzx; 
extern OPCODE popn_mul; 
extern OPCODE popn_neg; 
extern OPCODE popn_not; 
extern OPCODE popn_nop; 
extern OPCODE popn_or; 
extern OPCODE popn_out; 
extern OPCODE popn_outs; 
extern OPCODE popn_outsb; 
extern OPCODE popn_outsw; 
extern OPCODE popn_outsd; 
extern OPCODE popn_pop; 
extern OPCODE popn_popa; 
extern OPCODE popn_popad; 
extern OPCODE popn_popf; 
extern OPCODE popn_popfd; 
extern OPCODE popn_push; 
extern OPCODE popn_pusha; 
extern OPCODE popn_pushad; 
extern OPCODE popn_pushf; 
extern OPCODE popn_pushfd; 
extern OPCODE popn_rcl; 
extern OPCODE popn_rcr; 
extern OPCODE popn_rdtsc ;
extern OPCODE popn_rol; 
extern OPCODE popn_ror; 
extern OPCODE popn_repnz; 
extern OPCODE popn_repz; 
extern OPCODE popn_ret; 
extern OPCODE popn_retf; 
extern OPCODE popn_sahf; 
extern OPCODE popn_sal; 
extern OPCODE popn_sar; 
extern OPCODE popn_shl; 
extern OPCODE popn_shr; 
extern OPCODE popn_sbb; 
extern OPCODE popn_scas; 
extern OPCODE popn_scasb; 
extern OPCODE popn_scasw; 
extern OPCODE popn_scasd; 
extern OPCODE popn_seta; 
extern OPCODE popn_setnbe; 
extern OPCODE popn_setae; 
extern OPCODE popn_setnb; 
extern OPCODE popn_setnc; 
extern OPCODE popn_setb; 
extern OPCODE popn_setc; 
extern OPCODE popn_setnae; 
extern OPCODE popn_setbe; 
extern OPCODE popn_setna; 
extern OPCODE popn_sete; 
extern OPCODE popn_setz; 
extern OPCODE popn_setg; 
extern OPCODE popn_setnle; 
extern OPCODE popn_setl; 
extern OPCODE popn_setnge; 
extern OPCODE popn_setge; 
extern OPCODE popn_setnl; 
extern OPCODE popn_setle; 
extern OPCODE popn_setng; 
extern OPCODE popn_setne; 
extern OPCODE popn_setnz; 
extern OPCODE popn_seto; 
extern OPCODE popn_setno; 
extern OPCODE popn_setp; 
extern OPCODE popn_setnp; 
extern OPCODE popn_setpe; 
extern OPCODE popn_setpo; 
extern OPCODE popn_sets; 
extern OPCODE popn_setns; 
extern OPCODE popn_sgdt; 
extern OPCODE popn_sidt; 
extern OPCODE popn_sldt; 
extern OPCODE popn_smsw; 
extern OPCODE popn_shld; 
extern OPCODE popn_shrd; 
extern OPCODE popn_stc; 
extern OPCODE popn_std; 
extern OPCODE popn_sti; 
extern OPCODE popn_stos; 
extern OPCODE popn_stosb; 
extern OPCODE popn_stosw; 
extern OPCODE popn_stosd; 
extern OPCODE popn_str; 
extern OPCODE popn_sub; 
extern OPCODE popn_test; 
extern OPCODE popn_verr; 
extern OPCODE popn_verw; 
extern OPCODE popn_wait; 
extern OPCODE popn_wbinvd; 
extern OPCODE popn_xchg; 
extern OPCODE popn_xlat; 
extern OPCODE popn_xlatb; 
extern OPCODE popn_xor; 
extern OPCODE popn_f2xm1; 
extern OPCODE popn_fabs; 
extern OPCODE popn_fadd; 
extern OPCODE popn_faddp; 
extern OPCODE popn_fiadd; 
extern OPCODE popn_fchs; 
extern OPCODE popn_fclex; 
extern OPCODE popn_fnclex; 
extern OPCODE popn_fcom; 
extern OPCODE popn_fcomp; 
extern OPCODE popn_fcompp; 
extern OPCODE popn_fcos; 
extern OPCODE popn_fdecstp; 
extern OPCODE popn_fdiv; 
extern OPCODE popn_fdivp; 
extern OPCODE popn_fidiv; 
extern OPCODE popn_fdivr; 
extern OPCODE popn_fdivrp; 
extern OPCODE popn_fidivr; 
extern OPCODE popn_ffree; 
extern OPCODE popn_ficom; 
extern OPCODE popn_ficomp; 
extern OPCODE popn_fild; 
extern OPCODE popn_fincstp; 
extern OPCODE popn_finit; 
extern OPCODE popn_fninit; 
extern OPCODE popn_fist; 
extern OPCODE popn_fistp; 
extern OPCODE popn_fld; 
extern OPCODE popn_fldz; 
extern OPCODE popn_fldpi; 
extern OPCODE popn_fld1; 
extern OPCODE popn_fldl2t; 
extern OPCODE popn_fldl2e; 
extern OPCODE popn_fldlg2; 
extern OPCODE popn_fldln2; 
extern OPCODE popn_fldcw; 
extern OPCODE popn_fldenv; 
extern OPCODE popn_fmul; 
extern OPCODE popn_fmulp; 
extern OPCODE popn_fimul; 
extern OPCODE popn_fpatan; 
extern OPCODE popn_fprem; 
extern OPCODE popn_fprem1; 
extern OPCODE popn_fptan; 
extern OPCODE popn_frndint; 
extern OPCODE popn_frstor; 
extern OPCODE popn_fsave; 
extern OPCODE popn_fnsave; 
extern OPCODE popn_fscale; 
extern OPCODE popn_fsin; 
extern OPCODE popn_fsincos; 
extern OPCODE popn_fsqrt; 
extern OPCODE popn_fst; 
extern OPCODE popn_fstp; 
extern OPCODE popn_fstcw; 
extern OPCODE popn_fstsw; 
extern OPCODE popn_fnstcw; 
extern OPCODE popn_fnstsw; 
extern OPCODE popn_fstenv; 
extern OPCODE popn_fnstenv; 
extern OPCODE popn_fsub; 
extern OPCODE popn_fsubp; 
extern OPCODE popn_fisub; 
extern OPCODE popn_fsubr; 
extern OPCODE popn_fsubrp; 
extern OPCODE popn_fisubr; 
extern OPCODE popn_ftst; 
extern OPCODE popn_fucom; 
extern OPCODE popn_fucomp; 
extern OPCODE popn_fucompp; 
extern OPCODE popn_fwait; 
extern OPCODE popn_fxam; 
extern OPCODE popn_fxch; 
extern OPCODE popn_fxtract; 
extern OPCODE popn_fyl2x; 
extern OPCODE popn_fyl2xp1; 
extern LIST *mpthunklist;


int skipsize = 0;
int addsize = 0;

/*      variable initialization         */

char segregs[] = "CSDSESFSGSSS";

extern int      prm_asmfile;
extern int prm_lines,prm_nasm,prm_masm;

struct slit *strtab;

static int uses_float;

MULDIV *muldivlink = 0;
enum e_gt        gentype = nogen;               /* Current DC type */
enum e_sg        curseg = noseg;                /* Current seg */
int        outcol = 0;                          /* Curront col (roughly) */
int newlabel;
int needpointer;
static int nosize = 0;
static int phiput;

/* List of opcodes
 * This list MUST be in the same order as the op_ enums 
 */
ASMNAME oplst[] = { 
        { "reserved", op_reserved,0 , 0 },
        { "line#", op_reserved,0 , 0 },
        { "void#", op_void,0 , 0 },
        { "cmt#", op_reserved,0 , 0 },
        { "label#", op_reserved,0 , 0 },
        { "flabel#", op_reserved,0 , 0 },
        { "seq@", op_reserved,0 , 0 },
        { "db", op_reserved,0 , 0 },
        { "dd", op_reserved,0 , 0 },
        { "blockstart#", op_reserved, 0, 0 },
        { "blockend#", op_reserved, 0, 0 },
        { "aaa", op_aaa,0 ,&popn_aaa },
        { "aad", op_aad,0 ,&popn_aad },
        { "aam", op_aam,0 ,&popn_aam },
        { "aas", op_aas,0 ,&popn_aas },
        { "add", op_add,OPE_MATH ,&popn_add },
        { "adc", op_adc,OPE_MATH ,&popn_adc },
        { "and", op_and,OPE_MATH ,&popn_and },
        { "arpl", op_arpl,OPE_ARPL ,&popn_arpl },
        { "bound", op_bound,OPE_BOUND ,&popn_bound },
        { "bsf", op_bsf,OPE_BITSCAN ,&popn_bsf },
        { "bsr", op_bsr,OPE_BITSCAN ,&popn_bsr },
        { "bswap",op_bswap,OPE_REG32 ,&popn_bswap },
        { "btc", op_btc,OPE_BIT ,&popn_btc },
        { "bt", op_bt,OPE_BIT ,&popn_bt },
        { "btr", op_btr,OPE_BIT ,&popn_btr },
        { "bts", op_bts,OPE_BIT ,&popn_bts },
        { "call", op_call,OPE_CALL ,&popn_call },
        { "cbw", op_cbw,0 ,&popn_cbw },
        { "cwde", op_cwde,0 ,&popn_cwde },
        { "cwd", op_cwd, 0 ,&popn_cwd },
        { "cdq", op_cdq,0 ,&popn_cdq },
        { "clc", op_clc,0 ,&popn_clc },
        { "cld", op_cld,0 ,&popn_cld },
        { "cli", op_cli,0 ,&popn_cli },
        { "clts", op_clts, 0 ,&popn_clts },
        { "cmc", op_cmc, 0 ,&popn_cmc },
        { "cmp", op_cmp, OPE_MATH ,&popn_cmp },
        { "cmps", op_cmps, OPE_CMPS ,&popn_cmps },
        { "cmpsb", op_cmpsb, 0 ,&popn_cmpsb },
        { "cmpsw", op_cmpsw, 0 ,&popn_cmpsw },
        { "cmpsd", op_cmpsd, 0 ,&popn_cmpsd },
        { "daa",op_daa,0 ,&popn_daa },
        { "das", op_das,0 ,&popn_das },
        { "dec",op_dec, OPE_INCDEC,&popn_dec },
        { "div", op_div, OPE_RM,&popn_div },
        { "enter", op_enter, OPE_ENTER,&popn_enter },
        { "hlt", op_hlt, 0 ,&popn_hlt },
        { "idiv", op_idiv, OPE_RM ,&popn_idiv },
        { "imul", op_imul, OPE_IMUL ,&popn_imul },
        { "in", op_in, OPE_IN ,&popn_in },
        { "inc", op_inc, OPE_INCDEC ,&popn_inc },
        { "ins", op_ins, OPE_INS ,&popn_ins },
        { "insb", op_insb, 0 ,&popn_insb },
        { "insw", op_insw, 0 ,&popn_insw },
        { "insd", op_insd, 0 ,&popn_insd },
        { "int" , op_int, OPE_IMM8 ,&popn_int },
        { "int3", op_int3, 0 ,&popn_int3 },
        { "into", op_into, 0 ,&popn_into },
        { "invd", op_invd, 0 ,&popn_invd },
        { "iret", op_iret, 0,&popn_iret },
        { "iretd", op_iretd, 0,&popn_iretd },
        { "jecxz", op_jecxz, OPE_RELBR8,&popn_jcxz },
        { "ja", op_ja, OPE_RELBRA,&popn_ja },
        { "jnbe", op_jnbe, OPE_RELBRA,&popn_jnbe },
        { "jae", op_jae, OPE_RELBRA,&popn_jae },
        { "jnb", op_jnb, OPE_RELBRA,&popn_jnb },
        { "jnc", op_jnc, OPE_RELBRA,&popn_jnc },
        { "jb", op_jb, OPE_RELBRA,&popn_jb },
        { "jc", op_jc, OPE_RELBRA,&popn_jc },
        { "jnae", op_jnae, OPE_RELBRA,&popn_jnae },
        { "jbe", op_jbe, OPE_RELBRA,&popn_jbe },
        { "jna", op_jna, OPE_RELBRA,&popn_jna },
        { "je",op_je, OPE_RELBRA ,&popn_je },
        { "jz",op_jz, OPE_RELBRA ,&popn_jz },
        { "jg",op_jg, OPE_RELBRA ,&popn_jg },
        { "jnle",op_jnle, OPE_RELBRA ,&popn_jnle },
        { "jl",op_jl, OPE_RELBRA ,&popn_jl },
        { "jnge",op_jnge, OPE_RELBRA ,&popn_jnge },
        { "jge", op_jge, OPE_RELBRA ,&popn_jge },
        { "jnl", op_jnl, OPE_RELBRA ,&popn_jnl },
        { "jle", op_jle, OPE_RELBRA ,&popn_jle },
        { "jng", op_jng, OPE_RELBRA ,&popn_jng },
        { "jne", op_jne, OPE_RELBRA ,&popn_jne },
        { "jnz", op_jnz, OPE_RELBRA ,&popn_jnz },
        { "jo", op_jo, OPE_RELBRA ,&popn_jo },
        { "jno", op_jno, OPE_RELBRA ,&popn_jno },
        { "jp", op_jp, OPE_RELBRA ,&popn_jp },
        { "jnp", op_jnp, OPE_RELBRA ,&popn_jnp },
        { "jpe", op_jpe, OPE_RELBRA ,&popn_jpe },
        { "jpo", op_jpo, OPE_RELBRA ,&popn_jpo },
        { "js", op_js, OPE_RELBRA,&popn_js },
        { "jns", op_jns, OPE_RELBRA ,&popn_jns },
        { "jmp", op_jmp, OPE_JMP ,&popn_jmp },
        { "lahf", op_lahf, 0 ,&popn_lahf },
        { "lar", op_lar, OPE_REGRM ,&popn_lar },
        { "lds", op_lds, OPE_LOADSEG ,&popn_lds },
        { "les", op_les, OPE_LOADSEG ,&popn_les },
        { "lfs", op_lfs, OPE_LOADSEG ,&popn_lfs },
        { "lgs", op_lgs, OPE_LOADSEG ,&popn_lgs },
        { "lss", op_lss, OPE_LOADSEG ,&popn_lss },
        { "lea", op_lea, OPE_REGRM ,&popn_lea },
        { "leave", op_leave, 0 ,&popn_leave },
        { "lgdt", op_lgdt, OPE_LGDT ,&popn_lgdt },
        { "lidt", op_lidt, OPE_LIDT ,&popn_lidt },
        { "lldt", op_lldt, OPE_RM16 ,&popn_lldt },
        { "lmsw", op_lmsw, OPE_RM16 ,&popn_lmsw },
        { "lock", op_lock, 0 ,&popn_lock },
        { "lods", op_lods, OPE_LODS ,&popn_lods },
        { "lodsb", op_lodsb, 0 ,&popn_lodsb },
        { "lodsw", op_lodsw, 0 ,&popn_lodsw },
        { "lodsd", op_lodsd, 0 ,&popn_lodsd },
        { "loop",op_loop, OPE_RELBR8 ,&popn_loop },
        { "loope",op_loope, OPE_RELBR8 ,&popn_loope },
        { "loopz",op_loopz, OPE_RELBR8 ,&popn_loopz },
        { "loopne",op_loopne, OPE_RELBR8 ,&popn_loopne },
        { "loopnz",op_loopnz, OPE_RELBR8 ,&popn_loopnz },
        { "lsl", op_lsl, OPE_REGRM ,&popn_lsl },
        { "ltr", op_ltr, OPE_RM16 ,&popn_ltr },
        { "mov", op_mov, OPE_MOV ,&popn_mov },
        { "movs", op_movs, OPE_MOVS ,&popn_movs },
        { "movsb", op_movsb, 0 ,&popn_movsb },
        { "movsw", op_movsw, 0 ,&popn_movsw },
        { "movsd", op_movsd, 0 ,&popn_movsd },
        { "movsx", op_movsx, OPE_MOVSX,&popn_movsx },
        { "movzx", op_movzx, OPE_MOVSX,&popn_movzx },
        { "mul", op_mul, OPE_RM ,&popn_mul },
        { "neg", op_neg, OPE_RM ,&popn_neg },
        { "not", op_not, OPE_RM ,&popn_not },
        { "nop", op_nop, 0 ,&popn_nop },
        { "or", op_or,OPE_MATH ,&popn_or },
        { "out", op_out,OPE_OUT ,&popn_out },
        { "outs", op_outs, OPE_OUTS ,&popn_outs },
        { "outsb", op_outsb, 0 ,&popn_outsb },
        { "outsw", op_outsw, 0 ,&popn_outsw },
        { "outsd", op_outsd, 0 ,&popn_outsd },
        { "pop",op_pop, OPE_PUSHPOP ,&popn_pop },
        { "popa", op_popa, 0 ,&popn_popa },
        { "popad", op_popad, 0 ,&popn_popad },
        { "popf", op_popf, 0 ,&popn_popf },
        { "popfd", op_popfd, 0 ,&popn_popfd },
        { "push",op_push, OPE_PUSHPOP ,&popn_push },
        { "pusha", op_pusha, 0 ,&popn_pusha },
        { "pushad", op_pushad, 0 ,&popn_pushad },
        { "pushf", op_pushf, 0 ,&popn_pushf },
        { "pushfd", op_pushfd, 0 ,&popn_pushfd },
        { "rcl", op_rcl, OPE_SHIFT ,&popn_rcl },
        { "rcr", op_rcr, OPE_SHIFT ,&popn_rcr },
        { "rdtsc",op_rdtsc, 0, &popn_rdtsc } ,
        { "rol", op_rol, OPE_SHIFT ,&popn_rol },
        { "ror", op_ror, OPE_SHIFT ,&popn_ror },
        { "rep", op_rep, 0 ,&popn_repz },
        { "repne", op_repne, 0 ,&popn_repnz },
        { "repe", op_repe, 0 ,&popn_repz },
        { "repnz", op_repnz, 0 ,&popn_repnz },
        { "repz", op_repz, 0 ,&popn_repz },
        { "ret", op_ret, OPE_RET ,&popn_ret },
        { "retf", op_retf, OPE_RET ,&popn_retf },
        { "sahf", op_sahf, 0 ,&popn_sahf },
        { "sal", op_sal, OPE_SHIFT ,&popn_sal },
        { "sar", op_sar, OPE_SHIFT ,&popn_sar },
        { "shl", op_shl, OPE_SHIFT ,&popn_shl },
        { "shr", op_shr, OPE_SHIFT ,&popn_shr },
        { "sbb", op_sbb,OPE_MATH ,&popn_sbb },
        { "scas", op_scas, OPE_SCAS ,&popn_scas },
        { "scasb", op_scasb, 0 ,&popn_scasb },
        { "scasw", op_scasw, 0 ,&popn_scasw },
        { "scasd", op_scasd, 0 ,&popn_scasd },
        { "seta", op_seta, OPE_SET,&popn_seta },
        { "setnbe", op_setnbe, OPE_SET,&popn_setnbe },
        { "setae", op_setae, OPE_SET,&popn_setae },
        { "setnb", op_setnb, OPE_SET,&popn_setnb },
        { "setnc", op_setnc, OPE_SET,&popn_setnc },
        { "setb", op_setb, OPE_SET,&popn_setb },
        { "setc", op_setc, OPE_SET,&popn_setc },
        { "setnae", op_setnae, OPE_SET,&popn_setnae },
        { "setbe", op_setbe, OPE_SET,&popn_setbe },
        { "setna", op_setna, OPE_SET,&popn_setna },
        { "sete",op_sete, OPE_SET ,&popn_sete },
        { "setz",op_setz, OPE_SET ,&popn_setz },
        { "setg",op_setg, OPE_SET ,&popn_setg },
        { "setnle",op_setnle, OPE_SET ,&popn_setnle },
        { "setl",op_setl, OPE_SET ,&popn_setl },
        { "setnge",op_setnge, OPE_SET ,&popn_setnge },
        { "setge", op_setge, OPE_SET ,&popn_setge },
        { "setnl", op_setnl, OPE_SET ,&popn_setnl },
        { "setle", op_setle, OPE_SET ,&popn_setle },
        { "setng", op_setng, OPE_SET ,&popn_setng },
        { "setne", op_setne, OPE_SET ,&popn_setne },
        { "setnz", op_setnz, OPE_SET ,&popn_setnz },
        { "seto", op_seto, OPE_SET ,&popn_seto },
        { "setno", op_setno, OPE_SET ,&popn_setno },
        { "setp", op_setp, OPE_SET ,&popn_setp },
        { "setnp", op_setnp, OPE_SET ,&popn_setnp },
        { "setpe", op_setpe, OPE_SET ,&popn_setpe },
        { "setpo", op_setpo, OPE_SET ,&popn_setpo },
        { "sets", op_sets, OPE_SET,&popn_sets },
        { "setns", op_setns, OPE_SET ,&popn_setns },
        { "sgdt", op_sgdt, OPE_LGDT ,&popn_sgdt },
        { "sidt", op_sidt, OPE_LIDT ,&popn_sidt },
        { "sldt", op_sldt, OPE_RM16 ,&popn_sldt },
        { "smsw", op_smsw, OPE_RM16 ,&popn_smsw },
        { "shld", op_shld, OPE_SHLD ,&popn_shld },
        { "shrd", op_shrd, OPE_SHLD ,&popn_shrd },
        { "stc", op_stc, 0 ,&popn_stc },
        { "std", op_std, 0 ,&popn_std },
        { "sti", op_sti, 0 ,&popn_sti },
        { "stos", op_stos, OPE_STOS ,&popn_stos },
        { "stosb", op_stosb, 0 ,&popn_stosb },
        { "stosw", op_stosw, 0 ,&popn_stosw },
        { "stosd", op_stosd, 0 ,&popn_stosd },
        { "str", op_str, OPE_RM16 ,&popn_str },
        { "sub", op_sub, OPE_MATH ,&popn_sub },
        { "test", op_test, OPE_TEST ,&popn_test },
        { "verr", op_verr, OPE_RM16 ,&popn_verr },
        { "verw", op_verw, OPE_RM16 ,&popn_verw },
        { "wait", op_wait, 0 ,&popn_wait },
        { "wbinvd", op_wbinvd, 0 ,&popn_wbinvd },
        { "xchg", op_xchg, OPE_XCHG ,&popn_xchg },
        { "xlat", op_xlat, OPE_XLAT ,&popn_xlat },
        { "xlatb", op_xlatb, 0 ,&popn_xlatb },
        { "xor", op_xor,OPE_MATH ,&popn_xor },
        { "f2xm1", op_f2xm1, 0 ,&popn_f2xm1 },
        { "fabs", op_fabs, 0 ,&popn_fabs },
        { "fadd", op_fadd, OPE_FMATH ,&popn_fadd },
        { "faddp", op_faddp, OPE_FMATHP ,&popn_faddp },
        { "fiadd", op_fiadd, OPE_FMATHI ,&popn_fiadd },
        { "fchs", op_fchs, 0 ,&popn_fchs },
        { "fclex", op_fclex, 0 ,&popn_fclex },
        { "fnclex", op_fnclex, 0 ,&popn_fnclex },
        { "fcom", op_fcom, OPE_FCOM ,&popn_fcom },
        { "fcomp", op_fcomp, OPE_FCOM ,&popn_fcomp },
        { "fcompp", op_fcompp, 0 ,&popn_fcompp },
        { "fcos", op_fcos, 0 ,&popn_fcos },
        { "fdecstp", op_fdecstp, 0 ,&popn_fdecstp },
        { "fdiv", op_fdiv, OPE_FMATH ,&popn_fdiv },
        { "fdivp", op_fdivp, OPE_FMATHP ,&popn_fdivp },
        { "fidiv", op_fidiv, OPE_FMATHI ,&popn_fidiv },
        { "fdivr", op_fdivr, OPE_FMATH ,&popn_fdivr },
        { "fdivrp", op_fdivrp, OPE_FMATHP ,&popn_fdivrp },
        { "fidivr", op_fidivr, OPE_FMATHI ,&popn_fidivr },
        { "ffree", op_ffre, OPE_FREG ,&popn_ffree },
        { "ficom", op_ficom, OPE_FICOM ,&popn_ficom },
        { "ficomp", op_ficomp, OPE_FICOM ,&popn_ficomp },
        { "fild", op_fild, OPE_FILD ,&popn_fild },
        { "fincstp", op_fincstp, 0 ,&popn_fincstp },
        { "finit", op_finit, 0 ,&popn_finit },
        { "fninit", op_fninit, 0 ,&popn_fninit },
        { "fist", op_fist, OPE_FIST ,&popn_fist },
        { "fistp", op_fistp, OPE_FILD ,&popn_fistp },
        { "fld", op_fld, OPE_FLD ,&popn_fld },
        { "fldz", op_fldz, 0,&popn_fldz },
        { "fldpi", op_fldpi, 0,&popn_fldpi },
        { "fld1", op_fld1, 0,&popn_fld1 },
        { "fldl2t", op_fld2t, 0,&popn_fldl2t },
        { "fldl2e", op_fld2e, 0,&popn_fldl2e },
        { "fldlg2", op_fldlg2, 0,&popn_fldlg2 },
        { "fldln2", op_fldln2, 0,&popn_fldln2 },
        { "fldcw", op_fldcw, OPE_M16 ,&popn_fldcw },
        { "fldenv", op_fldenv, OPE_MN ,&popn_fldenv },
        { "fmul", op_fmul, OPE_FMATH,&popn_fmul },
        { "fmulp", op_fmulp, OPE_FMATHP,&popn_fmulp },
        { "fimul", op_fimul, OPE_FMATHI ,&popn_fimul },
        { "fpatan", op_fpatan, 0 ,&popn_fpatan },
        { "fprem", op_fprem, 0 ,&popn_fprem },
        { "fprem1", op_fprem1, 0 ,&popn_fprem1 },
        { "fptan", op_fptan, 0 ,&popn_fptan },
        { "frndint", op_frndint, 0 ,&popn_frndint },
        { "frstor", op_frstor, OPE_MN ,&popn_frstor },
        { "fsave", op_fsave, OPE_MN ,&popn_fsave },
        { "fnsave", op_fnsave, OPE_MN ,&popn_fnsave },
        { "fscale", op_fscale, 0 ,&popn_fscale },
        { "fsin", op_fsin, 0 ,&popn_fsin },
        { "fsincos", op_fsincos, 0 ,&popn_fsincos },
        { "fsqrt", op_fsqrt, 0 ,&popn_fsqrt },
        { "fst", op_fst, OPE_FST,&popn_fst },
        { "fstp", op_fstp, OPE_FSTP,&popn_fstp },
        { "fstcw", op_fstcw, OPE_M16,&popn_fstcw },
        { "fstsw", op_fstsw, OPE_M16,&popn_fstsw },
        { "fnstcw", op_fnstcw, OPE_M16,&popn_fnstcw },
        { "fnstsw", op_fnstsw, OPE_M16,&popn_fnstsw },
        { "fstenv", op_fstenv, OPE_MN ,&popn_fstenv },
        { "fnstenv", op_fsntenv, OPE_MN ,&popn_fnstenv },
        { "fsub", op_fsub, OPE_FMATH,&popn_fsub },
        { "fsubp", op_fsubp, OPE_FMATHP,&popn_fsubp },
        { "fisub", op_fisub, OPE_FMATHI,&popn_fisub },
        { "fsubr", op_fsubr, OPE_FMATH,&popn_fsubr },
        { "fsubrp", op_fsubrp, OPE_FMATHP,&popn_fsubrp },
        { "fisubr", op_fisubr, OPE_FMATHI,&popn_fisubr },
        { "ftst", op_ftst, 0,&popn_ftst },
        { "fucom", op_fucom, OPE_FUCOM ,&popn_fucom },
        { "fucomp", op_fucomp, OPE_FUCOM ,&popn_fucomp },
        { "fucompp", op_fucompp, 0 ,&popn_fucompp },
        { "fwait", op_fwait, 0 ,&popn_fwait },
        { "fxam", op_fxam, 0 ,&popn_fxam },
        { "fxch", op_fxch, OPE_FXCH ,&popn_fxch },
        { "fxtract", op_fxtract, 0 ,&popn_fxtract },
        { "fyl2x", op_fyl2x, 0 ,&popn_fyl2x },
        { "fyl2xp1", op_fyl2xp1, 0 ,&popn_fyl2xp1 },
        {0,0,0 },
        };
/* Init module */
void outcodeini(void)
{
        strtab = 0;
        gentype = nogen;
        curseg = noseg;
        outcol = 0;
        newlabel = FALSE;
        phiput = FALSE;
        muldivlink = 0;
				mpthunklist = 0;
}
void nl(void)
/*
 * New line
 */
{    if (prm_asmfile) {
       if(outcol > 0) {
                fputc('\n',outputFile);
                outcol = 0;
                gentype = nogen;
                }
                         if (phiused && !phiput)
                                                                fputc(0x1f,outputFile);
                 }
}
/* Put an opcode
 */
void outop(char *name)
{ fputc('\t',outputFile);
  while (*name) fputc(toupper(*name++),outputFile);
}
void putop(enum e_op op, AMODE *aps, AMODE *apd, int nooptx)
{ if (prm_nasm)
  { skipsize=FALSE;
    addsize=FALSE;  
    switch (op)
    { case op_lea:
        skipsize=TRUE;
        break;
      case op_push:
        addsize=TRUE;
        if (!aps->length) aps->length=4;
        break;
      case op_add:
      case op_sub:
      case op_adc:
			case op_sbb:
      case op_imul:   /* yes you can size an imul constant !!!! */
      case op_cmp:
      case op_and:
      case op_or:
      case op_xor:
			case op_idiv:
				if (apd)
        	addsize=apd->length!=0;
				else {
    	    addsize=TRUE;
      	  if (!aps->length) aps->length=4;
				}
        break;
    }
		if (op == op_fwait) {
      		outop(oplst[op_fwait].word+1);
      		return;
		}
		if (!nooptx) {
			switch (op) {
				case op_iretd:
						outop("iret");
						return;
				case op_pushad:
						outop("pusha");
						return;
				case op_popad:
						outop("popa");
						return;
				case op_pushfd:
						outop("pushf");
						return;
				case op_popfd:
						outop("popf");
						return;
			}
		}
		
  }
  if (op>op_fyl2xp1) DIAG("illegal opcode.");
  else outop(oplst[op].word);
  uses_float=(op>=op_f2xm1);
}

void putsym(char *buf, SYM *sp, char *p)
{
  if (sp->alias)
    strcpy(buf,sp->alias);
  else {
		if (sp->pascaldefn) {
			char *q=buf;
			if (prm_cmangle)
				p++;
			while (*p)
				*q++ = toupper(*p++);
			*q = 0;
		}
		else if (sp->isstdcall) {
			if (prm_cmangle)
				p++;
			strcpy(buf,p);
		} else
    	strcpy(buf,p);
	}
}
void putconst(ENODE *offset)
/*
 *      put a constant to the outputFile file.
 */                  
{ char buf[100];
	SYM *sp;
	switch (offset->nodetype)
  { case en_autoreg:
    case en_autocon:
    case en_icon:
    case en_lcon:
    case en_iucon:
    case en_lucon:
    case en_ccon:
    case en_absacon:
      fprintf(outputFile,"0%lXH",offset->v.i);
      break;
    case en_rcon:
    case en_fcon:
    case en_lrcon:
      fprintf(outputFile,"%.16f",offset->v.f);
      break;
    case en_labcon:
    case en_nalabcon:
      fprintf(outputFile,"L_%d",offset->v.i);
      break;
    case en_napccon:
    case en_nacon:
			sp = offset->v.sp;
			putsym(buf,sp,sp->name);
      fprintf(outputFile,"%s",buf);
      break;
    case en_add:
    case en_addstruc:
      putconst(offset->v.p[0]);
      fprintf(outputFile,"+");
      putconst(offset->v.p[1]);
      break;
    case en_sub:
      putconst(offset->v.p[0]);
      fprintf(outputFile,"-");
      putconst(offset->v.p[1]);
      break;
    case en_uminus:
      fprintf(outputFile,"-");
      putconst(offset->v.p[0]);
      break;
    default:
      DIAG("illegal constant node.");
      break;
  }
}
void putlen(int l)
/*
 *      append the length field to an instruction.
 */
{ 
	if (l < 0) 
		l = -l;
        if (l!= 10 && l != 8 && l != 7 && l != 4 && l != 1 && l != 2 && l != 0 && l != 5)
     DIAG("illegal length field.");
}
void putsizedreg(char *string, int reg, int size)
{
        static char *byteregs[] = { "AL","CL","DL","BL","AH","CH","DH","BH" };
        static char *wordregs[] = { "AX", "CX", "DX","BX","SP","BP","SI","DI"  };
        static char *longregs[] = { "EAX", "ECX", "EDX","EBX","ESP","EBP","ESI","EDI" };
	if (size < 0)
		size = - size;
  if (size == 4)
                fprintf(outputFile,string,longregs[reg]);
        else if (size == 1 || size == 5) {
                fprintf(outputFile,string,byteregs[reg]);
        } else
                fprintf(outputFile,string,wordregs[reg]);
}
void pointersize(int size)
{
        if (prm_nasm && skipsize)
                return;
				if (size < 0)
					size = - size;
/*      if (needpointer)
*/              switch (size) {         
                        case 10:
                                if (prm_nasm)
                                        fprintf(outputFile,"TWORD ");
                                else
                                        fprintf(outputFile,"TBYTE ");
                                break;
                        case 8:
                        case 6: // should never happen                      
        fprintf(outputFile,"QWORD ");
                                break;
                        case 7:
                                if (!uses_float) {
                                        if (prm_nasm)
                                                fprintf(outputFile,"DWORD FAR ");
                                        else
                                                fprintf(outputFile,"FWORD ");
                                        break;
                                }
                        case 4:                      
                                fprintf(outputFile,"DWORD ");
                                break;
                        case 2:
                                fprintf(outputFile,"WORD ");
                                break;
                        case 5:
                        case 1:
                                fprintf(outputFile,"BYTE ");
                                break;
												case 0: /* for NASM with certain FP ops */
																break;
                        default:
                                DIAG("Bad pointer");
                }       
                if (!prm_nasm && size)
                        fprintf(outputFile,"PTR ");
}
void putseg(int seg, int usecolon)
{
        if (!seg)
                return;
        seg-=1;
        seg<<=1;
        fputc(segregs[seg], outputFile);
        fputc(segregs[seg+1], outputFile);
  if (usecolon)
                fputc(':', outputFile);
}

void putamode(AMODE *ap)
/*
 *      output a general addressing mode.
 */
{ int oldnasm,l;

  switch (ap->mode)
  { case am_seg:
      putseg(ap->seg,0);
      break;
    case am_screg:
      fprintf(outputFile,"CR%d",ap->preg);
      break;
    case am_sdreg:
      fprintf(outputFile,"DR%d",ap->preg);
      break;
    case am_streg:
      fprintf(outputFile,"TR%d",ap->preg);
      break;
    case am_immed:
      if (ap->length>0 && (ap->offset->nodetype==en_labcon ||
        ap->offset->nodetype==en_nacon || ap->offset->nodetype==en_nalabcon ||
        ap->offset->nodetype==en_napccon))
        { if (!prm_nasm) fprintf(outputFile,"OFFSET ");
          else if (!nosize) fprintf(outputFile,"DWORD ");
        }
      else if (prm_nasm && addsize)pointersize(ap->length);
      putconst(ap->offset);
      break;
    case am_direct:
      pointersize(ap->length);
      if (!prm_nasm) putseg(ap->seg,TRUE);
      fputc('[',outputFile);
      oldnasm=prm_nasm;
      if (prm_nasm)putseg(ap->seg,TRUE);
      prm_nasm=TRUE;
      putconst(ap->offset);
      fputc(']',outputFile);
      prm_nasm=oldnasm;
      break;
    case am_dreg:
      putsizedreg("%s",ap->preg,ap->length);
      break;
    case am_freg:
      if (prm_nasm) fprintf(outputFile,"ST%d",ap->preg);
      else fprintf(outputFile,"ST(%d)",ap->preg);
      break;
    case am_indisp:
      pointersize(ap->length);
      if (!prm_nasm) putseg(ap->seg,TRUE);
      fputc('[',outputFile);
      if (prm_nasm) putseg(ap->seg,TRUE);
      putsizedreg("%s",ap->preg,4);
      if (ap->offset)
      { fputc('+',outputFile);
        putconst(ap->offset);
      }
      fputc(']',outputFile);
      break;
    case am_indispscale:
      { int scale=1,t=ap->scale;

        while (t--) scale<<=1;
        pointersize(ap->length);
        if (!prm_nasm) putseg(ap->seg,TRUE);
        fputc('[',outputFile);
        if (prm_nasm) putseg(ap->seg,TRUE);
        if (ap->preg!=-1) putsizedreg("%s+",ap->preg,4);
        putsizedreg("%s",ap->sreg,4);
        if (scale!=1) fprintf(outputFile,"*%d",scale);
        if (ap->offset)
        { fputc('+',outputFile);
          putconst(ap->offset);
        }
        fputc(']',outputFile);
      }
      break;
    default:
      DIAG("illegal address mode.");
      break;
  }
}

void put_code(OCODE *cd)
/*
 *      outputFile a generic instruction.
 */
{ int op=cd->opcode,len=0,len2=0;
  AMODE *aps=cd->oper1,*apd=cd->oper2,*ap3=cd->oper3;

  if (!prm_asmfile) return;
  if (op==op_line)
  { if (!prm_lines) return;
    fprintf(outputFile,";\n; Line %d:\t%s\n;\n",(int)apd,(char *)aps);
    return;
  }
  else if (op==op_comment)
  { if (!prm_lines) return;
    fprintf(outputFile,"%s",aps);
    return;
  }
  else if (op==op_void || op == op_blockstart || op == op_blockend) return;
  if (aps) len=aps->length;
  if (apd) len2=apd->length;
  needpointer=(len!=len2) || ((!aps || aps->mode!=am_dreg) &&
    (!apd || apd->mode!=am_dreg));
  putop(op,aps,apd,cd->noopt);
  if (prm_nasm && ((op>=op_ja && op<=op_jns && op!=op_jecxz) ||op == op_jmp && aps->mode == am_immed))
  { if (len) fprintf(outputFile,"\tSHORT");
    else fprintf(outputFile,"\tNEAR");
    nosize=TRUE;
  }
  else if (op==op_jmp && aps->mode==am_immed && aps->offset->nodetype==en_labcon
    && len==1 || len == -1)
  { fprintf(outputFile,"\tSHORT");
    nosize=TRUE;
  }
  switch (op)
  { case op_rep:
    case op_repz:
    case op_repe:
    case op_repnz:
    case op_repne:
    case op_lock:
      return;
  }
  putlen(len);
  if (aps!=0)
  { fprintf(outputFile,"\t");
    if (op==op_dd) nosize=TRUE;
    putamode(aps);
    nosize=FALSE;
    if (apd!=0) 
    { fprintf(outputFile,",");
      putamode(apd);
    }
    if (ap3!=0) 
    { fprintf(outputFile,",");
      putamode(ap3);
    }
  }
  fprintf(outputFile,"\n");
}

void gen_strlab(SYM *sp)
/*
 *      generate a named label.
 */
{
								char buf[100];
								putsym(buf,sp,sp->name);
                if (prm_asmfile)
                        if (curseg == dataseg || curseg == bssxseg) {
                                newlabel = TRUE;
                                fprintf(outputFile,"\n%s",buf);
                                outcol = strlen(buf)+1;
                        }
                        else
                					fprintf(outputFile,"%s:\n",buf);
}

void put_label(int lab)
/*
 *      outputFile a compiler generated label.
 */
{
       if (prm_asmfile)
                                        fprintf(outputFile,"L_%d:\n",lab);
			 else 
				outcode_put_label(lab) ;
}
void put_staticlabel(long label)
{
                                if (prm_asmfile) {
                                        nl();
                                        if (curseg == dataseg || curseg == bssxseg) {
                                                newlabel = TRUE;
                                                fprintf(outputFile,"\nL_%ld",label);
                                                outcol = 8;
                                        }
                                        else
                                                fprintf(outputFile,"L_%ld:\n",label);
                                } else
																	outcode_put_label(label) ;
}

void genfloat(double val)
/*
 * Output a float value
 */
{     if (prm_asmfile) {
        if( gentype == floatgen && outcol < 60) {
                fprintf(outputFile,",%.16f",val);
                outcol += 8;
                }
        else    {
                                                                if (!newlabel)
                                                                        nl();
                                                                else newlabel = FALSE;
                fprintf(outputFile,"\tDD\t%.16f",val);
                gentype = floatgen;
                outcol = 19;
                }
			} else
				outcode_genfloat(val) ;
}

void gendouble(double val)
/*
 * Output a double value
 */
{   if (prm_asmfile)
        if( gentype == doublegen && outcol < 60) {
                fprintf(outputFile,",%.16f",val);
                outcol += 8;
                }
        else    {
                                                                if (!newlabel)
                                                                        nl();
                                                                else newlabel = FALSE;
                fprintf(outputFile,"\tDQ\t%.16f",val);
                gentype = doublegen;
                outcol = 19;
                }
		else
			outcode_gendouble(val) ;
}
void genlongdouble(double val)
/*
 * Output a double value
 */
{   if (prm_asmfile)
        if( gentype == longdoublegen && outcol < 60) {
                fprintf(outputFile,",%.16f",val);
                outcol += 8;
                }
        else    {
                                                                if (!newlabel)
                                                                        nl();
                                                                else newlabel = FALSE;
                fprintf(outputFile,"\tDT\t%.16f",val);
                gentype = longdoublegen;
                outcol = 19;
                }
		else outcode_genlongdouble(val) ;
}
int genstring(char *str, int uselong, int len)
/*
 * Generate a string literal
 */
{
		if (prm_asmfile)
        if (uselong) {
								len/=2;
                while  (len--) {
                        genword(*((short *)str));
                        str+=2;
                }
                return pstrlen(str)*2;
        }
        else {
                while (len--)
                        genbyte(*str++);
                return strlen(str);
        } 
		else
					outcode_genstring(str,len) ;
}
void genbyte(long val)
/*
 * Output a byte value
 */
{               if (prm_asmfile)
        if( gentype == bytegen && outcol < 60) {
                fprintf(outputFile,",0%XH",val & 0x00ff);
                outcol += 4;
                }
        else    {
                                                                if (!newlabel)
                                                                        nl();
                                                                else newlabel = FALSE;
                fprintf(outputFile,"\tDB\t0%XH",val & 0x00ff);
                gentype = bytegen;
                outcol = 19;
                }
		else
				outcode_genbyte(val) ;
}

void genword(long val)
/*
 * Output a word value
 */
{     if (prm_asmfile)
        if( gentype == wordgen && outcol < 58) {
                fprintf(outputFile,",0%XH",val & 0x0ffff);
                outcol += 6;
                }
        else    {
                                                                if (!newlabel)
                                                                        nl();
                                                                else newlabel = FALSE;
                fprintf(outputFile,"\tDW\t0%XH",val & 0x0ffff);
                gentype = wordgen;
                outcol = 21;
                }
			else
					outcode_genword(val) ;
}

void genlong(long val)
/*
 * Output a long value
 */
{     if (prm_asmfile)
        if( gentype == longgen && outcol < 56) {
                fprintf(outputFile,",0%lXH",val);
                outcol += 10;
                }
        else    {
                if (!newlabel)
                	nl();
                else 
									newlabel = FALSE;
                fprintf(outputFile,"\tDD\t0%lXH",val);
                gentype = longgen;
                outcol = 25;
                }
			else 
				outcode_genlong(val) ;
}
void genlonglong(long val)
/*
 * Output a long value
 */
{     if (prm_asmfile)
        if( gentype == longgen && outcol < 56) {
                fprintf(outputFile,",0%lXH,0",val);
                outcol += 10;
                }
        else    {
                if (!newlabel)
                	nl();
                else 
									newlabel = FALSE;
                fprintf(outputFile,"\tDD\t0%lXH,0",val);
                gentype = longgen;
                outcol = 25;
                }
			else 
            outcode_genlonglong(val) ;
}

void gensrref(SYM *sp, int val)
{
	  char buf[100];
    if (prm_asmfile) {
				putsym(buf,sp,sp->name);
        if( gentype == srrefgen && outcol < 56) {
                fprintf(outputFile,",%s,%d",buf,val);
                outcol += strlen(buf)+1;
                }
        else    {
                nl();
                fprintf(outputFile,"\tDD\t%s,%d",buf,val);
                gentype = srrefgen;
                outcol = 25;
                }
		} else
			outcode_gensrref(sp,val) ;
}
void genref(SYM *sp,int offset)
/*
 * Output a reference to the data area (also gens fixups )
 */
{       char    sign;
        char name[100],buf[100];
		if (prm_asmfile) {
				putsym(name,sp,sp->name);
        if( offset < 0) {
                sign = '-';
                offset = -offset;
                }
        else
                sign = '+';
                        sprintf(buf,"%s%c%d",name,sign,offset);
                        if (prm_asmfile) {
        if( gentype == longgen && outcol < 55 - strlen(buf)) {
                fprintf(outputFile,",%s",buf);
                outcol += (11 + strlen(buf));
                }
        else    {
                                                                if (!newlabel)
                                                                        nl();
                                                                else newlabel = FALSE;
                fprintf(outputFile,"\tDD\t%s",buf);
                outcol = 26 + strlen(buf);
                gentype = longgen;
                }
                        }
		} else
			outcode_genref(sp,offset) ;

}
void genpcref(SYM *sp,int offset)
/*
 * Output a reference to the code area (also gens fixups )
 */
{
        genref(sp,offset);
}
void genstorage(int nbytes)
/*
 * Output bytes of storage
 */
{                       if (prm_asmfile) {
                                                                if (!newlabel)
                                                                        nl();
                                                                else newlabel = FALSE;
                                if (prm_nasm)
                fprintf(outputFile,"\tRESB\t0%XH",nbytes);
                                else
                fprintf(outputFile,"\tDB\t0%XH DUP (?)",nbytes);
                                outcol = 28;
                                gentype = storagegen;
                        } else
													outcode_genstorage(nbytes) ;
}

void gen_labref(int n)
/*
 * Generate a reference to a label
 */
{    if (prm_asmfile) {
        if( gentype == longgen && outcol < 58) {
                fprintf(outputFile,",L_%d",n);
                outcol += 6;
                }
        else    {
                                                                if (!newlabel)
                                                                        nl();
                                                                else newlabel = FALSE;
                fprintf(outputFile,"\tDD\tL_%d",n);
                outcol = 22;
                gentype = longgen;
                }
		} else
			outcode_gen_labref(n) ;
}

int     stringlit(char *s, int uselong, int len)
/*
 *      make s a string literal and return it's label number.
 */
{
				struct slit     *lp = strtab;
        if (uselong)
					len *= 2;
        if (prm_optmult) {
          while (lp) {
						if (len == lp->len && !memcmp(lp->str,s,len))
        		  return lp->label;
            lp = lp->next;
          }
        }
        ++global_flag;          /* always allocate from global space. */
        lp = xalloc(sizeof(struct slit));
        lp->label = nextlabel++;
        lp->str = malloc(len);
				memcpy(lp->str,s,len);
				lp->len = len;
        lp->next = strtab;
                                lp->type = uselong;
        strtab = lp;
        --global_flag;
        return lp->label;
}

void dumplits(void)
/*
 *      dump the string literal pool.
 */
{
		if (prm_asmfile) {
        while( strtab != 0) {
                xstringseg() ;
                nl();
                put_label(strtab->label);
                genstring(strtab->str,strtab->type,strtab->len-1);
                if (strtab->type)
                	genword(0);
                else
                	genbyte(0);
                strtab = strtab->next;
                }
        nl();
		} else
			outcode_dumplits() ;
}

/*
 * Exit if from a special segment
 */
void exitseg(void)
{
		if (prm_asmfile) {
        if (!prm_nasm) {
                if (curseg == startupxseg) {
                        curseg = noseg;
                        fprintf(outputFile,"cstartup\tENDS\n");
                }
                else if (curseg == rundownxseg) {
                        curseg = noseg;
                        fprintf(outputFile,"crundown\tENDS\n");
                }
                else if (curseg == cppxseg) {
                        curseg = noseg;
                        fprintf(outputFile,"cppinit\tENDS\n");
                } else if (curseg == constseg) {
                        curseg = noseg;
                        fprintf(outputFile,"_CONST\tENDS\n");
                } else if (curseg == stringseg) {
                        curseg = noseg;
                        fprintf(outputFile,"_STRING\tENDS\n");
								}
        }
		} else
			curseg = noseg ;
}
/*
 * Switch to cseg 
 */
void cseg(void)
{                       
		if (prm_asmfile) {
        if( curseg != codeseg) {
                nl();
                                                                exitseg();
                                                                if (prm_nasm)
                                                                        if (!prm_nodos)
                                fprintf(outputFile,"SECTION _TEXT\n");
                                                                        else {
                                fprintf(outputFile,"SECTION .text\n");
                                                                                fprintf(outputFile,"[BITS 32]\n");
                                                                        }
                                                                else
                        fprintf(outputFile,"\t.CODE\n");
                curseg = codeseg;
                }
		} else
			curseg = codeseg ;
}
void xconstseg(void)
{                
		if (prm_asmfile) {
                                if( curseg != constseg) {
                nl();
                                                                exitseg();
                                                                if (prm_nasm) {
                                                                        if (!prm_nodos)
                                fprintf(outputFile,"SECTION _CONST\n");
                                                                }
                                                                else
                        fprintf(outputFile,"_CONST\tSEGMENT USE32 PUBLIC DWORD \042CONST\042\n");
                curseg = constseg;
                }
		} else
			curseg = constseg ;
}
void xstringseg(void)
{   
    if (prm_asmfile) {
                                if( curseg != stringseg) {
                nl();
                                                                exitseg();
                                                                if (prm_nasm) {
                                                                        if (!prm_nodos)
                                fprintf(outputFile,"SECTION _STRING\n");
                                                                }
                                                                else
                        fprintf(outputFile,"_STRING\tSEGMENT USE32 PUBLIC DWORD \042STRING\042\n");
                curseg = stringseg;
                }
		} else
			curseg = stringseg ;
}
/*
 * Switch to deseg
 */
void dseg(void)
{     
	if (prm_asmfile)   {
                                if( curseg != dataseg) {
                nl();
                                                                exitseg();
                                                                if (prm_nasm)
                                                                        if (!prm_nodos)
                                fprintf(outputFile,"SECTION _DATA\n");
                                                                        else
                                fprintf(outputFile,"SECTION .data\n");
                                                                else
                        fprintf(outputFile,"\t.DATA\n");
                curseg = dataseg;
                }
		} else
			curseg = dataseg ;
}
/*
 * Switch to bssseg
 */
void bssseg(void)
{     if (prm_asmfile)  {
                                if( curseg != bssxseg) {
                nl();
                                                                exitseg();
                                                                if (prm_nasm)
                                                                        if (!prm_nodos)
                                fprintf(outputFile,"SECTION _BSS\n");
                                                                        else
                                fprintf(outputFile,"SECTION .bss\n");
                                                                else
                        fprintf(outputFile,"\t.DATA?\n");
                curseg = bssxseg;
                }
			} else
				curseg = bssxseg ;
}
/*
 * Switch to startupseg
 */
void startupseg(void)
{     if (prm_asmfile)   {
                                if( curseg != startupxseg) {
                nl();
                                                                exitseg();      
                                                                if (prm_nasm) {
                                                                        if (!prm_nodos)
                                fprintf(outputFile,"SECTION cstartup\n");
                                                                }
                                                                else
                        fprintf(outputFile,"cstartup\tSEGMENT USE32 PUBLIC DWORD \042INITDATA\042\n");
                curseg = startupxseg;
                }
			} else
				curseg = startupxseg ;
}
/*
 * Switch to rundownseg
 */
void rundownseg(void)
{     if (prm_asmfile)   {
                                if( curseg != rundownxseg) {
                nl();
                                                                exitseg();
                                                                if (prm_nasm) {
                                                                        if (!prm_nodos)
                                fprintf(outputFile,"SECTION crundown\n");
                                                                }
                                                                else
                      fprintf(outputFile,"crundown\tSEGMENT USE32 PUBLIC DWORD \042EXITDATA\042\n");
                curseg = rundownxseg;
                }
			} else
				curseg = rundownxseg ;
}
void cppseg(void)
{
     if (prm_asmfile)  {
                                if( curseg != cppxseg) {
                nl();
                                                                exitseg();
                                                                if (prm_nasm) {
                                                                        if (!prm_nodos)
                                fprintf(outputFile,"SECTION cppinit\n");
                                                                }
                                                                else
                        fprintf(outputFile,"cppinit\tSEGMENT USE32 PUBLIC DWORD \042CPPINIT\042\n");
                curseg = cppxseg;
                }
			} else
				curseg = cppxseg ;
}
void cpprdseg(void)
{
     if (prm_asmfile)  {
                                if( curseg != cpprseg) {
                nl();
                                                                exitseg();
                                                                if (prm_nasm) {
                                                                        if (!prm_nodos)
                                fprintf(outputFile,"SECTION cppexit\n");
                                                                }
                                                                else
                        fprintf(outputFile,"cpprundown\tSEGMENT USE32 PUBLIC DWORD \042CPPEXIT\042\n");
                curseg = cpprseg;
                }
			} else
				curseg = cpprseg ;
}
#ifdef CPLUSPLUS
void gen_virtual(SYM *sp)
{
				curseg = virtseg ;	
        if (prm_asmfile) {
                nl();
								if (prm_nasm) {
									curseg = noseg ;
									fprintf(outputFile,"\tSECTION @%s VIRTUAL\n",sp->name);
								} else
                	fprintf(outputFile,"@%s\tSEGMENT VIRTUAL\n",sp->name);
								fprintf(outputFile,"%s:\n",sp->name);
        } else
					outcode_start_virtual_seg(sp) ;
}
void gen_endvirtual(SYM *sp)
{
        if (prm_asmfile) {
                nl();
								if (!prm_nasm)
                	fprintf(outputFile,"@%s\tENDS\n",sp->name);
								else
									cseg();
        } else
					outcode_end_virtual_seg(sp) ;
	curseg = noseg ;
}
#endif
/*
 * Align
 */
void align(int size)
{
   if (curseg == codeseg)
      return ;
                        if (prm_asmfile) {
                                nl();
                                if (prm_nasm)
/* NASM 0.91 wouldn't let me use parenthesis but this should work
 * according to the documented precedence levels
 */
                                        fprintf(outputFile,"\tTIMES $$-$ & %d NOP\n",3);
                                else
                                        fprintf(outputFile,"\tALIGN\t%d\n",4);
                        } else
													outcode_align(size) ;
}
/*
 * queue muldiv val
 */              
long queue_muldivval(long number)
{
        MULDIV *p = muldivlink;
        if (prm_optmult) {
                while (p) {
                        if (p->size == 0 && p->value == number)
                                return p->label;
                        p = p->link;
                }
        }
        global_flag++;
        p = xalloc(sizeof(MULDIV));
        global_flag--;
        p->link = muldivlink;
        p->value = number;
        p->size = 0;
        muldivlink = p;
        return p->label = nextlabel++;
}
long queue_floatval(double number, int size)
{
        MULDIV *p = muldivlink;
        if (prm_optmult) {
                while (p) {
                        if (p->size == size && p->floatvalue == number)
                                return p->label;
                        p = p->link;
                }
        }
        global_flag++;
        p = xalloc(sizeof(MULDIV));
        global_flag--;
        p->link = muldivlink;
        p->floatvalue = number;
        p->size = size;
        muldivlink = p;
        return p->label = nextlabel++;
}
void dump_muldivval(void)
{
        int tag = FALSE;
        if (prm_asmfile) {
                fprintf(outputFile,"\n");
                if (muldivlink) {
                        tag = TRUE;
                        align(4);
                }
                while (muldivlink) {
                        put_label(muldivlink->label);
                        if (muldivlink->size == 0)
                                fprintf(outputFile,"\tDD\t0%xH\n",muldivlink->value);
                        else if (muldivlink->size == 6)
                                fprintf(outputFile,"\tDD\t%.16f\n",muldivlink->floatvalue);
                        else if (muldivlink->size == 8)
                                fprintf(outputFile,"\tDQ\t%.16f\n",muldivlink->floatvalue);
                        else
                                fprintf(outputFile,"\tDT\t%.16f\n",muldivlink->floatvalue);
                        muldivlink = muldivlink->link;
                }
                if (tag)
                        fprintf(outputFile,"\n");
        } else
					outcode_dump_muldivval() ;
}
void asm_header(void)
{
        nl();
        if (prm_nasm) {
                if (!prm_nodos) {
                        fprintf(outputFile,"\tSECTION _TEXT CLASS=CODE USE32\n");
                        fprintf(outputFile,"\tSECTION _DATA CLASS=DATA USE32\n");
                        fprintf(outputFile,"\tSECTION _BSS  CLASS=BSS USE32\n");
                        fprintf(outputFile,"\tSECTION _CONST  CLASS=CONST USE32\n");
                        fprintf(outputFile,"\tSECTION _STRING  CLASS=STRING USE32\n");
                        fprintf(outputFile,"\tSECTION cstartup CLASS=INITDATA USE32\n" );
                        fprintf(outputFile,"\tSECTION crundown CLASS=EXITDATA USE32\n");
                        fprintf(outputFile,"\tSECTION cppinit  CLASS=CPPINIT USE32\n");
                        fprintf(outputFile,"\tSECTION cppexit  CLASS=CPPEXIT USE32\n");
                        fprintf(outputFile,"\tGROUP DGROUP _DATA _BSS _CONST _STRING\n\n");
                }
                else {
                        fprintf(outputFile,"\tSECTION .text\n");
                        fprintf(outputFile,"\tSECTION .data\n");
                        fprintf(outputFile,"\tSECTION .bss\n");
                }
        }
        else {
                fprintf(outputFile,"\tTITLE\t'%s'\n",outfile);
                if (prm_flat)
                                fprintf(outputFile,"\t.486p\n\t.MODEL FLAT\n\n");
                else
                                if (prm_masm)
                                        fprintf(outputFile,"\t.486p\n\t.MODEL SMALL\n\n");
                                else
                                        fprintf(outputFile,"\t.486p\n\t.MODEL USE32 SMALL\n\n");
        }
}
void globaldef(SYM *sp)
{
        char buf[100],*q=buf,*p=sp->name;
		if (prm_asmfile) {
				putsym(buf,sp,p);
        if (prm_nasm)
      fprintf(outputFile,"[GLOBAL\t%s]\n",buf);
        else
      fprintf(outputFile,"\tPUBLIC\t%s\n",buf);
		}
}
void output_alias(char *name , char *alias)
{
	if (prm_asmfile) {
        if (prm_nasm)
                fprintf(outputFile,"%%define %s %s\n",name,alias);
        else
                fprintf(outputFile,"%s EQU\t<%s>\n",name,alias);
	}
}                       
int put_exfunc(SYM *sp, int notyet)
{
                  char buf[100],*q=buf,*p=sp->name;
									putsym(buf,sp,p);
                  if (prm_nasm) {
                    if (notyet) {
                      if (!prm_nodos)
                        fprintf(outputFile,"\nSECTION _TEXT\n");
                      else {
                        fprintf(outputFile,"\nSECTION .text\n");
	                      fprintf(outputFile,"[BITS 32]\n");
  	                  }
    	                notyet = FALSE;
      	            }
                   fprintf(outputFile,"[EXTERN\t%s]\n",buf);
                   if (sp->importable)
                     fprintf(outputFile,"\timport %s %s\n",buf,sp->importfile) ;
          	      }
            	    else {
              	    if (notyet) {
                	    fprintf(outputFile,"\n\t.CODE\n");
                  	  notyet = FALSE;
	                  }
                   fprintf(outputFile,"\tEXTRN\t%s:PROC\n",buf);
                   if (sp->importable)
                     fprintf(outputFile,"\timport %s %s\n",buf,sp->importfile) ;
    	            }
	return notyet ;
}
void putexterns(void)
/*
 * Output the fixup tables and the global/external list
 */
{       SYM     *sp;
                        int i;
				LIST *l ;
        char buf[100] ;
        if (prm_asmfile){
          int notyet = TRUE;
          nl();
          exitseg();
          for (i=0; i < HASHTABLESIZE; i++) {
            if ((sp=(SYM *) gsyms[i]) != 0) {
              while (sp) {
                if( sp->storage_class == sc_externalfunc && sp->extflag && !(sp->tp->cflags & DF_INTRINS)) {
									notyet = put_exfunc(sp,notyet) ;
      	        }
                 if (sp->exportable) {
                  if (notyet) {
                      if (!prm_nodos)
                        fprintf(outputFile,"\nSECTION _TEXT\n");
                      else {
                        fprintf(outputFile,"\nSECTION .text\n");
	                      fprintf(outputFile,"[BITS 32]\n");
  	                  }
    	                notyet = FALSE;
      	            }
                     putsym(buf,sp,sp->name) ;
                  if (prm_nasm)
                     fprintf(outputFile,"\texport %s\n",buf) ;
                  else
                     fprintf(outputFile,"\tpublicdll %s\n", buf) ;
                 }
        	      sp = sp->next;
          	  }
	          }
  	      }
            
              while (localfuncs) {
								sp = localfuncs->data ;
                if( sp->storage_class == sc_externalfunc && sp->extflag && !(sp->tp->cflags & DF_INTRINS)) {
                  notyet = put_exfunc(sp,notyet) ;
                }
                 if (sp->exportable) {
                  if (notyet) {
                      if (!prm_nodos)
                        fprintf(outputFile,"\nSECTION _TEXT\n");
                      else {
                        fprintf(outputFile,"\nSECTION .text\n");
	                      fprintf(outputFile,"[BITS 32]\n");
  	                  }
    	                notyet = FALSE;
      	            }
                     putsym(buf,sp,sp->name) ;
                  if (prm_nasm)
                     fprintf(outputFile,"\texport %s\n",buf) ;
                  else
                     fprintf(outputFile,"\tpublicdll %s\n", buf) ;
                 }
        	      localfuncs = localfuncs->link ;
          	  }
    	    notyet = TRUE;

           for (i=0; i < HASHTABLESIZE; i++) {
        	  if ((sp=(SYM *) gsyms[i]) != 0) {
          	  while (sp) {
            	  if( sp->storage_class == sc_external && sp->extflag) {
                  notyet = put_exfunc(sp,notyet) ;
	              }
  	            sp = sp->next;
    	        }
      	    }

        	}
	        if (!prm_nasm) {
  	        if (libincludes) {
    	        while (libincludes) {
      	        fprintf(outputFile,"\tINCLUDELIB\t%s\n",libincludes->data);
        	      libincludes = libincludes->link;
          	  }
            	fputc('\n',outputFile);
	          }
  	        fprintf(outputFile,"\tEND\n");
    	    }
      	}
}
