#include <ctype.h>
#define EXTERN
#include "a.h"
#include "y.tab.h"

void
main(int argc, char *argv[])
{
       char *p;
       int nout, nproc, status, i, c;

       thechar = '8';
       thestring = "386";
       memset(debug, 0, sizeof(debug));
       cinit();
       outfile = 0;
       include[ninclude++] = ".";
       ARGBEGIN {
       default:
               c = ARGC();
               if(c >= 0 || c < sizeof(debug))
                       debug[c] = 1;
               break;

       case 'o':
               outfile = ARGF();
               break;

       case 'D':
               p = ARGF();
               if(p)
                       Dlist[nDlist++] = p;
               break;

       case 'I':
               p = ARGF();
               setinclude(p);
               break;
       } ARGEND
       if(*argv == 0) {
               print("usage: %ca [-options] file.s\n", thechar);
               errorexit();
       }
       if(argc > 1 && systemtype(Windows)){
               print("can't assemble multiple files on windows\n");
               errorexit();
       }
       if(argc > 1 && !systemtype(Windows)) {
               nproc = 1;
               if(p = getenv("NPROC"))
                       nproc = atol(p);        /* */
               c = 0;
               nout = 0;
               for(;;) {
                       while(nout < nproc && argc > 0) {
                               i = myfork();
                               if(i < 0) {
                                       i = mywait(&status);
                                       if(i < 0)
                                               errorexit();
                                       if(status)
                                               c++;
                                       nout--;
                                       continue;
                               }
                               if(i == 0) {
                                       print("%s:\n", *argv);
                                       if(assemble(*argv))
                                               errorexit();
                                       exits(0);
                               }
                               nout++;
                               argc--;
                               argv++;
                       }
                       i = mywait(&status);
                       if(i < 0) {
                               if(c)
                                       errorexit();
                               exits(0);
                       }
                       if(status)
                               c++;
                       nout--;
               }
       }
       if(assemble(argv[0]))
               errorexit();
       exits(0);
}

int
assemble(char *file)
{
       char ofile[100], incfile[20], *p;
       int i, of;

       strcpy(ofile, file);
       p = utfrrune(ofile, pathchar());
       if(p) {
               include[0] = ofile;
               *p++ = 0;
       } else
               p = ofile;
       if(outfile == 0) {
               outfile = p;
               if(outfile){
                       p = utfrrune(outfile, '.');
                       if(p)
                               if(p[1] == 's' && p[2] == 0)
                                       p[0] = 0;
                       p = utfrune(outfile, 0);
                       p[0] = '.';
                       p[1] = thechar;
                       p[2] = 0;
               } else
                       outfile = "/dev/null";
       }
       p = getenv("INCLUDE");
       if(p) {
               setinclude(p);
       } else {
               if(systemtype(Plan9)) {
                       sprint(incfile,"/%s/include", thestring);
                       setinclude(strdup(incfile));
               }
       }

       of = mycreat(outfile, 0664);
       if(of < 0) {
               yyerror("%ca: cannot create %s", thechar, outfile);
               errorexit();
       }
       Binit(&obuf, of, OWRITE);

       pass = 1;
       pinit(file);
       for(i=0; i<nDlist; i++)
               dodefine(Dlist[i]);
       yyparse();
       if(nerrors) {
               cclean();
               return nerrors;
       }

       pass = 2;
       outhist();
       pinit(file);
       for(i=0; i<nDlist; i++)
               dodefine(Dlist[i]);
       yyparse();
       cclean();
       return nerrors;
}

struct
{
       char    *name;
       ushort  type;
       ushort  value;
} itab[] =
{
       "SP",           LSP,    D_AUTO,
       "SB",           LSB,    D_EXTERN,
       "FP",           LFP,    D_PARAM,
       "PC",           LPC,    D_BRANCH,

       "AL",           LBREG,  D_AL,
       "CL",           LBREG,  D_CL,
       "DL",           LBREG,  D_DL,
       "BL",           LBREG,  D_BL,
       "AH",           LBREG,  D_AH,
       "CH",           LBREG,  D_CH,
       "DH",           LBREG,  D_DH,
       "BH",           LBREG,  D_BH,

       "AX",           LLREG,  D_AX,
       "CX",           LLREG,  D_CX,
       "DX",           LLREG,  D_DX,
       "BX",           LLREG,  D_BX,
/*      "SP",           LLREG,  D_SP,   */
       "BP",           LLREG,  D_BP,
       "SI",           LLREG,  D_SI,
       "DI",           LLREG,  D_DI,

       "F0",           LFREG,  D_F0+0,
       "F1",           LFREG,  D_F0+1,
       "F2",           LFREG,  D_F0+2,
       "F3",           LFREG,  D_F0+3,
       "F4",           LFREG,  D_F0+4,
       "F5",           LFREG,  D_F0+5,
       "F6",           LFREG,  D_F0+6,
       "F7",           LFREG,  D_F0+7,

       "CS",           LSREG,  D_CS,
       "SS",           LSREG,  D_SS,
       "DS",           LSREG,  D_DS,
       "ES",           LSREG,  D_ES,
       "FS",           LSREG,  D_FS,
       "GS",           LSREG,  D_GS,

       "GDTR",         LBREG,  D_GDTR,
       "IDTR",         LBREG,  D_IDTR,
       "LDTR",         LBREG,  D_LDTR,
       "MSW",          LBREG,  D_MSW,
       "TASK",         LBREG,  D_TASK,

       "CR0",          LBREG,  D_CR+0,
       "CR1",          LBREG,  D_CR+1,
       "CR2",          LBREG,  D_CR+2,
       "CR3",          LBREG,  D_CR+3,
       "CR4",          LBREG,  D_CR+4,
       "CR5",          LBREG,  D_CR+5,
       "CR6",          LBREG,  D_CR+6,
       "CR7",          LBREG,  D_CR+7,

       "DR0",          LBREG,  D_DR+0,
       "DR1",          LBREG,  D_DR+1,
       "DR2",          LBREG,  D_DR+2,
       "DR3",          LBREG,  D_DR+3,
       "DR4",          LBREG,  D_DR+4,
       "DR5",          LBREG,  D_DR+5,
       "DR6",          LBREG,  D_DR+6,
       "DR7",          LBREG,  D_DR+7,

       "TR0",          LBREG,  D_TR+0,
       "TR1",          LBREG,  D_TR+1,
       "TR2",          LBREG,  D_TR+2,
       "TR3",          LBREG,  D_TR+3,
       "TR4",          LBREG,  D_TR+4,
       "TR5",          LBREG,  D_TR+5,
       "TR6",          LBREG,  D_TR+6,
       "TR7",          LBREG,  D_TR+7,

       "AAA",          LTYPE0, AAAA,
       "AAD",          LTYPE0, AAAD,
       "AAM",          LTYPE0, AAAM,
       "AAS",          LTYPE0, AAAS,
       "ADCB",         LTYPE3, AADCB,
       "ADCL",         LTYPE3, AADCL,
       "ADCW",         LTYPE3, AADCW,
       "ADDB",         LTYPE3, AADDB,
       "ADDL",         LTYPE3, AADDL,
       "ADDW",         LTYPE3, AADDW,
       "ADJSP",        LTYPE2, AADJSP,
       "ANDB",         LTYPE3, AANDB,
       "ANDL",         LTYPE3, AANDL,
       "ANDW",         LTYPE3, AANDW,
       "ARPL",         LTYPE3, AARPL,
       "BOUNDL",       LTYPE3, ABOUNDL,
       "BOUNDW",       LTYPE3, ABOUNDW,
       "BSFL",         LTYPE3, ABSFL,
       "BSFW",         LTYPE3, ABSFW,
       "BSRL",         LTYPE3, ABSRL,
       "BSRW",         LTYPE3, ABSRW,
       "BTCL",         LTYPE3, ABTCL,
       "BTCW",         LTYPE3, ABTCW,
       "BTL",          LTYPE3, ABTL,
       "BTRL",         LTYPE3, ABTRL,
       "BTRW",         LTYPE3, ABTRW,
       "BTSL",         LTYPE3, ABTSL,
       "BTSW",         LTYPE3, ABTSW,
       "BTW",          LTYPE3, ABTW,
       "BYTE",         LTYPE2, ABYTE,
       "CALL",         LTYPEC, ACALL,
       "CLC",          LTYPE0, ACLC,
       "CLD",          LTYPE0, ACLD,
       "CLI",          LTYPE0, ACLI,
       "CLTS",         LTYPE0, ACLTS,
       "CMC",          LTYPE0, ACMC,
       "CMPB",         LTYPE4, ACMPB,
       "CMPL",         LTYPE4, ACMPL,
       "CMPW",         LTYPE4, ACMPW,
       "CMPSB",        LTYPE0, ACMPSB,
       "CMPSL",        LTYPE0, ACMPSL,
       "CMPSW",        LTYPE0, ACMPSW,
       "DAA",          LTYPE0, ADAA,
       "DAS",          LTYPE0, ADAS,
       "DATA",         LTYPED, ADATA,
       "DECB",         LTYPE1, ADECB,
       "DECL",         LTYPE1, ADECL,
       "DECW",         LTYPE1, ADECW,
       "DIVB",         LTYPE2, ADIVB,
       "DIVL",         LTYPE2, ADIVL,
       "DIVW",         LTYPE2, ADIVW,
       "END",          LTYPE0, AEND,
       "ENTER",        LTYPE2, AENTER,
       "GLOBL",        LTYPET, AGLOBL,
       "HLT",          LTYPE0, AHLT,
       "IDIVB",        LTYPE2, AIDIVB,
       "IDIVL",        LTYPE2, AIDIVL,
       "IDIVW",        LTYPE2, AIDIVW,
       "IMULB",        LTYPE2, AIMULB,
       "IMULL",        LTYPE2, AIMULL,
       "IMULW",        LTYPE2, AIMULW,
       "INB",          LTYPE0, AINB,
       "INL",          LTYPE0, AINL,
       "INW",          LTYPE0, AINW,
       "INCB",         LTYPE1, AINCB,
       "INCL",         LTYPE1, AINCL,
       "INCW",         LTYPE1, AINCW,
       "INSB",         LTYPE0, AINSB,
       "INSL",         LTYPE0, AINSL,
       "INSW",         LTYPE0, AINSW,
       "INT",          LTYPE2, AINT,
       "INTO",         LTYPE0, AINTO,
       "IRETL",        LTYPE0, AIRETL,
       "IRETW",        LTYPE0, AIRETW,

       "JOS",          LTYPER, AJOS,
       "JO",           LTYPER, AJOS,   /* alternate */
       "JOC",          LTYPER, AJOC,
       "JNO",          LTYPER, AJOC,   /* alternate */
       "JCS",          LTYPER, AJCS,
       "JB",           LTYPER, AJCS,   /* alternate */
       "JC",           LTYPER, AJCS,   /* alternate */
       "JNAE",         LTYPER, AJCS,   /* alternate */
       "JLO",          LTYPER, AJCS,   /* alternate */
       "JCC",          LTYPER, AJCC,
       "JAE",          LTYPER, AJCC,   /* alternate */
       "JNB",          LTYPER, AJCC,   /* alternate */
       "JNC",          LTYPER, AJCC,   /* alternate */
       "JHS",          LTYPER, AJCC,   /* alternate */
       "JEQ",          LTYPER, AJEQ,
       "JE",           LTYPER, AJEQ,   /* alternate */
       "JZ",           LTYPER, AJEQ,   /* alternate */
       "JNE",          LTYPER, AJNE,
       "JNZ",          LTYPER, AJNE,   /* alternate */
       "JLS",          LTYPER, AJLS,
       "JBE",          LTYPER, AJLS,   /* alternate */
       "JNA",          LTYPER, AJLS,   /* alternate */
       "JHI",          LTYPER, AJHI,
       "JA",           LTYPER, AJHI,   /* alternate */
       "JNBE",         LTYPER, AJHI,   /* alternate */
       "JMI",          LTYPER, AJMI,
       "JS",           LTYPER, AJMI,   /* alternate */
       "JPL",          LTYPER, AJPL,
       "JNS",          LTYPER, AJPL,   /* alternate */
       "JPS",          LTYPER, AJPS,
       "JP",           LTYPER, AJPS,   /* alternate */
       "JPE",          LTYPER, AJPS,   /* alternate */
       "JPC",          LTYPER, AJPC,
       "JNP",          LTYPER, AJPC,   /* alternate */
       "JPO",          LTYPER, AJPC,   /* alternate */
       "JLT",          LTYPER, AJLT,
       "JL",           LTYPER, AJLT,   /* alternate */
       "JNGE",         LTYPER, AJLT,   /* alternate */
       "JGE",          LTYPER, AJGE,
       "JNL",          LTYPER, AJGE,   /* alternate */
       "JLE",          LTYPER, AJLE,
       "JNG",          LTYPER, AJLE,   /* alternate */
       "JGT",          LTYPER, AJGT,
       "JG",           LTYPER, AJGT,   /* alternate */
       "JNLE",         LTYPER, AJGT,   /* alternate */

       "JCXZ",         LTYPER, AJCXZ,
       "JMP",          LTYPEC, AJMP,
       "LAHF",         LTYPE0, ALAHF,
       "LARL",         LTYPE3, ALARL,
       "LARW",         LTYPE3, ALARW,
       "LEAL",         LTYPE3, ALEAL,
       "LEAW",         LTYPE3, ALEAW,
       "LEAVEL",       LTYPE0, ALEAVEL,
       "LEAVEW",       LTYPE0, ALEAVEW,
       "LOCK",         LTYPE0, ALOCK,
       "LODSB",        LTYPE0, ALODSB,
       "LODSL",        LTYPE0, ALODSL,
       "LODSW",        LTYPE0, ALODSW,
       "LONG",         LTYPE2, ALONG,
       "LOOP",         LTYPER, ALOOP,
       "LOOPEQ",       LTYPER, ALOOPEQ,
       "LOOPNE",       LTYPER, ALOOPNE,
       "LSLL",         LTYPE3, ALSLL,
       "LSLW",         LTYPE3, ALSLW,
       "MOVB",         LTYPE3, AMOVB,
       "MOVL",         LTYPEM, AMOVL,
       "MOVW",         LTYPEM, AMOVW,
       "MOVBLSX",      LTYPE3, AMOVBLSX,
       "MOVBLZX",      LTYPE3, AMOVBLZX,
       "MOVBWSX",      LTYPE3, AMOVBWSX,
       "MOVBWZX",      LTYPE3, AMOVBWZX,
       "MOVWLSX",      LTYPE3, AMOVWLSX,
       "MOVWLZX",      LTYPE3, AMOVWLZX,
       "MOVSB",        LTYPE0, AMOVSB,
       "MOVSL",        LTYPE0, AMOVSL,
       "MOVSW",        LTYPE0, AMOVSW,
       "MULB",         LTYPE2, AMULB,
       "MULL",         LTYPE2, AMULL,
       "MULW",         LTYPE2, AMULW,
       "NEGB",         LTYPE1, ANEGB,
       "NEGL",         LTYPE1, ANEGL,
       "NEGW",         LTYPE1, ANEGW,
       "NOP",          LTYPEN, ANOP,
       "NOTB",         LTYPE1, ANOTB,
       "NOTL",         LTYPE1, ANOTL,
       "NOTW",         LTYPE1, ANOTW,
       "ORB",          LTYPE3, AORB,
       "ORL",          LTYPE3, AORL,
       "ORW",          LTYPE3, AORW,
       "OUTB",         LTYPE0, AOUTB,
       "OUTL",         LTYPE0, AOUTL,
       "OUTW",         LTYPE0, AOUTW,
       "OUTSB",        LTYPE0, AOUTSB,
       "OUTSL",        LTYPE0, AOUTSL,
       "OUTSW",        LTYPE0, AOUTSW,
       "POPAL",        LTYPE0, APOPAL,
       "POPAW",        LTYPE0, APOPAW,
       "POPFL",        LTYPE0, APOPFL,
       "POPFW",        LTYPE0, APOPFW,
       "POPL",         LTYPE1, APOPL,
       "POPW",         LTYPE1, APOPW,
       "PUSHAL",       LTYPE0, APUSHAL,
       "PUSHAW",       LTYPE0, APUSHAW,
       "PUSHFL",       LTYPE0, APUSHFL,
       "PUSHFW",       LTYPE0, APUSHFW,
       "PUSHL",        LTYPE2, APUSHL,
       "PUSHW",        LTYPE2, APUSHW,
       "RCLB",         LTYPE3, ARCLB,
       "RCLL",         LTYPE3, ARCLL,
       "RCLW",         LTYPE3, ARCLW,
       "RCRB",         LTYPE3, ARCRB,
       "RCRL",         LTYPE3, ARCRL,
       "RCRW",         LTYPE3, ARCRW,
       "REP",          LTYPE0, AREP,
       "REPN",         LTYPE0, AREPN,
       "RET",          LTYPE0, ARET,
       "ROLB",         LTYPE3, AROLB,
       "ROLL",         LTYPE3, AROLL,
       "ROLW",         LTYPE3, AROLW,
       "RORB",         LTYPE3, ARORB,
       "RORL",         LTYPE3, ARORL,
       "RORW",         LTYPE3, ARORW,
       "SAHF",         LTYPE0, ASAHF,
       "SALB",         LTYPE3, ASALB,
       "SALL",         LTYPE3, ASALL,
       "SALW",         LTYPE3, ASALW,
       "SARB",         LTYPE3, ASARB,
       "SARL",         LTYPE3, ASARL,
       "SARW",         LTYPE3, ASARW,
       "SBBB",         LTYPE3, ASBBB,
       "SBBL",         LTYPE3, ASBBL,
       "SBBW",         LTYPE3, ASBBW,
       "SCASB",        LTYPE0, ASCASB,
       "SCASL",        LTYPE0, ASCASL,
       "SCASW",        LTYPE0, ASCASW,
       "SETCC",        LTYPE1, ASETCC,
       "SETCS",        LTYPE1, ASETCS,
       "SETEQ",        LTYPE1, ASETEQ,
       "SETGE",        LTYPE1, ASETGE,
       "SETGT",        LTYPE1, ASETGT,
       "SETHI",        LTYPE1, ASETHI,
       "SETLE",        LTYPE1, ASETLE,
       "SETLS",        LTYPE1, ASETLS,
       "SETLT",        LTYPE1, ASETLT,
       "SETMI",        LTYPE1, ASETMI,
       "SETNE",        LTYPE1, ASETNE,
       "SETOC",        LTYPE1, ASETOC,
       "SETOS",        LTYPE1, ASETOS,
       "SETPC",        LTYPE1, ASETPC,
       "SETPL",        LTYPE1, ASETPL,
       "SETPS",        LTYPE1, ASETPS,
       "CDQ",          LTYPE0, ACDQ,
       "CWD",          LTYPE0, ACWD,
       "SHLB",         LTYPE3, ASHLB,
       "SHLL",         LTYPES, ASHLL,
       "SHLW",         LTYPES, ASHLW,
       "SHRB",         LTYPE3, ASHRB,
       "SHRL",         LTYPES, ASHRL,
       "SHRW",         LTYPES, ASHRW,
       "STC",          LTYPE0, ASTC,
       "STD",          LTYPE0, ASTD,
       "STI",          LTYPE0, ASTI,
       "STOSB",        LTYPE0, ASTOSB,
       "STOSL",        LTYPE0, ASTOSL,
       "STOSW",        LTYPE0, ASTOSW,
       "SUBB",         LTYPE3, ASUBB,
       "SUBL",         LTYPE3, ASUBL,
       "SUBW",         LTYPE3, ASUBW,
       "SYSCALL",      LTYPE0, ASYSCALL,
       "TESTB",        LTYPE3, ATESTB,
       "TESTL",        LTYPE3, ATESTL,
       "TESTW",        LTYPE3, ATESTW,
       "TEXT",         LTYPET, ATEXT,
       "VERR",         LTYPE2, AVERR,
       "VERW",         LTYPE2, AVERW,
       "WAIT",         LTYPE0, AWAIT,
       "WORD",         LTYPE2, AWORD,
       "XCHGB",        LTYPE3, AXCHGB,
       "XCHGL",        LTYPE3, AXCHGL,
       "XCHGW",        LTYPE3, AXCHGW,
       "XLAT",         LTYPE2, AXLAT,
       "XORB",         LTYPE3, AXORB,
       "XORL",         LTYPE3, AXORL,
       "XORW",         LTYPE3, AXORW,

       "FMOVB",        LTYPE3, AFMOVB,
       "FMOVBP",       LTYPE3, AFMOVBP,
       "FMOVD",        LTYPE3, AFMOVD,
       "FMOVDP",       LTYPE3, AFMOVDP,
       "FMOVF",        LTYPE3, AFMOVF,
       "FMOVFP",       LTYPE3, AFMOVFP,
       "FMOVL",        LTYPE3, AFMOVL,
       "FMOVLP",       LTYPE3, AFMOVLP,
       "FMOVV",        LTYPE3, AFMOVV,
       "FMOVVP",       LTYPE3, AFMOVVP,
       "FMOVW",        LTYPE3, AFMOVW,
       "FMOVWP",       LTYPE3, AFMOVWP,
       "FMOVX",        LTYPE3, AFMOVX,
       "FMOVXP",       LTYPE3, AFMOVXP,
       "FCOMB",        LTYPE3, AFCOMB,
       "FCOMBP",       LTYPE3, AFCOMBP,
       "FCOMD",        LTYPE3, AFCOMD,
       "FCOMDP",       LTYPE3, AFCOMDP,
       "FCOMDPP",      LTYPE3, AFCOMDPP,
       "FCOMF",        LTYPE3, AFCOMF,
       "FCOMFP",       LTYPE3, AFCOMFP,
       "FCOML",        LTYPE3, AFCOML,
       "FCOMLP",       LTYPE3, AFCOMLP,
       "FCOMW",        LTYPE3, AFCOMW,
       "FCOMWP",       LTYPE3, AFCOMWP,
       "FUCOM",        LTYPE3, AFUCOM,
       "FUCOMP",       LTYPE3, AFUCOMP,
       "FUCOMPP",      LTYPE3, AFUCOMPP,
       "FADDW",        LTYPE3, AFADDW,
       "FADDL",        LTYPE3, AFADDL,
       "FADDF",        LTYPE3, AFADDF,
       "FADDD",        LTYPE3, AFADDD,
       "FADDDP",       LTYPE3, AFADDDP,
       "FSUBDP",       LTYPE3, AFSUBDP,
       "FSUBW",        LTYPE3, AFSUBW,
       "FSUBL",        LTYPE3, AFSUBL,
       "FSUBF",        LTYPE3, AFSUBF,
       "FSUBD",        LTYPE3, AFSUBD,
       "FSUBRDP",      LTYPE3, AFSUBRDP,
       "FSUBRW",       LTYPE3, AFSUBRW,
       "FSUBRL",       LTYPE3, AFSUBRL,
       "FSUBRF",       LTYPE3, AFSUBRF,
       "FSUBRD",       LTYPE3, AFSUBRD,
       "FMULDP",       LTYPE3, AFMULDP,
       "FMULW",        LTYPE3, AFMULW,
       "FMULL",        LTYPE3, AFMULL,
       "FMULF",        LTYPE3, AFMULF,
       "FMULD",        LTYPE3, AFMULD,
       "FDIVDP",       LTYPE3, AFDIVDP,
       "FDIVW",        LTYPE3, AFDIVW,
       "FDIVL",        LTYPE3, AFDIVL,
       "FDIVF",        LTYPE3, AFDIVF,
       "FDIVD",        LTYPE3, AFDIVD,
       "FDIVRDP",      LTYPE3, AFDIVRDP,
       "FDIVRW",       LTYPE3, AFDIVRW,
       "FDIVRL",       LTYPE3, AFDIVRL,
       "FDIVRF",       LTYPE3, AFDIVRF,
       "FDIVRD",       LTYPE3, AFDIVRD,
       "FXCHD",        LTYPE3, AFXCHD,
       "FFREE",        LTYPE1, AFFREE,
       "FLDCW",        LTYPE2, AFLDCW,
       "FLDENV",       LTYPE1, AFLDENV,
       "FRSTOR",       LTYPE2, AFRSTOR,
       "FSAVE",        LTYPE1, AFSAVE,
       "FSTCW",        LTYPE1, AFSTCW,
       "FSTENV",       LTYPE1, AFSTENV,
       "FSTSW",        LTYPE1, AFSTSW,
       "F2XM1",        LTYPE0, AF2XM1,
       "FABS",         LTYPE0, AFABS,
       "FCHS",         LTYPE0, AFCHS,
       "FCLEX",        LTYPE0, AFCLEX,
       "FCOS",         LTYPE0, AFCOS,
       "FDECSTP",      LTYPE0, AFDECSTP,
       "FINCSTP",      LTYPE0, AFINCSTP,
       "FINIT",        LTYPE0, AFINIT,
       "FLD1",         LTYPE0, AFLD1,
       "FLDL2E",       LTYPE0, AFLDL2E,
       "FLDL2T",       LTYPE0, AFLDL2T,
       "FLDLG2",       LTYPE0, AFLDLG2,
       "FLDLN2",       LTYPE0, AFLDLN2,
       "FLDPI",        LTYPE0, AFLDPI,
       "FLDZ",         LTYPE0, AFLDZ,
       "FNOP",         LTYPE0, AFNOP,
       "FPATAN",       LTYPE0, AFPATAN,
       "FPREM",        LTYPE0, AFPREM,
       "FPREM1",       LTYPE0, AFPREM1,
       "FPTAN",        LTYPE0, AFPTAN,
       "FRNDINT",      LTYPE0, AFRNDINT,
       "FSCALE",       LTYPE0, AFSCALE,
       "FSIN",         LTYPE0, AFSIN,
       "FSINCOS",      LTYPE0, AFSINCOS,
       "FSQRT",        LTYPE0, AFSQRT,
       "FTST",         LTYPE0, AFTST,
       "FXAM",         LTYPE0, AFXAM,
       "FXTRACT",      LTYPE0, AFXTRACT,
       "FYL2X",        LTYPE0, AFYL2X,
       "FYL2XP1",      LTYPE0, AFYL2XP1,

       0
};

void
cinit(void)
{
       Sym *s;
       int i;

       nullgen.sym = S;
       nullgen.offset = 0;
       if(FPCHIP)
               nullgen.dval = 0;
       for(i=0; i<sizeof(nullgen.sval); i++)
               nullgen.sval[i] = 0;
       nullgen.type = D_NONE;
       nullgen.index = D_NONE;
       nullgen.scale = 0;

       nerrors = 0;
       iostack = I;
       iofree = I;
       peekc = IGN;
       nhunk = 0;
       for(i=0; i<NHASH; i++)
               hash[i] = S;
       for(i=0; itab[i].name; i++) {
               s = slookup(itab[i].name);
               if(s->type != LNAME)
                       yyerror("double initialization %s", itab[i].name);
               s->type = itab[i].type;
               s->value = itab[i].value;
       }

       pathname = allocn(pathname, 0, 100);
       if(mygetwd(pathname, 99) == 0) {
               pathname = allocn(pathname, 100, 900);
               if(mygetwd(pathname, 999) == 0)
                       strcpy(pathname, "/???");
       }
}

void
checkscale(int scale)
{

       switch(scale) {
       case 1:
       case 2:
       case 4:
       case 8:
               return;
       }
       yyerror("scale must be 1248: %d", scale);
}

void
syminit(Sym *s)
{

       s->type = LNAME;
       s->value = 0;
}

void
cclean(void)
{
       Gen2 g2;

       g2.from = nullgen;
       g2.to = nullgen;
       outcode(AEND, &g2);
       Bflush(&obuf);
}

void
zname(char *n, int t, int s)
{

       Bputc(&obuf, ANAME);            /* as(2) */
       Bputc(&obuf, ANAME>>8);
       Bputc(&obuf, t);                /* type */
       Bputc(&obuf, s);                /* sym */
       while(*n) {
               Bputc(&obuf, *n);
               n++;
       }
       Bputc(&obuf, 0);
}

void
zaddr(Gen *a, int s)
{
       long l;
       int i, t;
       char *n;
       Ieee e;

       t = 0;
       if(a->index != D_NONE || a->scale != 0)
               t |= T_INDEX;
       if(a->offset != 0)
               t |= T_OFFSET;
       if(s != 0)
               t |= T_SYM;

       switch(a->type) {
       default:
               t |= T_TYPE;
               break;
       case D_FCONST:
               t |= T_FCONST;
               break;
       case D_SCONST:
               t |= T_SCONST;
               break;
       case D_NONE:
               break;
       }
       Bputc(&obuf, t);

       if(t & T_INDEX) {       /* implies index, scale */
               Bputc(&obuf, a->index);
               Bputc(&obuf, a->scale);
       }
       if(t & T_OFFSET) {      /* implies offset */
               l = a->offset;
               Bputc(&obuf, l);
               Bputc(&obuf, l>>8);
               Bputc(&obuf, l>>16);
               Bputc(&obuf, l>>24);
       }
       if(t & T_SYM)           /* implies sym */
               Bputc(&obuf, s);
       if(t & T_FCONST) {
               ieeedtod(&e, a->dval);
               l = e.l;
               Bputc(&obuf, l);
               Bputc(&obuf, l>>8);
               Bputc(&obuf, l>>16);
               Bputc(&obuf, l>>24);
               l = e.h;
               Bputc(&obuf, l);
               Bputc(&obuf, l>>8);
               Bputc(&obuf, l>>16);
               Bputc(&obuf, l>>24);
               return;
       }
       if(t & T_SCONST) {
               n = a->sval;
               for(i=0; i<NSNAME; i++) {
                       Bputc(&obuf, *n);
                       n++;
               }
               return;
       }
       if(t & T_TYPE)
               Bputc(&obuf, a->type);
}

void
outcode(int a, Gen2 *g2)
{
       int sf, st, t;
       Sym *s;

       if(pass == 1)
               goto out;

jackpot:
       sf = 0;
       s = g2->from.sym;
       while(s != S) {
               sf = s->sym;
               if(sf < 0 || sf >= NSYM)
                       sf = 0;
               t = g2->from.type;
               if(t == D_ADDR)
                       t = g2->from.index;
               if(h[sf].type == t)
               if(h[sf].sym == s)
                       break;
               zname(s->name, t, sym);
               s->sym = sym;
               h[sym].sym = s;
               h[sym].type = t;
               sf = sym;
               sym++;
               if(sym >= NSYM)
                       sym = 1;
               break;
       }
       st = 0;
       s = g2->to.sym;
       while(s != S) {
               st = s->sym;
               if(st < 0 || st >= NSYM)
                       st = 0;
               t = g2->to.type;
               if(t == D_ADDR)
                       t = g2->to.index;
               if(h[st].type == t)
               if(h[st].sym == s)
                       break;
               zname(s->name, t, sym);
               s->sym = sym;
               h[sym].sym = s;
               h[sym].type = t;
               st = sym;
               sym++;
               if(sym >= NSYM)
                       sym = 1;
               if(st == sf)
                       goto jackpot;
               break;
       }
       Bputc(&obuf, a);
       Bputc(&obuf, a>>8);
       Bputc(&obuf, lineno);
       Bputc(&obuf, lineno>>8);
       Bputc(&obuf, lineno>>16);
       Bputc(&obuf, lineno>>24);
       zaddr(&g2->from, sf);
       zaddr(&g2->to, st);

out:
       if(a != AGLOBL && a != ADATA)
               pc++;
}

void
outhist(void)
{
       Gen g;
       Hist *h;
       char *p, *q, *op, c;
       int n;

       g = nullgen;
       c = pathchar();
       for(h = hist; h != H; h = h->link) {
               p = h->name;
               op = 0;
               if(p && p[0] != c && h->offset == 0 && pathname){
                       /* on windows skip drive specifier in pathname */
                       if(systemtype(Windows) && pathname[2] == c) {
                               op = p;
                               p = pathname+2;
                               *p = '/';
                       } else if(pathname[0] == c){
                               op = p;
                               p = pathname;
                       }
               }
               while(p) {
                       q = strchr(p, c);
                       if(q) {
                               n = q-p;
                               if(n == 0)
                                       n = 1;  /* leading "/" */
                               q++;
                       } else {
                               n = strlen(p);
                               q = 0;
                       }
                       if(n) {
                               Bputc(&obuf, ANAME);
                               Bputc(&obuf, ANAME>>8);
                               Bputc(&obuf, D_FILE);   /* type */
                               Bputc(&obuf, 1);        /* sym */
                               Bputc(&obuf, '<');
                               Bwrite(&obuf, p, n);
                               Bputc(&obuf, 0);
                       }
                       p = q;
                       if(p == 0 && op) {
                               p = op;
                               op = 0;
                       }
               }
               g.offset = h->offset;

               Bputc(&obuf, AHISTORY);
               Bputc(&obuf, AHISTORY>>8);
               Bputc(&obuf, h->line);
               Bputc(&obuf, h->line>>8);
               Bputc(&obuf, h->line>>16);
               Bputc(&obuf, h->line>>24);
               zaddr(&nullgen, 0);
               zaddr(&g, 0);
       }
}

void
praghjdicks(void)
{
       while(getnsc() != '\n')
               ;
}

void
pragvararg(void)
{
       while(getnsc() != '\n')
               ;
}

void
pragfpround(void)
{
       while(getnsc() != '\n')
               ;
}

#include "../cc/lexbody"
#include "../cc/macbody"
#include "../cc/compat"