/*
  Copyright (C) 1990-1998 The SPHiNX C-- Programming Team

  FILENAME   : SCC.C
  DESCRIPTION: Main part of SCC.EXE
  LAST EDITED: July 20, 1998
*/

#include <stdio.h>   /* standard stuff */
#include <stdlib.h>  /* getenv and _splitpath stuff */
#include <io.h>      /* low level file stuff */
#include <fcntl.h>   /* O_ constant definitions */
#include <malloc.h>  /* memory allocation */
#include <string.h>  /* string functions */
#include "scc.h"


int tok,tok2; /* token holders current, next */
int rm,rm2;
int segm,segm2;
int post,post2;
unsigned char string[STRLEN],string2[STRLEN];
long number,number2;

#define MAXPOSTS 15000
unsigned char *posttype;   /* [MAXPOSTS]; */
unsigned int *postloc;     /* [MAXPOSTS]; */
unsigned int *postnum;     /* [MAXPOSTS]; */
unsigned int posts=0;      /* number of post entrys */
unsigned int secondcallnum=0;  /* # of different second calls and labels */
unsigned int postsize=0;       /* total size of all post vars */
unsigned int poststrptr=MAXDATA-1;  /* post string index in output */

FILE *mapfile;  /* map file handle */
unsigned char rawdrive[_MAX_DRIVE],rawdir[_MAX_DIR];
unsigned char rawfname[_MAX_FNAME],rawext[_MAX_EXT];
unsigned char rawfilename[FILENAMESIZE];
unsigned char inputfile[FILENAMESIZE];
unsigned char currentfilename[FILENAMESIZE];
long runfilesize;

int error=0;     /* current error number holder */

int dos1=0,dos2=0;    /* DOS version required for program execution */
unsigned char cpu=0;  /* CPU required, 2 for 80286, 3 for 80386, ... */

unsigned int paramsize=0;  /* byte size of all procedure parameters */
unsigned int localsize=0;  /* byte size of all procedure local variables */
unsigned int procedure_start=0; /* address of start of procedure */

int current_proc_type;   /* current procedure type (cpt_near, cpt_far, cpt_interrupt) */
int returntype;          /* return type, (void, byte, word, ...) */

#define DYNAMIC_HEADER 5 /* size in bytes of header in each dynamic buffer:
                    byte 0 and 1:  size of dynamic proc.
                          byte 2:  cpu required.
                          byte 3:  high version number of DOS required.
                          byte 4:  low version number of DOS required.
                         */
unsigned char *dynamic_ptrs[MAXDYNAMICS];
                          /* ptrs to stored dynamic procedures */
int dynamic_flag=NOT_DYNAMIC;  /* flag set number of current dynamic proc */
int dynamic_count=0;  /* current number of dynamic procedures */

unsigned int exeheader[16];  // 0x20 byte header for EXE format

/*+++++++++++++++++++++++ flexable compiler options +++++++++++++++++++++++*/
unsigned int  startptr = 0x100;       // start address
unsigned int  startptrdata = 0x100;   // data start address
unsigned char comfile = file_com;     // output file format
unsigned char makemapfile = 0;        // create map file
unsigned char jumptomain = CALL_NEAR; // jump to the main()
unsigned char optimizespeed = 1;      // optimize for size or speed flag
unsigned char parsecommandline = 0;   // parse command line flag
unsigned int  newcommandlineaddr = 0; // address of new command line
unsigned char alignword = 1;          // flag whether or not to align words
unsigned char aligner = 0;            // value used to align words
unsigned char header = 1;             // output SPHINX C-- Ver1 Ver2 header
unsigned char chip = 0;               // CPU optimization (286,386,486,...)
unsigned char killctrlc = 0;          // add disable CTRL-C code in header
unsigned char assumeDSSS = 0;         // assume SS is equal to DS
unsigned char stackcheck = 0;         // display stack available in tokscan
unsigned char resizemem = 1;          // set owned memory block to 64K
unsigned int  stacksize = 2048;       // stack size (2048 default)
unsigned char *resizemessage = NULL;  // resize memory error message
unsigned int  maxerrors = 16;         // number of errors to stop at
/*+++++++++++++++++++ end of flexable compiler options ++++++++++++++++++++*/
unsigned char notdoneprestuff = 1; // flag if initial stuff has been entered

unsigned int datasize=0,alignersize=0;  /* size of data and other */
unsigned int outptr=0x100,outptrdata=0x100;       /* ptr to output */
unsigned char *output;           /* [MAXDATA]; */
unsigned char *outputdata=NULL;  /* [MAXDATA]; */
unsigned int resizesizeaddress;  /* location of resize memory size descr. */
unsigned int stackstartaddress;  /* location of SP assignment */

unsigned int linenumber;
extern unsigned int endifcount;

unsigned char ver1=1,ver2=04;
unsigned char compilerstr[] = "SPHiNX C-- v1.04";

unsigned char compilerdir[FILENAMESIZE]; /* value of "C--" environment var */

/******************* function predefinitions ********************/

unsigned int addpoststring ();  /* add a string to the post queue */


/****************************** main () *********************************/


void startsymbiosys (symfile)
unsigned char *symfile;
{unsigned int size=0,filehandle,addresshold;
long filesize;

outptr = startptr;
filehandle = open( symfile, O_BINARY | O_RDONLY );
if( filehandle == -1 )
    {puts("ERROR> unable to open symbio COM file.");
    exit(e_symbioerror);}
if( (filesize=filelength(filehandle)) != -1L )
    {if( filesize+outptr < MAXDATA )
        {size = filesize;
        if( read(filehandle,output+outptr,size) != size )
            {close(filehandle);
            puts("Error reading symbio COM file.");
            exit(e_symbioerror);}
        outptr += size;
        }
    else{puts("Symbio COM file too large.");
        exit(e_symbioerror);}
    }
else{puts("Unable to determine symbio COM file size.");
    exit(e_symbioerror);
    }
close(filehandle);
outptrdata = outptr;
addresshold = outptr;
pushax();
pushbx();
pushcx();
pushdx();
pushdi();
pushsi();
pushbp();
pushes();
tok = tk_ID;
strcpy(string,"main");
tobedefined(CALL_NEAR,tk_void);  /* put main on the to be defined stack */
op(0xE8); outword(0);   /* CALL main() */
op(0xC7);  op(0x06);
outword(0x0100);
op(output[startptr]);
op(output[startptr+1]);  /* MOV WORD PTR [0100],(0x100)(0x101) */
op(0xC6); op(0x06);
outword(0x0102);
op(output[startptr+2]);  /* MOV BYTE PTR [0102],(0x102) */
popes();
popbp();
popsi();
popdi();
popdx();
popcx();
popbx();
popax();
op(0xE9);  outword(startptr-(outptr+2));   /* JMP startptr */

output[startptr]=0xE9;                  /* set     */
addresshold = addresshold-(startptr+3); /* inital  */
output[startptr+1]=addresshold&255;     /* code to */
output[startptr+2]=addresshold/256;     /* jump    */

notdoneprestuff = 0;
}


void compile ()
{long segments_required;
long longhold;

if(makemapfile)
    startmapfile();
printf("Compiling Commenced . . .\n");
sprintf(inputfile,"%s.C--",rawfilename);
currentfilename[0] = 0;       /* set current filename to nothing */
linenumber = 0;
compilefile(inputfile,1);
if( notdoneprestuff )
    doprestuff();
if( endifcount > 0 )
    preerror("?endif expected before end of file");
docalls();  /* attempt to declare remaining undeclared calls */
if( comfile == file_exe )           // if an EXE file
    {if( outptr%16 != 0 )    // paragraph align the end of the code seg
        outptr += 16 - outptr%16;
    }
else{
    longhold = outptr+postsize+stacksize;
    if( longhold > 65536L )
        preerror("Code, data and stack total exceeds 64k");
    }

if(posts > 0)
    doposts();  /* update all post address locations */
if(resizemem)
    {segments_required = (outptr+postsize+stacksize+15) /16;
    output[resizesizeaddress] = segments_required % 256;
    output[resizesizeaddress+1] = segments_required / 256;
    output[stackstartaddress] = segments_required*16 % 256;
    output[stackstartaddress+1] = segments_required*16 / 256;
    }
if(error==0)
    {printf("COMPILING FINISHED.   Errors: %d   Lines: %u\n",error,linenumber);
    if(dos1 > 0)
        printf("DOS required: %d.%d or greater.\n",dos1,dos2);
    if(cpu >= 1)
        printf("CPU required: 80%d86 or greater.\n",cpu);
    runfilesize = outptr-startptr;
    if( comfile == file_exe )
        {runfilesize += outptrdata-startptrdata+0x20;
        postsize += postsize%2;
        stacksize = (stacksize+15)/16*16;
        }
    if(makemapfile)
        finishmapfile();
    printmemsizes(stdout);
    if(writeoutput(0)==0)
        printf("Run File Saved (%ld bytes).\n",runfilesize);
    }
else if(makemapfile)
    finishmapfile();
}



char *pptr;   /* used for pointing to current command line entry */

main (argc,argv)
int argc;
char *argv[];
{int count,pari = 0;
printf("SPHiNX C-- Version %d.%.2d\n", ver1, ver2);
  puts("Copyright (C) 1990-1998 The SPHiNX C-- Programming Team\n");

getmem();   /* allocate buffers */

if( getenv("C--") )
    {strcpy(compilerdir,getenv("C--"));
    if( strlen(compilerdir) > 0 && compilerdir[strlen(compilerdir)-1]!='\\' )
        strcat(compilerdir,"\\");
    }
else{
    strcpy(compilerdir,argv[0]);
    count = strlen(compilerdir);
    while( count > 0 && compilerdir[count] != '\\' )
        count--;
    if( compilerdir[count] == '\\' )
        count++;
    compilerdir[count] = 0;
    }

for(count=1;count<argc;count++)    /* command line params handled here */
    {strupr(argv[count]);
    if(argv[count][0]=='/')
        {pptr = argv[count]+1;
        if( strcmp("-MAIN",pptr)==0 || strcmp("J0",pptr)==0 )
            {jumptomain = CALL_NONE;
            header = 0;}
        else if( strcmp("SHORTMAIN",pptr)==0 || strcmp("J1",pptr)==0 )
            {jumptomain = CALL_SHORT;
            header = 1;}
        else if( strcmp("+MAIN",pptr)==0 || strcmp("J2",pptr)==0 )
            {jumptomain = CALL_NEAR;
            header = 1;}
        else if(strcmp("-CTRLC",pptr)==0 || strcmp("-C",pptr)==0)
            killctrlc = 0;
        else if(strcmp("+CTRLC",pptr)==0 || strcmp("+C",pptr)==0)
            killctrlc = 1;
        else if(strcmp("SPEED",pptr)==0 || strcmp("OS",pptr)==0)
            optimizespeed = 1;
        else if(strcmp("SIZE",pptr)==0 || strcmp("OC",pptr)==0)
            optimizespeed = 0;
        else if(strcmp("-RESIZE",pptr)==0 || strcmp("-R",pptr)==0)
            resizemem = 0;
        else if(strcmp("+RESIZE",pptr)==0 || strcmp("+R",pptr)==0)
            resizemem = 1;
        else if(strcmp("-PARSE",pptr)==0 || strcmp("-P",pptr)==0)
            parsecommandline = 0;
        else if(strcmp("+PARSE",pptr)==0 || strcmp("+P",pptr)==0)
            parsecommandline = 1;
        else if(strcmp("-ALIGN",pptr)==0 || strcmp("-A",pptr)==0)
            alignword = 0;
        else if(strcmp("+ALIGN",pptr)==0 || strcmp("+A",pptr)==0)
            alignword = 1;
        else if(strcmp("-ASSUMEDSSS",pptr)==0 || strcmp("-D",pptr)==0)
            assumeDSSS = 0;
        else if(strcmp("+ASSUMEDSSS",pptr)==0 || strcmp("+D",pptr)==0)
            assumeDSSS = 1;
        else if (strcmp("COMPILER", pptr) == 0) {
          #ifdef __TURBOC__
            #ifdef __BORLANDC__
               puts("Borland C++ was used to build SCC.EXE.");
            #else
               puts("Borland Turbo C++ was used to build SCC.EXE.");
            #endif
          #else
               puts("An unknown C compiler was used to build SCC.EXE.");
          #endif
               exit(e_ok);
             }
        else if(strcmp("STACK",pptr)==0)
            stackcheck = 1;
        else if(strcmp("+MAP",pptr)==0 || strcmp("+M",pptr)==0)
            makemapfile = 1;
        else if(strcmp("-MAP",pptr)==0 || strcmp("-M",pptr)==0)
            makemapfile = 0;
        else if(strcmp("STACKPROC",pptr)==0)
            {outptr = startptr;
            if(argv[count+1] != NULL)
                {strcpy(string,argv[count+1]);
                if(includeproc()==-1)
                    printf("%s not in stack procedure library.\n",string);
                else{if(argv[count+2] != NULL)
                        {strcpy(rawfilename,argv[count+2]);
                        writeoutput(1);
                        puts("stack procedure extracted.");}
                    else puts("Output filename expected.");
                    }
                }
            else puts("stack procedure name expected.");
                exit( e_extract );
            }
        else if(strcmp("REGPROC",pptr)==0)
            {outptr = startptr;
            if(argv[count+1] != NULL)
                {strcpy(string,argv[count+1]);
                if(includeit(1)==-1)
                    printf("%s not in REG procedure library.\n",string);
                else{if(argv[count+2] != NULL)
                        {strcpy(rawfilename,argv[count+2]);
                        writeoutput(1);
                        puts("REG procedure extracted.");}
                    else puts("Output filename expected.");
                    }
                }
            else puts("REG procedure name expected.");
            exit( e_extract );
            }
        else if(strcmp("MACRO",pptr)==0)
            {outptr = startptr;
            if(argv[count+1] != NULL)
                {strcpy(string,argv[count+1]);
                if(includeit(0)==-1)
                    printf("%s not in MACRO library.\n",string);
                else{if(argv[count+2] != NULL)
                        {strcpy(rawfilename,argv[count+2]);
                        writeoutput(1);
                        puts("MACRO extracted.");}
                    else puts("Output filename expected.");
                    }
                }
            else puts("MACRO name expected.");
            exit( e_extract );
            }
        else if(strcmp("SYM",pptr)==0)
            {startptr = 0x100;
            comfile = file_com;
            count++;
            startsymbiosys(argv[count]);}
        else if(strcmp("8088",pptr)==0 || strcmp("8086",pptr)==0 || strcmp("0",pptr)==0)
            chip = 0;
        else if(strcmp("80186",pptr)==0 || strcmp("1",pptr)==0)
            chip = 1;
        else if(strcmp("80286",pptr)==0 || strcmp("2",pptr)==0)
            chip = 2;
        else if(strcmp("80386",pptr)==0 || strcmp("3",pptr)==0)
            chip = 3;
        else if(strcmp("80486",pptr)==0 || strcmp("4",pptr)==0)
            chip = 4;
        else if(strcmp("80586",pptr)==0 || strcmp("5",pptr)==0)
            chip = 5;
        else if(strcmp("80686",pptr)==0 || strcmp("6",pptr)==0)
            chip = 6;
        else if(strcmp("80786",pptr)==0 || strcmp("7",pptr)==0)
            chip = 7;
        else if(strcmp("X",pptr)==0)
            header = 0;
        else if(strcmp("EXE",pptr)==0 || strcmp("E",pptr)==0)
            {puts("WARNING!!!  EXE file output not yet complete.  Do not use!");
            comfile = file_exe;
            dos1=2;
            dos2=0;
            if( outputdata == NULL )
                {outputdata = (unsigned char *) malloc( (size_t) MAXDATA );
                if(outputdata == NULL)
                    {printf("ERROR > Not enough memory for output data buffer.\n");
                    exit(e_outofmemory);}
                }
            }
        else if(strcmp("OBJ",pptr)==0)
            {comfile = file_obj;
            startptr = 0x0000;       // start address
            startptrdata = 0x0000;   // data start address
            jumptomain = CALL_NONE;
            header = 0;
            }
        else if(strcmp("HELP",pptr)==0 || strcmp("?",pptr)==0)
            {printf("Read the document files (C--INFO.DOC, etc.).\n");
            exit( e_ok );}
        else if(strcmp("KEYWORDS",pptr)==0)
            {displaykeywords();
            exit( e_ok );}
        else{
            if( pptr[0] == 'S' && pptr[1] == '=' )
                {pptr += 2;
                stacksize = 0;
                while( *pptr >= '0' && *pptr <= '9' )
                    {stacksize = stacksize*10 + (*pptr - '0');
                    pptr++;
                    }
                if( *pptr )
                    {printf("ERROR > Bad stack size.\n");
                    exit( e_unknowncommandline );
                    }
                }
            else{printf("ERROR > Unknown command line option '%s'.\n",argv[count]);
                exit( e_unknowncommandline );
                }
           }
        }
    else{if(pari==0)
            {_splitpath(argv[count],rawdrive,rawdir,rawfname,rawext);
            if( strcmp(rawext,"")!=0 && strcmp(rawext,".C--")!=0 )
                {printf("ERROR > Bad input file extension '%s'.",rawext);
                exit( e_badinputfilename );}
            sprintf(rawfilename,"%s%s%s",rawdrive,rawdir,rawfname);
            pari = 1;}
        else{printf("ERROR > Unknown command line parameter '%s'.\n",argv[count]);
            exit( e_unknowncommandline );}
        }
    }
if(pari != 1)
    {
    puts("Syntax is: SCC <file> [option[s]]   * = default\n"
         "  /80286              Enable 80286 code optimizations (/2)\n"
         "  /80386              Enable 80386 code optimizations (/3)\n"
         "  /+ALIGN           * Enable even word address alignment (/+A)\n"
         "  /-ASSUMEDSSS      * Disable assumption of DS = SS optimization (/-D)\n"
//       "  /COMPILER           Display C compiler used to build SCC.EXE\n"
         "  /-CTRLC           * Do not insert <CTRL+C> ignoring code (/-C)\n"
//       "  /EXE                Produce .EXE run file (almost available) (/E)\n"
//       "  /HELP               Get a little help (not much) (/?)\n"
         "  /KEYWORDS           Display list of SPHiNX C-- reserved words\n"
         "  /MACRO <name>       Extract MACRO <name> from internal library\n"
         "  /+MAIN            * Set initial jump to main() to be NEAR (/J2)\n"
         "  /-MAP             * Do not generate map file (/-M)\n"
//       "  /OBJ                Produce .OBJ output file\n"
         "  /-PARSE           * Do not insert parse command-line code (/-P)\n"
         "  /REGPROC <name>     Extract REG procedure <name> from internal library\n"
         "  /+RESIZE          * Insert resize program memory block code (/+R)\n"
         "  /S=#####            Set stack size to ##### decimal value (default 2048)\n"
         "  /SIZE               Optimize for code size (/OC)\n"
         "  /SPEED            * Optimize for speed (/OS)\n"
//       "  /STACK              Activate compiler stack check during compiling\n"
         "  /STACKPROC <name>   Extract stack procedure <name> from internal library\n"
         "  /SYM <file>         .COM file symbiosis with <file>\n"
         "  /X                  Disable SPHiNX C-- header in output file");
    exit( e_noinputspecified );
    }
tokainitalize();
compile();
if( error == 0 )
    exit( e_ok );
exit( e_someerrors );
}


doprestuff ()  // do initial code things, like resize mem, jump to main...
{struct tokenrec holdtoken;
storecurrenttoken(&holdtoken);

notdoneprestuff = 0;

if( comfile == file_com || comfile == file_obj )
    {outptr = startptr;
    if(resizemem)
        {popax();                   /* get return address off stack */
        op(0xBC);
        stackstartaddress = outptr;
        outword(0); /* MOV SP,# */  /* set new stack location */
        pushax();                   /* put return address on new stack */
        outword(0x4AB4);            /* MOV AH,4Ah */
        op(0xBB);
        resizesizeaddress = outptr;
        outword(0x1000);     /* MOV BX,0x1000 */
        outword(0x21CD);     /* INT 21h - Resize memory block */
        op(0x73);            /* JNB */
        if(resizemessage == NULL)
            {op(0x01);}           /* JNB down 1 byte */
        else{op(0x08);            /* JNB down 8 bytes */
            outword(0x09B4);      /* MOV AH,09h */
            strcpy(string,resizemessage);
            op(0xBA); outword(addpoststring());  /* MOV DX,resizemessage */
            outword(0x21CD);}   /* INT 0x21 to display the string */
        ret();
        }
    if(killctrlc)
        {outword(0x01EB);   // JMP down 1 byte over IRET
        iret();
        xorAXAX();
        outword(0xC08E);  /* MOV ES,AX */
        op(0x26);         /* ES: MOV [0x8C],iret offset */
        outword(0x06C7);  outword(0x8C);  outword(outptr-8);
        op(0x26);         /* ES: */
        outword(0x0E8C);  outword(0x8E);   /* MOV [],CS */
        }
    if(parsecommandline)
        outparsecommandline();
    if(jumptomain != CALL_NONE)
        {tok = tk_ID;
        strcpy(string,"main");
        tobedefined(jumptomain,tk_void);  /* put main on the to be defined stack */
        if( jumptomain == CALL_NEAR )
            {op(0xE9); outword(0x0000);}  /* JMP near */
        else{op(0xEB); op(0x00);}   /* JMP short */
        }
    }
else if( comfile == file_exe )
    {startptr = 0;         /* EXE file stuff */
    outptr = 0;
    outptrdata = 0;
    startptrdata = 0;
    pushss();
    popds();
    tok = tk_ID;
    strcpy(string,"main");
    tobedefined(CALL_NEAR,tk_void); /* put main on the to be defined stack */
    op(0xE8); outword(0x0000);  /* CALL main() */
    op(0xB8); outword(0x4C00);  /* MOV AX,0x4C00 */
    op(0xCD); op(0x21);         /* INT 0x21 >> exit with 0 return code */
    }

if(header)
    {outheader();
    alignersize += 12;}
restorecurrenttoken(&holdtoken);
if( jumptomain != CALL_NONE )
    if( (tok == tk_ID || tok == tk_id) && strcmp(string,"main")==0 )
        tok = tk_undefregproc;
}


compilefile (filename,firstflag)
char *filename;
int firstflag;
{int hold;
char trialfilename[FILENAMESIZE];

strcpy(trialfilename,filename);
hold = loadinputfile(trialfilename);
if( firstflag == 0 && hold == -2 && compilerdir[0] != 0 )
    {sprintf(trialfilename,"%s%s",compilerdir,filename);
    hold = loadinputfile(trialfilename);
    }
if( hold == -2 )
    unabletoopen(filename);
if( hold != 0 )
    exit( e_cannotopeninput );
strcpy(currentfilename,trialfilename);
if( makemapfile )
    fprintf(mapfile,"File %s included.\n",currentfilename);

starttok();
nexttok();
while( tok != tk_eof )
    {while( tok == tk_question )
        directive();
    if( notdoneprestuff )
        doprestuff();
    switch(tok)
        {case tk_id:
        case tk_ID:
        case tk_undefregproc:
        case tk_undefproc:  declare_procedure(tokens,cpt_near);  break;
        case tk_far:        nexttok();  declare_procedure(tokens,cpt_near);  break;
        case tk_at:         insertcode();               break;
        case tk_colon:      dynamic_proc();             break;
        case tk_fixed32s:
        case tk_fixed32u:
        case tk_long:
        case tk_dword:
        case tk_word:
        case tk_byte:
        case tk_char:
        case tk_int:       globalvar(tok);   break;
        case tk_interrupt: interruptproc();  break;
        case tk_void:      nexttok();
                           if( tok == tk_far )
                               {nexttok();
                               declare_procedure(tk_void,cpt_far);}
                           else declare_procedure(tk_void,cpt_near);
                           break;
        case tk_question:  directive();  break;
        case tk_enum:     doenum();  break;
        case tk_from:     nexttok();  dofrom(0);  nextseminext();  break;
        case tk_extract:  nexttok();  doextract(0);  seminext();  break;
        case tk_loop:
        case tk_while:
        case tk_do:
        case tk_else:
        case tk_ELSE:
        case tk_if:
        case tk_IF:
        case tk_interruptproc:
        case tk_proc:
        case tk_regproc:
        case tk_charvar:
        case tk_intvar:
        case tk_bytevar:
        case tk_longvar:
        case tk_dwordvar:
        case tk_fixed32svar:
        case tk_fixed32uvar:
        case tk_wordvar:  idalreadydefined();  break;
        case tk_reg32:
        case tk_debugreg:
        case tk_controlreg:
        case tk_testreg:
        case tk_reg:
        case tk_seg:
        case tk_beg:  regnameerror();
        case tk_eof:  break;
        case tk_locallabel:  internalerror("local label token found outside procedure block.");
        default:      unuseableinput();  break;
        }
    }
freeinput();
}


printmemsizes (whereto)
FILE *whereto;
{long stacklong;
unsigned int stackword;
unsigned int postword;
postword = postsize;
if(comfile == file_com)
    {if( resizemem == 0 )
        {stacklong = 0xFFFE - outptr - postsize;
        stackword = stacklong;}
    else stackword = stacksize;
    fprintf(whereto,"Code: %u bytes, Data: %u bytes, Post: %u bytes, Stack: %u bytes\n"
                ,outptr-startptr-datasize-alignersize,datasize,postword,stackword);
    }
else{fprintf(whereto,"Code: %u bytes, Data: %u bytes, Post: %u bytes, Stack: %u bytes\n"
                ,outptr-startptr,datasize,postword,stacksize );
    }
}


/*================ OBJ file output stuff starts ===============*/


void obj_outLEDATA(FILE *fp,unsigned int offset,unsigned int recordlength,
                   unsigned char *data)
{
int checksum,i;
unsigned char recordtype = 0xA0;

fwrite(&recordtype,1,1,fp);
recordlength+=4;
checksum = recordtype;
checksum += (recordlength/256);
checksum += (recordlength&255);
fwrite(&recordlength,2,1,fp);
i = 0x01;
checksum += i;
fwrite(&i,1,1,fp);
checksum += (offset/256);
checksum += (offset&255);
fwrite(&offset,2,1,fp);
recordlength-=4;
for( i=0; i < recordlength; i++)
    checksum += data[i];
fwrite(data,recordlength,1,fp);
checksum = -checksum;
fwrite(&checksum,1,1,fp);
}



int obj_outrecord (FILE *fp,int recordtype,unsigned int recordlength,
                   unsigned char *data)
/*
   Outputs an OBJ record.
*/
{
int checksum,i;
recordlength++;
checksum = recordtype;
fwrite(&recordtype,1,1,fp);
checksum += (recordlength/256);
checksum += (recordlength&255);
fwrite(&recordlength,2,1,fp);
recordlength--;
for( i=0; i < recordlength; i++)
    checksum += data[i];
fwrite(data,recordlength,1,fp);
checksum = -checksum;
fwrite(&checksum,1,1,fp);
}


int out_objfile (char *objfilename,unsigned int length,char *data)
{
FILE *fp;
unsigned char holdstr[64];
unsigned int i;

// open .OBJ file
fp = fopen(objfilename, "wb");

// output THEADR
holdstr[0] = strlen(inputfile);
for (i = 0; i < strlen(inputfile); i++)
  holdstr[1 + i] = inputfile[i];
obj_outrecord(fp, 0x80, i + 1, holdstr);

// output COMENT
holdstr[0] = 0x00; // COMENT type = purgable & listable
holdstr[1] = 0x00; // COMENT class = translator
for (i = 0; i < strlen(compilerstr); i++)
  holdstr[2 + i] = compilerstr[i];
obj_outrecord(fp, 0x88, i + 2, holdstr);

// some linkers need a blank LNAMES record before the real LNAMES record
obj_outrecord(fp, 0x96, 1, "\x00");

// output LNAMES
holdstr[0] = 0x04;
holdstr[1] = 'C';
holdstr[2] = 'O';
holdstr[3] = 'D';
holdstr[4] = 'E';
obj_outrecord(fp, 0x96, 5, holdstr);

// output the SEGDEF
holdstr[0] = 0x28;
holdstr[1] = length & 255;    // Set the length of the segment of DATA or CODE
holdstr[2] = length / 256;    //
holdstr[3] = 0x02;
holdstr[4] = 0x01;
holdstr[5] = 0x01;
obj_outrecord(fp,0x98,6,holdstr);

// output the PUBDEF records for each exteral procedures (all procedures)
outputPUBDEF(fp);

// output the data (LEDATA) in 1K chunks as required!
i = 0;
while( i < length )
    {
    if( i+1024 > length )
        obj_outLEDATA(fp,i,length-i,data+i);
    else obj_outLEDATA(fp,i,1024,data+i);
    i += 1024;
    }

// output MODEND
obj_outrecord(fp, 0x8A, 1, "\x00");

// close .OBJ file
fclose(fp);
}


/*================ OBJ file output stuff ends ===============*/

/* ------------------- output procedures start ------------------- */

int writeoutput (fullname)
char fullname;
{FILE *diskout;
long paragraphsrequired;
unsigned int count;
unsigned char outputfile[FILENAMESIZE];

if(comfile == file_com)
    {if( fullname )
        strcpy(outputfile,rawfilename);
    else sprintf(outputfile,"%s.COM",rawfilename);
    if(!(diskout=fopen(outputfile,"wb")))
        {fprintf(stderr,"ERROR, unable to open output file %s.\n",outputfile);
        return(-1);}
    if( fwrite(output+startptr,outptr-startptr,1,diskout) != 1 )
        {fclose(diskout);
        fprintf(stderr,"ERROR, unable to write output file %s.\n",outputfile);
        return(-1);}
    fclose(diskout);
    }
else if(comfile == file_exe)
    {exeheader[0]=0x5A4D;         // MZ
    exeheader[1]=runfilesize%512;
    exeheader[2]=runfilesize/512;
    exeheader[3]=0;     // # of relocation items
    exeheader[4]=2;     // size of header in paragraphs (2 paragraphs)
    paragraphsrequired = (outptr+outptrdata+postsize+stacksize+15) /16;
    exeheader[5]= (unsigned int) paragraphsrequired;  // min-paragraphs
    exeheader[6]= (unsigned int) paragraphsrequired;  // max-paragraphs
    exeheader[7]=outptr/16;      // displacement of SS
    exeheader[8]=outptrdata+postsize+stacksize; // intial value of SP
    exeheader[9]=0;                      // word check sum WHO KNOWS? prob all file
    for(count=0; count<9; count++)
        exeheader[9]+=exeheader[count];
    exeheader[10]=0;             // IP at entry (0x0000)
    exeheader[11]=0;             // displacement of CS (0x0000)
    exeheader[12]=0;             // offset of first relocation item (0x0000)
    exeheader[13]=0;             // overlay # (0 for resident code)
    exeheader[14]=0; exeheader[15]=0;  // unused

    sprintf(outputfile,"%s.EXE",rawfilename);
    if(!(diskout=fopen(outputfile,"wb")))
        {fprintf(stderr,"ERROR, unable to open output file %s.\n",outputfile);
        return(-1);}
    if( fwrite(exeheader,0x20,1,diskout) != 1 )
        {fclose(diskout);
        fprintf(stderr,"ERROR, unable to write EXE header to file %s.\n",outputfile);
        return(-1);}
    if( fwrite(output+startptr,outptr-startptr,1,diskout) != 1 )
        {fclose(diskout);
        fprintf(stderr,"ERROR, unable to write CODE to file %s.\n",outputfile);
        return(-1);}
    if( outptrdata-startptrdata != 0 )
        if( fwrite(outputdata+startptrdata,outptrdata-startptrdata,1,diskout) != 1 )
            {fclose(diskout);
            fprintf(stderr,"ERROR, unable to write DATA to file %s.\n",outputfile);
            return(-1);}
    fclose(diskout);
    }
else{// OBJ output file.
    sprintf(outputfile,"%s.OBJ",rawfilename);
    out_objfile(outputfile,outptr-startptr,output+startptr);
    }
return(0);
}


startmapfile ()
{unsigned char mapfilename[80];
sprintf(mapfilename,"%s.MAP",rawfilename);
if(!(mapfile=fopen(mapfilename,"w")))
    {fprintf(stderr,"ERROR, unable to open map file %s.\n",++error,mapfilename);
    mapfile = 0;
    exit(e_cannotopenmapfile);}
fprintf(mapfile,"MAP FILE FOR %s.",rawfilename);
if( comfile == file_com )
    fprintf(mapfile,"COM\n\n");
else if( comfile == file_obj )
    fprintf(mapfile,"OBJ\n\n");
else fprintf(mapfile,"EXE\n\n");
}


finishmapfile ()
{fprintf(mapfile,"\n");
displaytree();
fprintf(mapfile,"Component Sizes:\n");
printmemsizes(mapfile);
fprintf(mapfile,"RUN File Size: %ld bytes\n",runfilesize);
fprintf(mapfile,"\nEND OF MAP FILE FOR %s.",rawfilename);
if( comfile == file_com )
    fprintf(mapfile,"COM");
else if( comfile == file_obj )
    fprintf(mapfile,"OBJ");
else fprintf(mapfile,"EXE");
fclose(mapfile);
}

/* ------------------- output procedures start ------------------- */

op (byte)
int byte;
{if(outptr>=MAXDATA)
    maxoutputerror();
output[outptr++]=byte;
if(comfile != file_exe)
    outptrdata = outptr;
}


void opd (byte)
int byte;
{if(comfile != file_exe )
    {if(outptr>=MAXDATA)
        maxoutputerror();
    output[outptr++]=byte;
    outptrdata = outptr;
    }
else{if(outptrdata>=MAXDATA)
        maxdataerror();
    outputdata[outptrdata++]=byte;
    }
}


void outword (num)
unsigned int num;
{if(outptr>=MAXDATA-1)
    maxoutputerror();
output[outptr++]=num;
output[outptr++]=num/256;
if(comfile != file_exe)
    outptrdata = outptr;
}


void outwordd (num)
unsigned int num;
{if(comfile != file_exe)
    {if(outptr>=MAXDATA-1)
        maxoutputerror();
    output[outptr++]=num;
    output[outptr++]=num/256;
    outptrdata = outptr;
    }
else{if(outptrdata>=MAXDATA-1)
        maxdataerror();
    outputdata[outptrdata++]=num;
    outputdata[outptrdata++]=num/256;
    }
}


void outdword (num)
unsigned long num;
{outword( (unsigned int) (num & 0xFFFFL) );
outword( (unsigned int) (num / 0x10000L) );
}


void outdwordd (num)
unsigned long num;
{outwordd( (unsigned int) (num & 0xFFFFL) );
outwordd( (unsigned int) (num / 0x10000L) );
}


void outaddress (outrm,outnumber)
unsigned int outrm,outnumber;
{if( outrm == rm_d16 )
    outword(outnumber);
else{outrm &= rm_mod11;
    if( outrm == rm_mod11 )
        internalerror("Bad outrm value in outaddress();");
    else if( outrm == rm_mod10 )
        outword(outnumber);
    else if( outrm != rm_mod00 )
        op(outnumber);
    }
}



void doblock ()
{unsigned char done=0;
expecting(tk_openbrace);
while( tok != tk_eof && done==0 )
    {if(tok == tk_closebrace)
        {done=1;
        nexttok();}
    else docommand();
    }
if(done==0)
    unexpectedeof();
}


docommand ()     /* do a single command */
{int useflag=0;
switch(tok)
    {case tk_ID:  useflag = 1;
    case tk_id:   if(doid(useflag,tk_void)!=tokens)
                      nextseminext();
                  break;
    case tk_undefregproc:  useflag=1;
    case tk_undefproc:     if(doanyundefproc(useflag,tk_void)!=tokens)
                               nextseminext();
                           break;
    case tk_regproc:  useflag = 1;
    case tk_proc:     doanyproc(useflag,tk_void);
                      nextseminext();
                      break;
    case tk_charvar:  useflag = 1;
    case tk_bytevar:  dobytevar(useflag);
                      break;
    case tk_intvar:   useflag = 1;
    case tk_wordvar:  dowordvar(useflag);
                      break;
    case tk_longvar:   useflag = 1;
    case tk_dwordvar:  dodwordvar(useflag);
                       break;
    case tk_fixed32svar:  useflag = 1;
    case tk_fixed32uvar:  dodwordvar(useflag);
                          break;
    case tk_return:    doreturn();    break;
    case tk_at:  nexttok();
                 macros(tk_void);
                 nextseminext();
                 break;
    case tk_if:        doif();        break;
    case tk_IF:        dobigif();     break;
    case tk_loop:      doloop();      break;
    case tk_while:     whileerror();  nexttok();  break;
    case tk_do:        dodo();        break;
    case tk_reg32:     doreg32((unsigned int)number);  break;
    case tk_reg:       doreg((unsigned int)number);  break;
    case tk_beg:       dobeg((unsigned int)number);  break;
    case tk_seg:       doseg((unsigned int)number);  break;
    case tk_dollar:    doasm();     break;
    case tk_openbrace:  doblock();  break;
    case tk_from:  nexttok();  dofrom(0);  nextseminext();  break;
    case tk_extract:  nexttok();  doextract(0);  seminext();  break;
    case tk_minus:  useflag = 1;
    case tk_not:    nexttok();
                    notnegit(useflag,tok,(unsigned int)number,rm,post,segm);
                    nextseminext();
                    break;
    case tk_locallabel:  define_locallabel();  break;
    case tk_question:  directive();  break;
    case tk_camma:
    case tk_semicolon:  nexttok();        break;
    case tk_else:       elseerror();      break;
    case tk_ELSE:       ELSEerror();      break;
    case tk_eof:        unexpectedeof();  break;
    case tk_void:
    case tk_long:
    case tk_dword:
    case tk_word:
    case tk_byte:
    case tk_int:
    case tk_char:  notwithinblock();  break;
    default:  unuseableinput();  break;
    }
}


/* ---------------------- Procedure Calling Starts -------------------- */


int doanyundefproc (regproc,expectedreturn)
int regproc,expectedreturn;
{unsigned int cnum;
int returnvalue;
if( tok2 == tk_colon )  // if a label
    {if( regproc )    /* local label that has been used, but not placed */
        {addlocalvar(string,tk_number,outptr);
        updatecall( (unsigned int)number,outptr,procedure_start);
        }
    else{if( dynamic_flag != NOT_DYNAMIC )
            dynamiclabelerror();
        tok = tk_proc;
        number = outptr;
        updatecall( (unsigned int)updatetree(), (unsigned int)number,0);
        }
    nexttok();  // move past id
    nexttok();  // move past :
    return(tokens);
    }
if( tok2 == tk_openbracket )
    {cnum = (unsigned int)number;
    if( typesize(expectedreturn) > typesize(rm) )
        {rm = expectedreturn;
        updatetree();}
    returnvalue = rm;
    nexttok();
    if(regproc)
        doregparams();
    else doparams();
    addacall(cnum,CALL_NEAR);
    callloc(0x0000);    /* produce CALL [#] */
    return(returnvalue);
    }
undefinederror();
nexttok();
return(tk_long);
}


int doanyproc (regflag)
int regflag;
{unsigned int cloc;
int returnvalue,dynamicindex = NOT_DYNAMIC;
cloc = (unsigned int)number;   /* get address or handle */
returnvalue = rm;
if( segm != NOT_DYNAMIC && segm < MAXDYNAMICS ) /* if a nonstatic dynamic */
    dynamicindex = segm;
nexttok();
if(regflag)
    doregparams();
else doparams();
if( dynamicindex != NOT_DYNAMIC )
    {addacall(cloc,CALL_NEAR);
    cloc = 0x0000;
    }
callloc(cloc);
return(returnvalue);
}


int doid (uppercase,expectedreturn)
char uppercase;
int expectedreturn;
{int cnum;
if( tok2 == tk_colon )  // if a label
    {if( uppercase )
        addlocalvar(string,tk_number,outptr);
    else{if( dynamic_flag != NOT_DYNAMIC )
            dynamiclabelerror();
        tok = tk_proc;
        rm = tk_void;
        number = outptr;
        segm = NOT_DYNAMIC;
        addtotree(string);
        }
    nexttok();  // move past id
    nexttok();  // move past :
    return(tokens);
    }
if( tok2 == tk_openbracket )
    {tobedefined(CALL_NEAR,expectedreturn);
    cnum = posts-1;
    nexttok();
    if(uppercase)
        doregparams();
    else doparams();
    postloc[cnum] = outptr + 1;
    callloc(0x0000);      /* produce CALL [#] */
    return(expectedreturn);
    }
undefinederror();
nexttok();
return(tk_long);
}


int typesize (vartype)
/* return the size in bytes of the given type */
int vartype;
{char holdstr[60];
switch( vartype )
    {case tk_void:  return(0);
    case tk_char:
    case tk_byte:  return(1);
    case tk_int:
    case tk_word:  return(2);
    case tk_fixed32u:
    case tk_fixed32s:
    case tk_dword:
    case tk_long:  return(4);
    default:  sprintf(holdstr,"vartype=%d in typesize()",vartype);
              internalerror(holdstr);
              break;
    }
}



void convert_returnvalue (expectedreturn,actualreturn)
int expectedreturn,actualreturn;
{
if( expectedreturn == tk_void )
    return;

if( actualreturn == tk_void )
    {preerror("Procedure has return type of void");
    return;
    }

switch( expectedreturn )
    {case tk_byte:
    case tk_char:  if( actualreturn == tk_fixed32s ||
                           actualreturn == tk_fixed32u )
                       {  /* SHR EAX,16 */
                       outword(0xC166);  outword(0x10E8);
                       if( cpu < 3 )
                           cpu = 3;
                       }
                   break;
    case tk_word:
    case tk_int:  if( actualreturn == tk_fixed32s ||
                         actualreturn == tk_fixed32u )
                      {  /* SHR EAX,16 */
                      outword(0xC166);  outword(0x10E8);
                      if( cpu < 3 )
                          cpu = 3;
                      }
                  else if( actualreturn == tk_char )
                      cbw();
                  else if( actualreturn == tk_byte )
                      xorAHAH();
                  break;
    case tk_long:
    case tk_dword:  switch( actualreturn )
                        {case tk_char:  cbd();  break;
                        case tk_byte:   /* MOVZX EAX,AL */
                                       outword(0x0F66); outword(0xC0B6);
                                       break;
                        case tk_word:  /* MOVZX EAX,AX */
                                       outword(0x0F66); outword(0xC0B7);
                                       break;
                        case tk_int:  /* MOVSX EAX,AX */
                                      outword(0x0F66); outword(0xC0BF);
                                      break;
                        case tk_fixed32s:  /* SAR EAX,16 */
                                           outword(0xC166);  outword(0x10F8);
                                           break;
                        case tk_fixed32u:  /* SHR EAX,16 */
                                           outword(0xC166);  outword(0x10E8);
                                           break;
                        }
                    if( cpu < 3 )
                        cpu = 3;
                    break;
    case tk_fixed32s:
    case tk_fixed32u:
            switch( actualreturn )
                {case tk_char:  cbw();
                                /* SHL EAX,16 */
                                outword(0xC166);  outword(0x10E0);
                                break;
                case tk_byte:  xorAHAH();
                case tk_word:
                case tk_int:
                case tk_dword:
                case tk_long:
                               /* SHL EAX,16 */
                               outword(0xC166);  outword(0x10E0);
                               break;
                }
            if( cpu < 3 )
                cpu = 3;
            break;
    }
}


procdo (expectedreturn)
int expectedreturn;
{int actualreturn;
int idflag=0;
if( dynamic_flag != NOT_DYNAMIC )
    preerror("Function calls within a dynamic procedure are illegal");
switch(tok)
    {case tk_ID:  idflag=1;
    case tk_id:   actualreturn = doid(idflag,expectedreturn);
                  break;
    case tk_regproc:  idflag=1;
    case tk_proc:     actualreturn = doanyproc(idflag);
                      break;
    case tk_undefregproc: idflag=1;
    case tk_undefproc:    actualreturn=doanyundefproc(idflag,expectedreturn);
                          break;
    default:  internalerror("Bad tok in procdo();");
              break;
    }
convert_returnvalue(expectedreturn,actualreturn);
}



/* +++++++++++++++++++++++ loops and ifs start ++++++++++++++++++++++++ */

/*** FIXED32 stuff not done for following procedure!!! ***/

int outcmp (swapped,ctok,cnumber,crm,csegm,cpost,ctok2,cnumber2,crm2,csegm2,cpost2)
int swapped,ctok,ctok2,crm,crm2,cpost,csegm,csegm2,cpost2;
long cnumber,cnumber2;
{unsigned char err=0;
switch(ctok)
    {case tk_reg:
        switch(ctok2)
            {case tk_reg:  op(0x39);
                           op(0xC0 +(unsigned int)cnumber +(unsigned int)cnumber2*8);
                           break;
            case tk_postnumber:
            case tk_number:  if(cnumber==AX)
                                 op(0x3D);
                             else{op(0x81);
                                 op(0xF8 +(unsigned int)cnumber);}
                             if( ctok2 == tk_postnumber )
                                 setwordpost();
                             outword((unsigned int)cnumber2);
                             break;
            default:  if(swapped)
                          err = 1;
                      else return( outcmp(1,ctok2,cnumber2,crm2,csegm2,cpost2,ctok,cnumber,crm,csegm,cpost) );
                      break;
            }
        break;
    case tk_intvar:
    case tk_wordvar:
        switch(ctok2)
            {case tk_reg:  outseg(csegm,cpost,2);
                           op(0x39);
                           op((unsigned int)cnumber2*8 +crm);
                           outaddress(crm,(unsigned int)cnumber);
                           break;
            case tk_postnumber:
            case tk_number:  outseg(csegm,cpost,2);
                             op(0x81);
                             op(0x38+crm);
                             outaddress(crm,(unsigned int)cnumber);
                             if( ctok2 == tk_postnumber )
                                 setwordpost();
                             outword((unsigned int)cnumber2);
                             break;
            case tk_charvar:
            case tk_intvar:  getintoax(1,ctok2,(unsigned int)cnumber2,crm2,csegm2,cpost2);
                             outseg(csegm,cpost,2);
                             op(0x39);  /* CMP [word],AX */
                             op(crm);
                             outaddress(crm,(unsigned int)cnumber);
                             break;
            default:  getintoax(0,ctok2,(unsigned int)cnumber2,crm2,csegm2,cpost2);
                      outseg(csegm,cpost,2);
                      op(0x39); /* CMP [word],AX */
                      op(crm);
                      outaddress(crm,(unsigned int)cnumber);
                      break;
            }
        break;
    case tk_number:  if( ctok2==tk_number || ctok2==tk_postnumber )
                         {op(0xB8);    /* MOV AX,# */
                         outword((unsigned int)cnumber);
                         op(0x3D);     /* CMP AX,# */
                         if(ctok2==tk_postnumber)
                             setwordpost();
                         outword((unsigned int)cnumber2);}
                     else{if(swapped)
                             err = 1;
                         else return( outcmp(1,ctok2,cnumber2,crm2,csegm2,cpost2,ctok,cnumber,crm,csegm,cpost) );
                         }
                     break;
    case tk_postnumber:  if( ctok2==tk_number || ctok2==tk_postnumber )
                             {op(0xB8); /* MOV AX,# */
                             setwordpost();
                             outword((unsigned int)cnumber);
                             op(0x3D);  /* CMP AX,# */
                             if(ctok2==tk_postnumber)
                                 setwordpost();
                             outword((unsigned int)cnumber2);}
                         else{if(swapped)
                                 err = 1;
                             else return( outcmp(1,ctok2,cnumber2,crm2,csegm2,cpost2,ctok,cnumber,crm,csegm,cpost) );
                             }
                         break;
    case tk_charvar:
    case tk_bytevar:  switch(ctok2)
                          {case tk_number:  outseg(csegm,cpost,2);
                                            op(0x80);  /* CMP [byte],# */
                                            op(0x38+crm);
                                            outaddress(crm,(unsigned int)cnumber);
                                            op((unsigned int)cnumber2);
                                            break;
                          case tk_beg:   outseg(csegm,cpost,2);
                                         op(0x38);   /* CMP [byte],beg */
                                         op((unsigned int)cnumber2*8 +crm);
                                         outaddress(crm,(unsigned int)cnumber);
                                         break;
                          default:  getintoal(ctok2,(unsigned int)cnumber2,crm2,csegm2,cpost2);
                                    outseg(csegm,cpost,2);
                                    op(0x38);   /* CMP [byte],AL */
                                    op(crm);
                                    outaddress(crm,(unsigned int)cnumber);
                                    break;
                           }
                       break;
    case tk_beg:  switch(ctok2)
                      {case tk_number:  if((unsigned int)cnumber == AL)
                                            op(0x3C);
                                        else{op(0x80);
                                            op(0xF8+(unsigned int)cnumber);}
                                        op((unsigned int)cnumber2);
                                        break;
                      case tk_beg:  op(0x38);
                                    op(0xC0+(unsigned int)cnumber+(unsigned int)cnumber2*8);
                                    break;
                      case tk_reg:  if((unsigned int)cnumber2 <= BX)  /* CMP beg,beg */
                                        {op(0x38);
                                        op(0xC0+(unsigned int)cnumber+(unsigned int)cnumber2*8);}
                                    else{op(0x89);          /* MOV AX,reg */
                                        op(0xC0+(unsigned int)cnumber2*8);
                                        op(0x38);       /* CMP beg,AL */
                                        op(0xC0+(unsigned int)cnumber);}
                                    break;
                      default:  if(swapped)
                                    err = 1;
                                else return( outcmp(1,ctok2,cnumber2,crm2,csegm2,cpost2,ctok,cnumber,crm,csegm,cpost) );
                                break;
                      }
                  break;
    case tk_reg32:
        switch(ctok2)
            {case tk_reg32:  outword(0x3966);
                             op(0xC0 +(unsigned int)cnumber +(unsigned int)cnumber2*8);
                             break;
            case tk_postnumber:
            case tk_number:  if(cnumber==EAX)
                                 outword(0x3D66);
                             else{outword(0x8166);
                                 op(0xF8 +(unsigned int)cnumber);}
                             if( ctok2 == tk_postnumber )
                                 setdwordpost();
                             outdword(cnumber2);
                             break;
            default:  if(swapped)
                          err = 1;
                      else return( outcmp(1,ctok2,cnumber2,crm2,csegm2,cpost2,ctok,cnumber,crm,csegm,cpost) );
                      break;
            }
        break;
    case tk_longvar:
    case tk_dwordvar:
        switch(ctok2)
            {case tk_reg32:  outseg(csegm,cpost,3);
                             outword(0x3966);
                             op((unsigned int)cnumber2*8 +crm);
                             outaddress(crm,(unsigned int)cnumber);
                             break;
            case tk_postnumber:
            case tk_number:  outseg(csegm,cpost,3);
                             outword(0x8166);
                             op(0x38+crm);
                             outaddress(crm,(unsigned int)cnumber);
                             if( ctok2 == tk_postnumber )
                                 setdwordpost();
                             outdword(cnumber2);
                             break;
            case tk_charvar:
            case tk_intvar:  getintoeax(1,ctok2,cnumber2,crm2,csegm2,cpost2);
                             outseg(csegm,cpost,3);
                             outword(0x3966);   /* CMP [dword],EAX */
                             op(crm);
                             outaddress(crm,(unsigned int)cnumber);
                             break;
            default:  getintoeax(0,ctok2,cnumber2,crm2,csegm2,cpost2);
                      outseg(csegm,cpost,3);
                      outword(0x3966); /* CMP [dword],EAX */
                      op(crm);
                      outaddress(crm,(unsigned int)cnumber);
                      break;
            }
        break;
    default:  err = 1;
              break;
    }
if(err)
    preerror("unable to create comparison, check restrictions");
return(swapped);
}


outjxx (comparetok,flipit,signedtype)     /* produce JXX [#] */
int comparetok,flipit,signedtype;
{int code;
if(!flipit)
    switch(comparetok)
        {case tk_equalto:  code = 0x74;  break;
        case tk_notequal:  code = 0x75;  break;
        case tk_greater:   if(signedtype==0)
                               code = 0x77;
                           else code = 0x7F;
                           break;
        case tk_less:  if(signedtype==0)
                           code = 0x72;
                       else code = 0x7C;
                       break;
        case tk_greaterequal:  if(signedtype==0)
                                   code = 0x73;
                               else code = 0x7D;
                               break;
        case tk_lessequal:  if(signedtype==0)
                                code = 0x76;
                            else code = 0x7E;
                            break;
        default:  unknowncompop();
                  break;
        }
else switch(comparetok)     /* all are flipped types */
        {case tk_equalto:  code = 0x75;  break;
        case tk_notequal:  code = 0x74;  break;
        case tk_greater:  if(signedtype==0)
                              code = 0x76;
                          else code = 0x7E;
                          break;
        case tk_less:  if(signedtype==0)
                           code = 0x73;
                       else code = 0x7D;
                       break;
        case tk_greaterequal:  if(signedtype==0)
                                   code = 0x72;
                               else code = 0x7C;
                               break;
        case tk_lessequal:  if(signedtype==0)
                                code = 0x77;
                            else code = 0x7F;
                            break;
        default:  internalerror("Bad comparetok in outjxx();");
                  break;
        }
op(code);  /* output instruction code */
}


int getjumptype(gtok,gtok2,vartype)  /* determines if signed operand */
int gtok,gtok2,vartype;
{if( vartype == tk_char || vartype == tk_int || vartype == tk_long
        || vartype == tk_fixed32s )
    return(1);
return(0);
}


int iscomparetok (ctok)
int ctok;
{if( ctok==tk_equalto || ctok==tk_notequal || ctok==tk_greater ||
        ctok==tk_less || ctok==tk_greaterequal || ctok==tk_lessequal )
    return(1);
else return(0);
}


int doflag (op1,op2,invertflag,startloc)
int op1,op2;
int invertflag;
unsigned int startloc;
{if(invertflag==2)
    {if( outptr+2-startloc > 127)       // long jump
        invertflag=1;
    else invertflag=0;
    }
if(invertflag)
    op(op2);
else op(op1);
nexttok();
expecting(tk_closebracket);
return(invertflag);
}


int constructcompare (invertflag,startloc)
/* build cmp for IF, if and do {} while */
int invertflag;
unsigned int startloc;
{int comparetok,jumptype,cmpreturn,vartype;
int itok,irm,isegm,ipost,itok2,irm2,isegm2,ipost2;
long inumber,inumber2;
nexttok();
expecting(tk_openbracket);
switch(tok)
    {case tk_fixed32s:
    case tk_fixed32u:
    case tk_int:
    case tk_word:
    case tk_char:
    case tk_byte:
    case tk_long:
    case tk_dword:  vartype = tok;  nexttok();  break;
    case tk_carryflag:        return(doflag(0x72,0x73,invertflag,startloc));
    case tk_notcarryflag:     return(doflag(0x73,0x72,invertflag,startloc));
    case tk_overflowflag:     return(doflag(0x70,0x71,invertflag,startloc));
    case tk_notoverflowflag:  return(doflag(0x71,0x70,invertflag,startloc));
    case tk_zeroflag:         return(doflag(0x74,0x75,invertflag,startloc));
    case tk_notzeroflag:      return(doflag(0x75,0x74,invertflag,startloc));
    case tk_regproc:
    case tk_proc:  vartype = rm;
                   if( vartype == tokens )
                       vartype = tk_word;
                   else if( vartype == tk_void )
                       {preerror("Procedure has a return type of void");
                       vartype = tk_word;}
                   break;
    case tk_beg:
    case tk_bytevar:  vartype = tk_byte;  break;
    case tk_charvar:  vartype = tk_char;  break;
    case tk_intvar:   vartype = tk_int;   break;
    case tk_reg32:
    case tk_dwordvar: vartype = tk_dword;  break;
    case tk_longvar:  vartype = tk_long;   break;
    case tk_fixed32svar:  vartype = tk_fixed32s;  break;
    case tk_fixed32uvar:  vartype = tk_fixed32u;  break;
    case tk_at:  nexttok();
                 if( tok == tk_regproc && segm != NOT_DYNAMIC )
                     vartype = rm;
                 else vartype = tk_word;
                 macros(vartype);
                 switch(vartype)
                     {case tk_byte:
                     case tk_char:  tok = tk_beg;  break;
                     case tk_int:
                     case tk_word:  tok = tk_reg;  break;
                     case tk_fixed32u:
                     case tk_fixed32s:
                     case tk_dword:
                     case tk_long:  tok = tk_reg32;     break;
                     default:  preerror("Macro has a return type of void");
                               tok = tk_reg;
                               break;
                     }
                 number = AX;  // or AL or EAX
                 break;
    default:  vartype = tk_word;  break;
    }
if(tok==tk_minus && tok2 == tk_number)
    {nexttok();
    number = -number;
    }
if( iscomparetok(tok2) == 0 )
    {switch(vartype)
        {case tk_int:  doaxmath(1);  itok = tk_reg;  break;
        case tk_word:  doaxmath(0);  itok = tk_reg;  break;
        case tk_char:  doalmath(1);  itok = tk_beg;  break;
        case tk_byte:  doalmath(0);  itok = tk_beg;  break;
        case tk_long:  doeaxmath(1);  itok = tk_reg32;  break;
        case tk_dword:  doeaxmath(0);  itok = tk_reg32;  break;
        case tk_fixed32s:  dofixed32math(1);  itok = tk_reg32;  break;
        case tk_fixed32u:  dofixed32math(0);  itok = tk_reg32;  break;
        default:  internalerror("Bad vartype value in constructcompare();");
                  tok = tk_reg;  break;
        }
    inumber = AX;       /* same value as AL and EAX */
    }
else{itok = tok;
    irm = rm;
    isegm = segm;
    ipost = post;
    inumber = number;
    nexttok();
    }
if( tok != tk_closebracket )
    {if( iscomparetok(tok) )
        comparetok = tok;
    else{unknowncompop();
        comparetok = tk_equalto;}
    nexttok();
    if(tok==tk_minus)
        {nexttok();
        if(tok != tk_number)
            negcomperror();
        else number = -number;
        }
    if(tok == tk_number)
        {switch(vartype)
            {case tk_int:
            case tk_char:
            case tk_long:  inumber2 = doconstlongmath();  break;
            case tk_word:
            case tk_byte:
            case tk_dword:  inumber2 = doconstdwordmath();  break;
/*** FIXED32 stuff has to be done right here ***/
            }
        itok2 = tk_number;
        }
    else{itok2 = tok;
        inumber2 = number;
        irm2 = rm;
        isegm2 = segm;
        ipost2 = post;
        nexttok();
        }
    }
else{comparetok = tk_notequal;
    itok2 = tk_number;
    inumber2 = 0;
    irm2 = rm_d16;
    isegm2 = DS;
    ipost2 = 0;
    }
jumptype = getjumptype(itok,itok2,vartype);
cmpreturn = outcmp(0,itok,inumber,irm,isegm,ipost,itok2,inumber2,irm2,isegm2,ipost2);
if(invertflag==2)
    {if( outptr+2-startloc > 127)        /* long jump */
        invertflag=1;
    else invertflag=0;
    }
if( cmpreturn != 0 )  // if operands have been swapped
    {switch(comparetok)
        {case tk_less:         comparetok = tk_greater;       break;
        case tk_lessequal:     comparetok = tk_greaterequal;  break;
        case tk_greater:       comparetok = tk_less;          break;
        case tk_greaterequal:  comparetok = tk_lessequal;     break;
        }
    }
outjxx(comparetok,invertflag,jumptype);
expecting(tk_closebracket);
return(invertflag);
}


doif ()
{unsigned int startloc,elseline;
constructcompare(0,outptr);
op(0x03);        /* jump over word jump instruction of 3 bytes */
op(0xE9);        /* JMP word */
op(0x00);
op(0x00);
startloc = outptr;
docommand();
if(tok==tk_else)
    {op(0xE9);
    op(0x00);
    op(0x00);
    output[startloc-2] = (outptr - startloc) %256;
    output[startloc-1] = (outptr - startloc) /256;
    startloc = outptr;
    nexttok();
    docommand();
    output[startloc-2] = (outptr - startloc) %256;
    output[startloc-1] = (outptr - startloc) /256;
    }
else if(tok==tk_ELSE)
    {elseline = linenumber;
    op(0xEB);
    op(0x00);
    output[startloc-2] = (outptr - startloc) %256;
    output[startloc-1] = (outptr - startloc) /256;
    startloc = outptr;
    nexttok();
    docommand();
    if( outptr-startloc > 127)
        ELSEjumperror(elseline);
    output[startloc-1] = outptr - startloc;
    }
else{output[startloc-2] = (outptr - startloc) %256;
    output[startloc-1] = (outptr - startloc) /256;
    }
}


int dobigif ()
{unsigned int startloc,elseline,ifline;
ifline = linenumber;
constructcompare(1,outptr);
op(0x00);
startloc = outptr;
docommand();
if(tok==tk_else)
    {op(0xE9);
    op(0x00);
    op(0x00);
    if( outptr-startloc > 127)
        IFjumperror(ifline);
    output[startloc-1] = outptr - startloc;
    startloc = outptr;
    nexttok();
    docommand();
    output[startloc-2] = (outptr - startloc) %256;
    output[startloc-1] = (outptr - startloc) /256;
    }
else if(tok==tk_ELSE)
    {elseline = linenumber;
    op(0xEB);
    op(0x00);
    if( outptr-startloc > 127)
        IFjumperror(ifline);
    output[startloc-1] = outptr - startloc;
    startloc = outptr;
    nexttok();
    docommand();
    if( outptr-startloc > 127)
        ELSEjumperror(elseline);
    output[startloc-1] = outptr - startloc;
    }
else{if( outptr-startloc > 127)
        IFjumperror(ifline);
    output[startloc-1] = outptr - startloc;
    }
}


dodo ()
{unsigned int startloc;
nexttok();
startloc = outptr;
docommand();
if( tok!=tk_while )
    preerror("'while' expected following 'do'");
if( constructcompare(2,startloc) )   /* long jump */
    {op(0x03);              /* jump over large jump */
    op(0xE9);
    outword(startloc - (outptr+2));   /* the large jump */
    }
else op(startloc - (outptr+1));      /* the small jump */
seminext();
}


void decit (dectok,decnumber,decrm,decsegm,decpost,errormessage)
/*
    outputs code to decrement the given variable one.
*/
int dectok,decrm,decsegm,decpost,errormessage;
unsigned int decnumber;
{int vop = 0;
switch(dectok)
    {
    case tk_fixed32u:
    case tk_fixed32s:  outseg(decsegm,decpost,2);
                       op(0xFF);
                       op(0x08+decrm);
                       outaddress(decrm,decnumber+2); /* dec high word only */
                       break;
    case tk_wordvar:
    case tk_intvar:   vop = 1;
    case tk_bytevar:
    case tk_charvar:  outseg(decsegm,decpost,2);
                      op(0xFE+vop);
                      op(0x08+decrm);
                      outaddress(decrm,decnumber);
                      break;
    case tk_dwordvar:
    case tk_longvar:  outseg(decsegm,decpost,3);
                      outword(0xFF66);  op(0x08+decrm);
                      outaddress(decrm,decnumber);
                      if( cpu < 3 )
                          cpu = 3;
                      break;
    case tk_reg:  op(0x48+decnumber);
                  break;
    case tk_beg:  op(0xFE);
                  op(0xC8+decnumber);
                  break;
    case tk_reg32:  op(0x66);  op(0x48+decnumber);
                    if( cpu < 3 )
                        cpu = 3;
                    break;
    default:  if(errormessage)
                  preerror("invalid token to be decremented");
              break;
    }
}


doloop ()               /* both short and long loops */
{unsigned int startloc,loopnumber;
int looptok,looprm,loopsegm,looppost;
signed char delta;
nexttok();
expecting(tk_openbracket);
looptok = tok;
loopnumber = (unsigned int)number;
looprm = rm;
looppost = post;
loopsegm = segm;
if( tok!=tk_bytevar && tok!=tk_charvar && tok!=tk_wordvar && tok!=tk_intvar
      && tok!=tk_dwordvar && tok!=tk_longvar && tok!=tk_reg && tok!=tk_reg32
      && tok!=tk_beg && tok!=tk_closebracket
      && tok!=tk_fixed32svar && tok!=tk_fixed32uvar )
    preerror("invalid token to be decremented");
if( tok != tk_closebracket )
    nexttok();
expecting(tk_closebracket);
startloc = outptr;
docommand();
if( looptok != tk_closebracket )
    {if( (outptr-startloc <= 127-2) && (chip < 3 || optimizespeed==0)
            && looptok == tk_reg && loopnumber == CX )
        {delta = startloc - (outptr+2);
        op(0xE2);
        op(delta);  /* LOOP 'delta' */
        }
    else{
        decit( looptok,loopnumber,looprm,loopsegm,looppost,0 );
        if( outptr-startloc > 127-2 )   /* long jump */
            {if( chip < 3 )
                {op(0x74);
                op(3);  /* JZ past jump up */
                op(0xE9);
                outword( startloc - (outptr+2) );}  /* JMP top of loop */
            else{op(0x0F); op(0x85);
                outword( startloc - (outptr+2) );  /* JNZ <full disp.> */
                if( cpu < 3 )
                    cpu = 3;
                }
            }
        else{delta = startloc - (outptr+2);     /* short jump */
            op(0x75);
            op(delta);} /* JNZ 'delta' */
        }
    }
else{if( (outptr+2)-startloc > 127)     /* long jump */
        {op(0xE9);
        outword( startloc - (outptr+2) );}      /* JMP top of loop */
    else{delta = startloc - (outptr+2); /* short jump */
        op(0xEB);
        op(delta);}     /* JNZ 'delta' */
    }
}


/* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */


globalvar (type)   /* both initialized and unitialized combined */
/*
    fixed32u and fixed32s are initialized with 32bit ints, for now...
*/
int type;
{long size,loop,i,longpostsize,elements=1;
char done=0;
char var_name[IDLENGTH];

nexttok();
if( tok == tk_far )
    {nexttok();
    declare_procedure(type,cpt_far);
    return(0);
    }
if(tok2==tk_openbracket)
    {declare_procedure(type,cpt_near);
    return(0);
    }

size = typesize(type);

while(tok!=tk_eof && done==0)
    {switch(tok)
        {case tk_id:
        case tk_ID:
            strcpy(var_name, string);
            nexttok();
            if(tok==tk_openblock)
                {nexttok();
                elements = doconstlongmath();
                expecting(tk_closeblock);}
            else elements = 1;
            if(tok == tk_assign)
                {switch(type)
                    {case tk_byte:      tok = tk_bytevar;       break;
                    case tk_word:       tok = tk_wordvar;       break;
                    case tk_char:       tok = tk_charvar;       break;
                    case tk_int:        tok = tk_intvar;        break;
                    case tk_dword:      tok = tk_dwordvar;      break;
                    case tk_long:       tok = tk_longvar;       break;
                    case tk_fixed32s:   tok = tk_fixed32svar;   break;
                    case tk_fixed32u:   tok = tk_fixed32uvar;   break;
                    default:  internalerror("Bad type in globalvar();");
                              break;
                    }
                if( size==2 )
                    {if( alignword && outptrdata%2 == 1)
                        {opd(aligner);
                        alignersize++;}
                    }
                else if( size == 4 )
                    {if( alignword )
                        {switch( outptrdata%4 )
                            {case 1:  opd(aligner);
                                      alignersize++;
                            case 2:   opd(aligner);
                                      alignersize++;
                            case 3:   opd(aligner);
                                      alignersize++;
                                      break;
                            }
                        }
                    }
                number = outptrdata;
                rm = rm_d16;
                segm = DS;
                addtotree(var_name);
                nexttok();
                switch(tok)
                    {case tk_minus:
                    case tk_number:  if( type==tk_byte || type==tk_word ||
                                             type==tk_dword || type==tk_fixed32u )
                                         i = doconstdwordmath();
                                     else i = doconstlongmath();
                                     for(loop=0;loop<elements;loop++)
                                         {switch(size)
                                             {case 1:  opd((unsigned int)i);    break;
                                             case 2: outwordd((unsigned int)i); break;
                                             case 4: outdwordd(i);              break;
                                             }
                                         datasize += size;
                                         }
                                     break;
                    case tk_string:  loop = 1;  /* because of opd(0); */
                                     do {for(i=0;i<number;i++)
                                            {opd(string[i]);
                                            loop++;
                                            datasize++;}
                                         nexttok();
                                         } while( tok == tk_string );
                                     opd(0);
                                     datasize++;
                                     for(;loop<size*elements;loop++)
                                         {opd(0);
                                         datasize++;}
                                     break;
                    case tk_from:  nexttok();
                                   if( comfile == file_exe )
                                       loop = dofrom(1);
                                   else loop = dofrom(0);
                                   datasize += loop;
                                   for(;loop<size*elements;loop++)
                                       {opd(0);
                                       datasize++;}
                                   nexttok();
                                   break;
                    case tk_extract:  nexttok();
                                      if( comfile == file_exe )
                                          loop = doextract(1);
                                      else loop = doextract(0);
                                      datasize += loop;
                                      for(;loop<size*elements;loop++)
                                          {opd(0);
                                          datasize++;}
                                      break;
                    case tk_openbrace:  loop = 0;
                                        nexttok();
                                        i = 0;
                                        loop = 0;
                                        while( tok != tk_closebrace )
                                            {if(i)
                                                expecting(tk_camma);
                                            i = 1;
                                            if(tok != tk_number && tok != tk_minus)
                                                {numexpected();
                                                nexttok();}
                                            else{switch(type)
                                                    {case tk_byte:  opd((unsigned int)doconstdwordmath());
                                                                    break;
                                                    case tk_word:  outwordd((unsigned int)doconstdwordmath());
                                                                   break;
                                                    case tk_char:  opd((int)doconstlongmath());
                                                                   break;
                                                    case tk_int:  outwordd((int)doconstlongmath());
                                                                  break;
                                                    case tk_fixed32u:
                                                    case tk_dword:  outdwordd(doconstdwordmath());
                                                                    break;
                                                    case tk_fixed32s:
                                                    case tk_long:  outdwordd(doconstlongmath());
                                                                   break;
                                                    default:  internalerror("Bad type in globalvar();");
                                                              break;
                                                    }
                                                datasize += size;
                                                loop++;
                                                }
                                            }
                                        for(;loop<elements;loop++)
                                            {switch(size)
                                                {case 1: opd(0);  break;
                                                case 2: outwordd(0);  break;
                                                case 4: outdwordd(0);  break;
                                                }
                                            datasize += size;}
                                        nexttok();
                                        break;
                    default:  numexpected();
                              nexttok();
                              break;
                    }
                }
            else{switch(tok)
                    {default:       expected(';');
                    case tk_semicolon:  done=1;
                    case tk_camma:              /* post global type */
                        switch(type)
                            {case tk_byte: tok=tk_bytevar;  break;
                            case tk_word:  tok=tk_wordvar;  break;
                            case tk_char:  tok=tk_charvar;  break;
                            case tk_int:   tok=tk_intvar;   break;
                            case tk_dword: tok=tk_dwordvar; break;
                            case tk_long:  tok=tk_longvar;  break;
                            case tk_fixed32s:  tok=tk_fixed32svar;  break;
                            case tk_fixed32u:  tok=tk_fixed32uvar;  break;
                            default:  internalerror("Bad type in globalvar();");
                                      break;
                            }
                        post = 1;
                        segm = DS;
                        if( alignword )
                            {if( size == 2 )
                                {if( postsize%2 == 1 )
                                    postsize++;
                                }
                            else if( size == 4 )
                                postsize += outptrdata%4;
                            }
                        number = postsize;
                        addtotree(var_name);
                        longpostsize = elements * size + postsize;
                        if( longpostsize > 0xFFFFL )
                            {preerror("maximum size of post variables exceeded");
                            postsize = 0xFFFF;}
                        else postsize = longpostsize;
                        nexttok();
                        break;
                    }
                }
            break;
        case tk_proc:
        case tk_regproc:
        case tk_fixed32svar:
        case tk_fixed32uvar:
        case tk_dwordvar:
        case tk_longvar:
        case tk_charvar:
        case tk_intvar:
        case tk_bytevar:
        case tk_wordvar:  idalreadydefined();
                          nexttok();
                          break;
        default:            expected(';');
        case tk_semicolon:  done = 1;
        case tk_camma:      nexttok();
                            break;
        }
    }
}


/* ======= procedure handling starts here ======== */


int setuprm (defflag)
/* set rm, segm and returntype for proper values required for adding
   or modifing the id tree entry of a undef to regproc or proc.
*/
int defflag;
{segm = dynamic_flag;
if( segm != NOT_DYNAMIC )       /* if dynamic proc */
    number = secondcallnum++;   /* get a call number reference */
if( defflag == 0 )
    rm = tk_void;
if( rm != tokens )
    {if( returntype == tokens )
        returntype = rm;
    else if( typesize(returntype) < typesize(rm) )
        {badreturntype();
        return(-1);}
    else rm = returntype;
    }
else if( returntype == tokens )
    {rm = tk_void;
    returntype = tk_void;
    }
else rm = returntype;
return(0);
}


void doregparams ()
{int signflag=0;
expecting(tk_openbracket);
if(tok == tk_closebracket)
    return;
if(tok != tk_camma)
    {switch(tok)
        {
        case tk_int:   signflag=1;
        case tk_word:  nexttok();  doaxmath(signflag);  break;
        case tk_char:  signflag=1;
        case tk_byte:  nexttok();  doalmath(signflag);  break;
        case tk_long:   signflag=1;
        case tk_dword:  nexttok();  doeaxmath(signflag); break;
        case tk_fixed32s:  signflag=1;
        case tk_fixed32u:  nexttok();  dofixed32math(signflag); break;
        case tk_string:  op(0xB8);
                         outword(addpoststring());
                         nexttok();
                         break;
        case tk_longvar:   signflag=1;
        case tk_reg32:
        case tk_dwordvar:  doeaxmath(signflag);  break;
        case tk_fixed32svar:  signflag=1;
        case tk_fixed32uvar:  dofixed32math(signflag); break;
        default:  doaxmath(0);  break;
        }
    }
if(tok == tk_camma)
    nexttok();
else{if(tok != tk_closebracket)
        expected(')');
    return;}
if(tok != tk_camma)
    {switch( tok )
        {case tk_char:
        case tk_byte:  nexttok();  getintobeg(BL);  dobegmath(BL);  break;
        case tk_dword:
        case tk_long:  nexttok();  getintoreg32(EBX);  doreg32math(EBX);  break;
        case tk_fixed32s:
        case tk_fixed32u:  nexttok();
                           getintofixedreg32(EBX);
                           dofixedreg32math(EBX);
                           break;
        case tk_string:  op(0xB8+BX);
                         outword(addpoststring());
                         nexttok();
                         break;
        case tk_dwordvar:
        case tk_reg32:
        case tk_longvar:  getintoreg32(EBX);  doreg32math(EBX);  break;
        case tk_fixed32svar:
        case tk_fixed32uvar:  getintofixedreg32(EBX);
                              dofixedreg32math(EBX);
                              break;
        case tk_int:
        case tk_word:  nexttok();
        default:       getintoreg(BX);
                       doregmath(BX);
                       break;
        }
    }
if(tok == tk_camma)
    nexttok();
else{if(tok != tk_closebracket)
        expected(')');
    return;}
if(tok != tk_camma)
    {switch( tok )
        {case tk_char:
        case tk_byte:  nexttok();  getintobeg(CL);  dobegmath(CL);  break;
        case tk_dword:
        case tk_long:  nexttok();  getintoreg32(ECX);  doreg32math(ECX);  break;
        case tk_fixed32s:
        case tk_fixed32u:  nexttok();
                           getintofixedreg32(ECX);
                           dofixedreg32math(ECX);
                           break;
        case tk_string:  op(0xB8+CX);
                         outword(addpoststring());
                         nexttok();
                         break;
        case tk_dwordvar:
        case tk_reg32:
        case tk_longvar:  getintoreg32(ECX);  doreg32math(ECX);  break;
        case tk_fixed32svar:
        case tk_fixed32uvar:  getintofixedreg32(ECX);
                              dofixedreg32math(ECX);
                              break;
        case tk_int:
        case tk_word:  nexttok();
        default:       getintoreg(CX);
                       doregmath(CX);
                       break;
        }
    }
if(tok == tk_camma)
    nexttok();
else{if(tok != tk_closebracket)
        expected(')');
    return;}
if(tok != tk_camma)
    {switch( tok )
        {case tk_char:
        case tk_byte:  nexttok();  getintobeg(DL);  dobegmath(DL);  break;
        case tk_dword:
        case tk_long:  nexttok();  getintoreg32(EDX);  doreg32math(EDX);  break;
        case tk_fixed32s:
        case tk_fixed32u:  nexttok();
                           getintofixedreg32(EDX);
                           dofixedreg32math(EDX);
                           break;
        case tk_string:  op(0xB8+DX);
                         outword(addpoststring());
                         nexttok();
                         break;
        case tk_dwordvar:
        case tk_reg32:
        case tk_longvar:  getintoreg32(EDX);  doreg32math(EDX);  break;
        case tk_fixed32svar:
        case tk_fixed32uvar:  getintofixedreg32(EDX);
                              dofixedreg32math(EDX);
                              break;
        case tk_int:
        case tk_word:  nexttok();
        default:       getintoreg(DX);
                       doregmath(DX);
                       break;
        }
    }
if(tok == tk_camma)
    nexttok();
else{if(tok != tk_closebracket)
        expected(')');
    return;}
if(tok != tk_camma)
    {switch( tok )
        {case tk_char:
        case tk_byte:  preerror("Only DI and EDI math valid");
                       break;
        case tk_dword:
        case tk_long:  nexttok();  getintoreg32(EDI);  doreg32math(EDI);  break;
        case tk_fixed32s:
        case tk_fixed32u:  nexttok();
                           getintofixedreg32(EDI);
                           dofixedreg32math(EDI);
                           break;
        case tk_string:  op(0xB8+DI);
                         outword(addpoststring());
                         nexttok();
                         break;
        case tk_dwordvar:
        case tk_reg32:
        case tk_longvar:  getintoreg32(EDI);  doreg32math(EDI);  break;
        case tk_fixed32svar:
        case tk_fixed32uvar:  getintofixedreg32(EDI);
                              dofixedreg32math(EDI);
                              break;
        case tk_int:
        case tk_word:  nexttok();
        default:       getintoreg(DI);
                       doregmath(DI);
                       break;
        }
    }
if(tok == tk_camma)
    nexttok();
else{if(tok != tk_closebracket)
        expected(')');
    return;}
if(tok != tk_camma)
    {switch( tok )
        {case tk_char:
        case tk_byte:  preerror("Only SI and ESI math valid");
                       break;
        case tk_dword:
        case tk_long:  nexttok();  getintoreg32(ESI);  doreg32math(ESI);  break;
        case tk_fixed32s:
        case tk_fixed32u:  nexttok();
                           getintofixedreg32(ESI);
                           dofixedreg32math(ESI);
                           break;
        case tk_string:  op(0xB8+SI);
                         outword(addpoststring());
                         nexttok();
                         break;
        case tk_dwordvar:
        case tk_reg32:
        case tk_longvar:  getintoreg32(ESI);  doreg32math(ESI);  break;
        case tk_fixed32svar:
        case tk_fixed32uvar:  getintofixedreg32(ESI);
                              dofixedreg32math(ESI);
                              break;
        case tk_int:
        case tk_word:  nexttok();
        default:       getintoreg(SI);
                       doregmath(SI);
                       break;
        }
    }
if(tok!=tk_closebracket)
    expected(')');
}


regproc (int defflag,int proc_type)
{int inlineflag = 0;  // flag for disabling entry and exit codes production
current_proc_type = proc_type;
tok = tk_regproc;
number = outptr;
if( setuprm(defflag) == -1 )
    return(-1);
if(defflag)
    updatecall( (unsigned int)updatetree(), (unsigned int)number, 0 );
else addtotree(string);
nexttok();
expecting(tk_openbracket);
expecting(tk_closebracket);
if( tok == tk_inline )
    {inlineflag = 1;
    nexttok();}
else if( tok != tk_openbrace )
    declarelocals();
doblock();
if( inlineflag == 0 )
    leaveproc();
killlocals();
}


proc (int defflag,int proc_type)
{int inlineflag = 0;  // flag for disabling entry and exit codes production
current_proc_type = proc_type;
tok = tk_proc;
number = outptr;
if( setuprm(defflag) == -1 )
    return(-1);
if(defflag)
    updatecall( (unsigned int)updatetree(), (unsigned int)number, 0 );
else addtotree(string);
nexttok();
expecting(tk_openbracket);
if(tok!=tk_closebracket)
    declareparams();
nexttok();
if( tok == tk_inline )
    {inlineflag = 1;
    nexttok();}
else{if(paramsize > 0)
        {op(0x55);         /* PUSH BP */
        outword(0xE589);}  /* MOV BP,SP */
    if( tok != tk_openbrace )
        declarelocals();
    }
doblock();              /* do proc */
if( inlineflag == 0 )
    leaveproc();
killlocals();
}


declareparams ()                   /* declare procedure parameters */
{int paramtok;
char flag = 33;

do {if(flag != 33)
        nexttok();
    flag = 1;
    switch(tok)
        {case tk_int:  paramtok = tk_paramint;   break;
        case tk_word:  paramtok = tk_paramword;  break;
        case tk_char:  paramtok = tk_paramchar;  break;
        case tk_byte:  paramtok = tk_parambyte;  break;
        case tk_long:   paramtok = tk_paramlong;  break;
        case tk_dword:  paramtok = tk_paramdword;  break;
        case tk_fixed32s:  paramtok = tk_paramfixed32s;  break;
        case tk_fixed32u:  paramtok = tk_paramfixed32u;  break;
        default:  datatype_expected();
                  flag = 0;
                  nexttok();
                  break;
        }
    if( flag )
        {do {nexttok();
            if( tok != tk_ID && tok != tk_id )
                idexpected();
            else{paramsize += 2;
                if( paramtok == tk_paramlong || paramtok == tk_paramdword
                        || paramtok == tk_paramfixed32s
                        || paramtok == tk_paramfixed32u )
                    paramsize += 2;   // add 2 more bytes
                addlocalvar(string,paramtok,paramsize);
                }
            nexttok();
            } while ( tok == tk_camma );
        }
    } while( tok == tk_semicolon );
}


declarelocals ()                           /* declare locals */
{unsigned int size;
int localtok;

do {switch(tok)
        {case tk_int:  localtok = tk_localint;   size = 2;  break;
        case tk_word:  localtok = tk_localword;  size = 2;  break;
        case tk_char:  localtok = tk_localchar;  size = 1;  break;
        case tk_byte:  localtok = tk_localbyte;  size = 1;  break;
        case tk_long:  localtok = tk_locallong;  size = 4;  break;
        case tk_dword:  localtok = tk_localdword;  size = 4;  break;
        case tk_fixed32s:  localtok = tk_localfixed32s;  size = 4;  break;
        case tk_fixed32u:  localtok = tk_localfixed32u;  size = 4;  break;
        default:  datatype_expected();
                  nexttok();
                  size = 0;
                  break;
        }
    if( size != 0 )
        {do {nexttok();
            if( tok != tk_ID && tok != tk_id )
                idexpected();
            else{addlocalvar(string,localtok,localsize);
                nexttok();
                if( tok == tk_openblock )
                    {nexttok();
                    localsize += doconstlongmath() * size;
                    expecting(tk_closeblock);}
                else localsize += size;
                }
            } while ( tok == tk_camma );
        expecting(tk_semicolon);
        }
    } while( tok != tk_openbrace && tok != tk_eof );
if( optimizespeed || chip < 2 )
    {if(paramsize == 0) /* else this has already been done */
        {op(0x55);            /* PUSH BP */
        op(0x89);  op(0xE5);  /* MOV BP,SP */
        }
    op(0x81);  op(0xEC);
    outword(localsize);}          /* sub SP, # of locals */
else{if(paramsize != 0)
        outptr -= 3;          /* remove PUSH BP and MOV BP,SP */
    op(0xC8);             /* ENTER */
    outword(localsize);   /* # of locals */
    op(0x00);             /* level = 0 */
    if( cpu < 2 )
        cpu = 2;
    }
}


declare_procedure (int rtype,int proc_type)
{returntype = rtype;
procedure_start = outptr;
switch(tok)
    {case tk_id:           proc(0,proc_type);     break;
    case tk_ID:            regproc(0,proc_type);  break;
    case tk_undefregproc:  regproc(1,proc_type);  break;
    case tk_undefproc:     proc(1,proc_type);     break;
    default:               idexpected();          break;
    }
dopoststrings();
}


interruptproc ()
{procedure_start = outptr;
returntype = tk_void;
current_proc_type = cpt_interrupt;
paramsize = 0;
localsize = 0;
nexttok();
if(tok == tk_ID || tok == tk_id)
    {tok = tk_interruptproc;
    number = outptr;
    segm = NOT_DYNAMIC;
    post = 0;
    rm = tk_void;
    addtotree(string);}
else idexpected();
nexttok();
expecting(tk_openbracket);
expecting(tk_closebracket);
doblock();
leaveproc();
paramsize = 0;
localsize = 0;
dopoststrings();
}


doparams ()      /* do stack procedure parameter pushing */
{char done=0,next;
int vartype;
int count;
expecting(tk_openbracket);
if(tok!=tk_closebracket)
    {while(tok!=tk_eof && done==0)
        {if(tok==tk_string)
            {if(chip<2)
                {op(0xB8);
                outword(addpoststring());  /* MOV AX,imm16 */
                op(0x50);}      /* PUSH AX */
            else{op(0x68);
                outword(addpoststring());  /* PUSH imm16 */
                if(cpu < 2)
                    cpu=2;
                }
            nexttok();
            }
        else{switch(tok)
                {case tk_int:
                case tk_word:
                case tk_char:
                case tk_byte:
                case tk_long:
                case tk_fixed32s:
                case tk_fixed32u:
                case tk_dword:  vartype = tok;
                                nexttok();
                                break;
                case tk_longvar:      vartype = tk_long;      break;
                case tk_fixed32svar:  vartype = tk_fixed32s;  break;
                case tk_fixed32uvar:  vartype = tk_fixed32u;  break;
                case tk_dwordvar:     vartype = tk_dword;     break;
                default:        vartype = tk_word;      break;
                }
            if( tok2isopperand() )
                {switch(vartype)
                    {case tk_int:   doaxmath(1);        break;
                    case tk_word:   doaxmath(0);        break;
                    case tk_char:   doalmath(1);        break;
                    case tk_byte:   doalmath(0);        break;
                    case tk_dword:  doeaxmath(0);  op(0x66);
                                    if( cpu < 3 )
                                        cpu = 3;
                                    break;
                    case tk_long:  doeaxmath(1);  op(0x66);
                                   if( cpu < 3 )
                                       cpu = 3;
                                   break;
                    case tk_fixed32s:  dofixed32math(1);
                                       op(0x66);
                                       if( cpu < 3 )
                                           cpu = 3;
                                       break;
                    case tk_fixed32u:  dofixed32math(0);
                                       op(0x66);
                                       if( cpu < 3 )
                                           cpu = 3;
                                       break;
                    default:  beep();  break;
                    }
                op(0x50);}      /* PUSH AX or EAX */
            else{next = 1;
                if(vartype != tk_long && vartype != tk_dword
                       && vartype != tk_fixed32s && vartype != tk_fixed32u )
                    {switch(tok)
                        {case tk_reg:   op(0x50+(unsigned int)number);
                                        break;
                        case tk_seg:  if( (unsigned int)number < FS )
                                          op(0x06+(unsigned int)number*8);
                                      else{op(0xF);  op(0x80+(unsigned int)number*8);
                                      if( (unsigned int)number <= GS )
                                          {if( cpu < 3 )
                                              cpu = 3;
                                          }
                                      else if( cpu < 5 )
                                              cpu = 5;
                                      }
                                      break;
                        case tk_intvar:
                        case tk_wordvar:  outseg(segm,post,2);
                                          op(0xFF);       /* PUSH [word] */
                                          op(0x30+rm);
                                          outaddress(rm,(unsigned int)number);
                                          break;
                        case tk_number: if( chip >= 2 )
                                            {if( number<128 && number>=-128 )
                                                {op(0x6A);  /* PUSH const */
                                                op((unsigned int)number);}
                                            else{op(0x68);   /* PUSH const */
                                                outword((unsigned int)number);}
                                            if( cpu < 2 )
                                                cpu = 2;
                                            break;}
                        default:  switch(vartype)
                                      {case tk_int:  doaxmath(1);       break;
                                      case tk_word:  doaxmath(0);       break;
                                      case tk_char:  doalmath(1);       break;
                                      case tk_byte:  doalmath(0);       break;
                                      default:  beep();  break;
                                      }
                                  op(0x50);   /* PUSH AX */
                                  next = 0;
                                  break;
                        }
                    }
                else{switch(tok)        // long or dword or fixed32
                        {case tk_reg32:  op(0x66);
                                         op(0x50+(unsigned int)number);
                                         break;
                        case tk_fixed32s:
                        case tk_fixed32u:
                        case tk_dwordvar:
                        case tk_longvar:  outseg(segm,post,3);
                                          op(0x66);
                                          op(0xFF);  /* PUSH [dword] */
                                          op(0x30+rm);
                                          outaddress(rm,(unsigned int)number);
                                          break;
                        case tk_number: if( number<128 && number>=-128 )
                                            {op(0x66);
                                            op(0x6A); /* PUSH 8 extend to 32 bit */
                                            op((unsigned int)number);}
                                         else{op(0x66); op(0x68); /* PUSH const */
                                             outdword(number);}
                                         break;
                        default:  if( vartype == tk_long )
                                      doeaxmath(1);
                                  else doeaxmath(0);
                                  op(0x66);  op(0x50);   /* PUSH EAX */
                                  next = 0;
                                  break;
                        }
                    if( cpu < 3 )
                        cpu = 3;
                    }
                if(next)
                    nexttok();
                }
            }
        if(tok==tk_camma)
            nexttok();
        else if(tok==tk_closebracket)
            done = 1;
        else{expected(')');
            done = 1;}
        }
    }
}


leaveproc ()
{if( current_proc_type == cpt_interrupt )   /* interrupt procedure */
    iret();                    /* IRET */
else{if(localsize > 0)
        {if(chip < 2)
            {op(0x89);  op(0xEC);  /* MOV SP,BP */
            op(0x5D);}             /* POP BP */
        else{op(0xC9);       /* LEAVE   (80286+) */
            if( cpu < 2 )
                cpu = 2;
            }
        }
    else if(paramsize > 0)
        op(0x5D);          /* POP BP */
    if( current_proc_type == cpt_far )
        {if(paramsize == 0)
            retf();               /* RETF */
        else retfnum(paramsize);  /* RETF # */
        }
    else{if(paramsize == 0)
            ret();               /* RET */
        else retnum(paramsize);  /* RET # */
        }
    }
}


dynamic_proc ()
{unsigned int dynamicsize;
int regprocflag=0,cpu_hold,dos1_hold,dos2_hold;
int proc_type;
if( dynamic_count >= MAXDYNAMICS )
    preerror("Maximum number of dynamic procedures exceeded.\n");
procedure_start = outptr;
cpu_hold = cpu;
cpu = 0;
dos1_hold = dos1;
dos2_hold = dos2;
dos1 = 0;
dos2 = 0;
nexttok();
switch(tok)
    {case tk_byte:
    case tk_word:
    case tk_int:
    case tk_char:
    case tk_fixed32s:
    case tk_fixed32u:
    case tk_dword:
    case tk_long:
    case tk_void:  returntype = tok;
                   nexttok();
                   break;
    default:               preerror("Return type expected");
                           nexttok();
    case tk_id:
    case tk_ID:
    case tk_undefregproc:
    case tk_undefproc:     returntype = tokens;
                           break;
    }
if( tok == tk_far )
    {proc_type = cpt_far;
    nexttok();
    }
else proc_type = cpt_near;
dynamic_flag = dynamic_count;
switch(tok)
    {case tk_id:           proc(0,proc_type);   break;
    case tk_ID:            regproc(0,proc_type);        regprocflag = 1;  break;
    case tk_undefregproc:  regproc(1,proc_type);        regprocflag = 1;  break;
    case tk_undefproc:     proc(1,proc_type);   break;
    default:  idexpected();  break;
    }

if( dynamic_count < MAXDYNAMICS )   /* store dynamic procedure */
    {dynamicsize = outptr-procedure_start;
    dynamic_ptrs[dynamic_count] = (unsigned char *) malloc( dynamicsize+DYNAMIC_HEADER );
    if( dynamic_ptrs[dynamic_count] == NULL )
        {preerror("Compiler out of memory for dynamic procedure storage");
        exit( e_outofmemory );}
    dynamic_ptrs[dynamic_count][0] = dynamicsize&255;
    dynamic_ptrs[dynamic_count][1] = dynamicsize/256;
    dynamic_ptrs[dynamic_count][2] = cpu;
    dynamic_ptrs[dynamic_count][3] = dos1;
    dynamic_ptrs[dynamic_count][4] = dos2;
    if( dynamicsize > 0 )
        memcpy(dynamic_ptrs[dynamic_count]+DYNAMIC_HEADER,output+procedure_start,dynamicsize);
    dynamic_count++;
    }
cpu = cpu_hold;
dos1 = dos1_hold;
dos2 = dos2_hold;
outptr = procedure_start;
if(comfile != file_exe)
    outptrdata = outptr;
dynamic_flag = NOT_DYNAMIC;
}


/* ======= procedure handling ends here ======== */

macros (expectedreturn)
int expectedreturn;
{int count,dynamicindex,actualreturn;
char heldid[IDLENGTH];
if(tok!=tk_ID && tok!=tk_id && tok!=tk_regproc && tok!=tk_undefregproc
        && tok!=tk_proc && tok!=tk_undefproc)
    {idexpected();
    nexttok();
    return(-1);}
if( tok == tk_regproc && segm != NOT_DYNAMIC )
    {dynamicindex = segm;
    if( dynamicindex >= MAXDYNAMICS )
        dynamicindex -= MAXDYNAMICS;
    actualreturn = rm;
    }
else dynamicindex = NOT_DYNAMIC;
strcpy(heldid,string);
nexttok();
doregparams();
strcpy(string,heldid);
if( dynamicindex == NOT_DYNAMIC )
    {if(includeit(0)==-1)
        unknownmacro();
    }
else{insert_dynamic(dynamicindex,0);
    convert_returnvalue(expectedreturn,actualreturn);}
}


int updatecall (which,where,top)
/* update output with newly defined location, but only for addresses after
   and including top.
   return the number of addresses updated.
*/
unsigned int which,where,top;
{unsigned int count=0,hold;
int updates=0;
while(count<posts)
    {if( (posttype[count]==CALL_NEAR || posttype[count]==CALL_SHORT)
            && postnum[count]==which && postloc[count] >= top )
        {if( posttype[count] == CALL_NEAR )
            {hold = where - (postloc[count] + 2);
            output[postloc[count]] = hold%256;
            output[postloc[count]+1]= hold/256;}
        else{hold = where - (postloc[count] + 1);   /* CALL_SHORT */
            if( short_ok(hold) )
                output[postloc[count]] = hold;
            else shortjumptoolarge();}
        posts--;
        postloc[count] = postloc[posts];
        posttype[count] = posttype[posts];
        postnum[count] = postnum[posts];
        updates++;
        }
    else count++;
    }
return(updates);
}


tobedefined (callkind,expectedreturn)
int callkind,expectedreturn;
{if(tok == tk_ID)
    tok = tk_undefregproc;
else tok = tk_undefproc;
number = secondcallnum;
segm = NOT_DYNAMIC;
rm = expectedreturn;
post = 0;
addtotree(string);
addacall(secondcallnum,callkind);
secondcallnum++;
}


addlocaljump (callkind)
int callkind;
{addlocalvar(string,tk_locallabel,secondcallnum);
addacall(secondcallnum,callkind);
secondcallnum++;
}


define_locallabel ()
{updatecall( (unsigned int)updatelocalvar(string,tk_number,outptr), outptr, procedure_start );
nexttok();
expecting(tk_colon);
}


addacall (idnum,callkind)
unsigned int idnum;
unsigned char callkind;
{if(posts>=MAXPOSTS)
    {preerror("maximum number of second pass procedure calls exceeded");
    return(-1);}
postnum[posts] = idnum;
postloc[posts] = outptr + 1;
posttype[posts] = callkind;
posts++;
}


unsigned int dofrom (dataflag) // returns number of bytes read from FROM file
int dataflag;
{unsigned int size=0,filehandle;
long filesize;
if(tok!=tk_string)
    {stringexpected();
    return(0);}
filehandle = open( string, O_BINARY | O_RDONLY );
if( filehandle == -1 )
    {unableopenfile();
    return(0);}
if( (filesize=filelength(filehandle)) != -1L )
    {if( filesize < 0xFFFFL )
        {size = filesize;
        if(dataflag)
            {filesize += outptrdata;
            if( filesize < MAXDATA )
                {if( read(filehandle,outputdata+outptrdata,size) != size )
                    errorreadingfile();
                outptrdata += size;}
            else maxdataerror();}
        else{filesize += outptr;
            if( filesize < MAXDATA )
                {if( read(filehandle,output+outptr,size) != size )
                    errorreadingfile();
                outptr += size;}
            else maxoutputerror();
            }
        }
    else preerror("FROM file too large");
    }
else preerror("Unable to determine FROM file size");
close(filehandle);
if(comfile != file_exe)
    outptrdata = outptr;
return(size);
}


unsigned int doextract (dataflag) // returns number of bytes EXTRACTed
int dataflag;
{unsigned int size=0,filehandle,sizetoread;
long filesize,startpos;
if(tok!=tk_string)
    {stringexpected();
    return(0);}
filehandle = open( string, O_BINARY | O_RDONLY );
if( filehandle == -1 )
    {unableopenfile();
    return(0);}
nexttok();
expecting(tk_camma);
if( tok != tk_number )
    {numexpected();
    return(0);}
startpos = doconstlongmath();
expecting(tk_camma);
if( tok != tk_number )
    {numexpected();
    return(0);}
sizetoread = doconstlongmath();
if( (filesize=filelength(filehandle)) == -1L )
    {preerror("Unable to determine EXTRACT file size");
    close(filehandle);
    return(0);}
if( filesize <= startpos )
    {preerror("EXTRACT offset exceeds the length of the file");
    close(filehandle);
    return(0);}
if( sizetoread == 0)
    sizetoread = filesize-startpos;
if(sizetoread >= 0xFFFFL)
    {preerror("Block to EXTRACT exceeds 64K");
    close(filehandle);
    return(0);}
lseek(filehandle,startpos,0);   // error checking required on this
filesize = sizetoread;
size = sizetoread;
if(dataflag)
    {filesize += outptrdata;
    if( filesize < MAXDATA )
        {if( read(filehandle,outputdata+outptrdata,size) != size )
            errorreadingfile();
        outptrdata += size;}
    else maxdataerror();}
else{filesize += outptr;
    if( filesize < MAXDATA )
        {if( read(filehandle,output+outptr,size) != size )
            errorreadingfile();
        outptr += size;}
    else maxoutputerror();
    }
close(filehandle);
if(comfile != file_exe)
    outptrdata = outptr;
return(size);
}


outseg (segment,postnumber,locadd)
int segment,postnumber;
unsigned int locadd;
{switch(segment)
    {case ES: op(0x26); break; /* ES: */
    case SS:  if(!assumeDSSS)
                  op(0x36);    /* SS: */
              break;
    case CS:  op(0x2E);        /* CS: */
    case DS:  break;           /* DS: not needed */
    case FS:  op(0x64);        /* FS: */
              if( cpu < 3 )
                  cpu = 3;
              break;
    case GS:  op(0x65);        /* GS: */
              if( cpu < 3 )
                  cpu = 3;
              break;
    case HS:
    case IS:  preerror("Invalid segment override");
              break;
    default:  internalerror("Bad segment value in outset()");
              break;
    }
if(postnumber)
    {if(posts >= MAXPOSTS)
        {maxwordpostserror();
        return(-1);}
    posttype[posts] = POST_VAR;
    postloc[posts] = outptr + locadd;
    posts++;
    }
}


setwordpost ()            /* for post word num setting */
{if(posts >= MAXPOSTS)
    {maxwordpostserror();
    return(-1);}
posttype[posts] = POST_VAR;
postloc[posts] = outptr;
posts++;
}


setdwordpost ()           /* for post dword num setting */
{if(posts >= MAXPOSTS)
    {maxwordpostserror();
    return(-1);}
posttype[posts] = POST_DWORD;
postloc[posts] = outptr;
posts++;
}


doposts ()
{unsigned int addvalue,addhold,addhold2,i;
addvalue = outptrdata;
if( outptrdata%2==1 )  /* alignment of entire post data block manditory */
    {addvalue++;
    postsize++;}
if(MAXDATA-outptrdata < postsize)
    {preerror2("post variable size exceeds size left in data segment");
    return(-1);}
for(i=0;i<posts;i++)
    {if( posttype[i]==POST_VAR )
        {addhold = output[postloc[i]] + (output[postloc[i]+1]<<8) + addvalue;
        output[postloc[i]] = addhold & 255;   /* LOW byte */
        output[postloc[i]+1] = addhold >> 8;  /* HIGH byte */
        }
    else if( posttype[i]==POST_DWORD )
        {addhold2 = output[postloc[i]] + (output[postloc[i]+1] << 8);
        addhold = addhold2 + addvalue;
        output[postloc[i]] = addhold & 255;   /* LOW byte */
        output[postloc[i]+1] = addhold >> 8;  /* HIGH byte */
        if( addhold2 > addhold )  /* if overflow occured, inc high word */
            {addhold = output[postloc[i]+2] + (output[postloc[i]+3]<<8) + 1;
            output[postloc[i]+2] = addhold & 255; /* LOW byte */
            output[postloc[i]+3] = addhold >> 8;  /* HIGH byte */
            }
        }
    }
}


unsigned int addpoststring ()    /* add a string to the post queue */
{unsigned int i,returnvalue;
if( dynamic_flag != NOT_DYNAMIC )
    preerror("String constants are illegal within dynamic procedures");
if(posts >= MAXPOSTS)
    {preerror("cannot add post string, post queue full");
    return(-1);}
posttype[posts] = POST_STRING;
postloc[posts] = outptr;
posts++;
returnvalue = MAXDATA-1-poststrptr;
i=0;
while( string[i]!=0 && poststrptr>0 )
    outputdata[poststrptr--]=string[i++];
if(poststrptr>0)
    outputdata[poststrptr--]=0;
else preerror("Data segment full");
return(returnvalue);
}


dopoststrings ()
{unsigned int addvalue,addhold,i;
addvalue = outptrdata;
if(outptrdata > poststrptr)
    {preerror("post string size exceeds size left in data segment");
    return(-1);}
datasize += MAXDATA-1-poststrptr;
for(i=MAXDATA-1; i>poststrptr; i--)
    outputdata[outptrdata++]=outputdata[i];
if(comfile != file_exe)
    outptr=outptrdata;
for(i=0;i<posts;i++)
    if( posttype[i]==POST_STRING )
        {addhold = outputdata[postloc[i]]
                        + (outputdata[postloc[i]+1] << 8) + addvalue;
        outputdata[postloc[i]] = addhold & 255;   /* LOW byte */
        outputdata[postloc[i]+1] = addhold >> 8;        /* HIGH byte */
        posts--;
        postloc[i]=postloc[posts];
        posttype[i]=posttype[posts];
        postnum[i]=postnum[posts];
        i--;
        }
poststrptr = MAXDATA-1;    /* reset the poststrptr */
}


insertcode ()     // force code procedure at specified location
{nexttok();
switch(tok)
    {case tk_void:
    case tk_word:
    case tk_int:
    case tk_char:
    case tk_fixed32s:
    case tk_fixed32u:
    case tk_byte:  returntype = tok;
                   nexttok();
                   break;
    default:  returntype = tk_word;
              break;
    }
if( tok == tk_id || tok == tk_ID )
    {number = outptr;
    if( setuprm(0) == -1 )
        return(-1);
    }
else if( tok == tk_undefregproc || tok == tk_undefproc )
    {number = outptr;
    if( setuprm(1) == -1 )
        return(-1);
    }
switch(tok)
    {case tk_undefregproc:  tok = tk_regproc;
                            updatecall( (unsigned int)updatetree(), (unsigned int)number,0 );
                            if(includeit(1)==-1)
                                thisundefined(string);
                            break;
    case tk_undefproc:  tok = tk_proc;
                        updatecall( (unsigned int)updatetree(), (unsigned int)number,0 );
                        if(includeproc()==-1)
                            thisundefined(string);
                        break;
    case tk_id:  tok = tk_proc;
                 addtotree(string);
                 if(includeproc()==-1)
                     thisundefined(string);
                 break;
    case tk_ID:  tok = tk_regproc;
                 addtotree(string);
                 if(includeit(1)==-1)
                     thisundefined(string);
                 break;
    case tk_regproc:
    case tk_proc:  if( segm != NOT_DYNAMIC && segm < MAXDYNAMICS )
                       {number = outptr;
                       segm += MAXDYNAMICS;
                       updatecall( (unsigned int)updatetree(), (unsigned int)number,0 );
                       insert_dynamic(segm-MAXDYNAMICS,1);
                       }
                   else preerror("Procedure already inserted in code");
                   break;
    default:  idexpected();
              break;
    }
nexttok();
expecting(tk_openbracket);
while( tok != tk_eof && tok != tk_closebracket )
    nexttok();
if( tok == tk_eof )
    unexpectedeof();
else nextseminext();
}


/************ some of the dynamic procedure support functions *************/


int insert_dynamic (index,retflag)
int index,retflag;
{unsigned int dynamicsize;
if( index >= dynamic_count )
    {internalerror("index value in insert_dynamic too high");
    return(-1);}
dynamicsize = dynamic_ptrs[index][1]*256 + dynamic_ptrs[index][0];
if( retflag==0 && dynamicsize > 0 )
    dynamicsize--;
if( dynamicsize > 0 )
    outprocedure(dynamic_ptrs[index]+DYNAMIC_HEADER,dynamicsize);
if( dynamic_ptrs[index][2] > cpu )
    cpu = dynamic_ptrs[index][2];
if( dynamic_ptrs[index][3] > dos1 )
    dos1 = dynamic_ptrs[index][3];
if( dynamic_ptrs[index][4] > dos2 )
    dos2 = dynamic_ptrs[index][4];
return(0);
}


unsigned int getdynamicsize (index)
int index;
{return( dynamic_ptrs[index][1]*256 + dynamic_ptrs[index][0] );
}


int getdynamiccpu (index)
int index;
{return( dynamic_ptrs[index][2] );
}


int getdynamicdos1 (index)
int index;
{return( dynamic_ptrs[index][3] );
}


int getdynamicdos2 (index)
int index;
{return( dynamic_ptrs[index][4] );
}


/* ==============  allocation of memory for arrays begins ============== */

int getmem ()
/* attempts to allocate memory required for compiling.
   if fails then displays error message and exits to DOS.
*/
{output = (unsigned char *) malloc( (size_t) MAXDATA );
if(output == NULL)
    outofmemory2();
if(comfile != file_exe)
    outputdata = output;
else{outputdata = (unsigned char *) malloc( (size_t) MAXDATA );
    if(outputdata == NULL)
        outofmemory2();
    }
postloc = (unsigned int *) malloc( MAXPOSTS*2 );
if(postloc == NULL)
    outofmemory2();
postnum = (unsigned int *) malloc( MAXPOSTS*2 );
if(postnum == NULL)
    outofmemory2();
posttype = (unsigned char *) malloc( MAXPOSTS );
if(posttype == NULL)
    outofmemory2();
}

/* end of SCC.C */
