/********************************************************************/
/*                              NEGA.C                              */
/********************************************************************/
/*                     The NEGA compiler, v3.22                     */
/*          Copyright (C) Mar. 1997 by Tylisha C. Andersen          */
/*           Original idea developed by Jim Neil, c. 1989           */
/********************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <ctype.h>

#define isxalpha(c)     xalphatbl[(unsigned char) (c)]

int  FindCond(char *in, char *out);
int  GetLine(char *buf);
int  GetStatement(void);
int  GetToken(char *buf, int flg);
void InitToken(void);
int  IsEmpty(char *buf);
int  ParseBumping(void);
int  ParseCond(char *in, char *out, int flip);
int  ParseStatement(void);
int  PeekToken(char *buf);
int  ReadLine(char *buf);
void StripComments(char *buf);

void soutput(char *s, char *fmt, ...);
void xerror(int en);

/********************************************************************/
/* Data section                                                     */
/********************************************************************/

char xalphatbl[256] = {     // see isxalpha() macro
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,
    0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,1,
    0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
};

char InName[128], OutName[128];
char ErrorBuf[400], GenBuf[300];

char SendBuf[3000], FollowBuf[1000];

char LineBuf[300];
long LineCtr = 0;
int  LinePos;

int  BlkStack[30], BlkType[30];
int  BlkPtr = -1, NextBlk = 1;
int  MainBlk = -1;

char Strs[32][128];
char Stat[64];

FILE *InFile = NULL, *OutFile = NULL;

/********************************************************************/
/* Main procedure                                                   */
/********************************************************************/

main(int argc, char *argv[])
{
    printf("ÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜÜ\n"
           "Û³  The NEGA compiler v3.22 (symbolic assembler)  ³Û\n"
           "Û³ Copyright (C) Mar. 1997 by Tylisha C. Andersen ³Û\n"
           "ßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßßß\n\n");

    if(argc < 2) {
        printf("Syntax: NEGA file[.N]\n");
        exit(1);
    }
    strcpy(InName, argv[1]);
    strupr(InName);
    if(!strchr(InName, '.'))
        strcat(InName, ".N");
    strcpy(OutName, InName);
    strcpy(strchr(OutName, '.'), ".ASM");
    if((InFile = fopen(InName, "rb")) == NULL) {
        sprintf(ErrorBuf, "can't open input file %s", InName);
        xerror(0);
    }
    if((OutFile = fopen(OutName, "wb")) == NULL) {
        sprintf(ErrorBuf, "can't open output file %s", OutName);
        xerror(1);
    }

    setvbuf(InFile, NULL, 16384, _IOFBF);
    setvbuf(OutFile, NULL, 16384, _IOFBF);
    printf("input:  %s\n", InName);
    printf("output: %s\n\n", OutName);

    while(ParseStatement());
    printf("\rprocessed %ld lines\n", LineCtr);

    fclose(InFile);
    fclose(OutFile);
    return 0;
}

/********************************************************************/
/* Parse one statement                                              */
/********************************************************************/

int ParseStatement(void)
{
    int i, j, true_blk, to_follow = 0;
    int k, sshift;
    char f_char, *p;
    static char cond1[5], cond2[5];
    static char sbuf[5], ibuf[64];

    if(!PeekToken(&f_char)) return 0;               // peek token to get char
    if(!GetStatement()) return 0;                   // get the statement
    if(BlkType[true_blk = BlkPtr] == 0)             // find the true block
        true_blk--;
    FollowBuf[0] = SendBuf[0] = 0;                  // clear output buffers
    to_follow = ParseBumping();                     // parse pointer bumping

    if(strchr(Stat, '{') || strchr(Stat, '}')) {

////////////////////////////////////////////////////// BLOCK STRUCTURES

        FindCond(Stat, cond1);                      // decode condition(s)
        FindCond(Stat, cond2);
        if((p = strchr(Stat, ',')) != NULL) {

////////////////////////////////////////////////////// ELSE CLAUSE

            if(!strchr(Stat, '{')) goto ps_blkerr;  // ELSE must have '{'
            strcpy(ibuf, p + 1); *(p + 1) = 0;      // separate into halves

            if(ibuf[j = 0] == '.') j = 1;           // check for long jump indicator
                                                    // j = long jump flag
            k = 0;                                  // assume end jump ok

            if(!strcmp(Stat, "},"))                 // nothing
                ;
            else if(Stat[0] != '}') {
                i = true_blk;                       // find the penultimate block
                if(--i < 0) goto ps_noblk;
                if(BlkType[i] == 0) i--;

                if(!strcmp(Stat, ".},") || !strcmp(Stat, "..},")) {
                    soutput(SendBuf, "\tjmp\t%s?End%04X\n",
                        Stat[1] == '.' ? "" : "short ", BlkStack[i]);
                    k = 1;                          // end jump not needed
                } else if(!strcmp(Stat, "?C},") && !strcmp(cond1, "=="))
                    soutput(SendBuf, "\tjcxz\t?End%04X\n", BlkStack[i]);
                else if(!strcmp(Stat, "-C},") && !strcmp(cond1, "=="))
                    soutput(SendBuf, "\tloopz\t?End%04X\n", BlkStack[i]);
                else if(!strcmp(Stat, "-C},") && !strcmp(cond1, "<>"))
                    soutput(SendBuf, "\tloopnz\t?End%04X\n", BlkStack[i]);
                else if(!strcmp(Stat, "-.},"))
                    soutput(SendBuf, "\tloop\t?End%04X\n", BlkStack[i]);
                else {
                    ParseCond(cond1, sbuf, 0);      // parse conditions
                    if(!strcmp(Stat, "C},") || !strcmp(Stat, ".C},"))
                        soutput(SendBuf, "\tj%s\t%s?End%04X\n", sbuf, Stat[0] == '.' ? "" : "short ", BlkStack[i]);
                    else goto ps_blkerr;
                }
            } else {
                ParseCond(cond1, sbuf, 0);          // parse other conditions
                     if(!strcmp(Stat, "}C,"))   soutput(SendBuf, "\tj%s\t?Top%04X\n", sbuf, BlkStack[BlkPtr]);
                else if(!strcmp(Stat, "}.,"))   soutput(SendBuf, "\tjmp\t?Top%04X\n", BlkStack[BlkPtr]);
                else if(!strcmp(Stat, "}-.,"))  soutput(SendBuf, "\tloop\t?Top%04X\n", BlkStack[BlkPtr]);
                else if(!strcmp(Stat, "}.C,")) {    // distant loop
                    ParseCond(cond1, sbuf, k = 1);  // parse as reverse
                    if(!j) {                        // short jump to end
                        soutput(SendBuf, "\tj%s\t?End%04X\n", sbuf, BlkStack[true_blk]);
                        soutput(SendBuf, "\tjmp\t?Top%04X\n", BlkStack[BlkPtr]);
                    } else {                        // long jump to end
                        soutput(SendBuf, "\tj%s\t?Els%04X\n", sbuf, NextBlk);
                        soutput(SendBuf, "\tjmp\t?Top%04X\n", BlkStack[BlkPtr]);
                        soutput(SendBuf, "?Els%04X:\n", NextBlk++);
                        soutput(SendBuf, "\tjmp\t?End%04X\n", BlkStack[true_blk]);
                    }
                } else if(!strcmp(Stat, "}?C;") && !strcmp(cond1, "==")) {
                    soutput(SendBuf, "\tjcxz\t?Top%04X\n", BlkStack[BlkPtr]);
                } else if(!strcmp(Stat, "}-C;") && !strcmp(cond1, "==")) {
                    soutput(SendBuf, "\tloopz\t?Top%04X\n", BlkStack[BlkPtr]);
                } else if(!strcmp(Stat, "}-C;") && !strcmp(cond1, "<>")) {
                    soutput(SendBuf, "\tloopnz\t?Top%04X\n", BlkStack[BlkPtr]);
                } else goto ps_blkerr;
            }

            if(strchr(Stat, 'C'))                   // cond1 = second conditional
                strcpy(cond1, cond2);
            if(!k) {                                // output jump to end if not done already
                soutput(SendBuf, "\tjmp\t%s?End%04X\n",
                    j ? "" : "short ", BlkStack[true_blk]);
            }
            soutput(SendBuf, "?Els%04X:\n", BlkStack[BlkPtr]);
            if(BlkType[BlkPtr] == 1)                // if true block, add an else block
                if(++BlkPtr >= 30) goto ps_nesterr;
            BlkStack[BlkPtr] = NextBlk++;           // set up new block
            BlkType[BlkPtr] = 0;

            if(!strcmp(ibuf, "{") || !strcmp(ibuf, ".{"))
                ;                                   // nothing
            else if(!strcmp(ibuf, "C{")) {          // conditional else
                ParseCond(cond1, sbuf, 1);
                soutput(SendBuf, "\tj%s\t?Els%04X\n", sbuf, BlkStack[BlkPtr]);
            } else if(!strcmp(ibuf, ".C{")) {       // IF clause (near jump)
                ParseCond(cond1, sbuf, 0);
                soutput(SendBuf, "\tj%s\t?Top%04X\n", sbuf, BlkStack[BlkPtr]);
                soutput(SendBuf, "\tjmp\t?Els%04X\n", BlkStack[BlkPtr]);
            } else if(!strcmp(ibuf, "?C{") && !strcmp(cond1, "<>")) {
                soutput(SendBuf, "\tjcxz\t?Els%04X\n", BlkStack[BlkPtr]);
            } else if(!strcmp(ibuf, "-.{")) {
                soutput(SendBuf, "\tloop\t?Els%04X\n", BlkStack[BlkPtr]);
            } else if(!strcmp(ibuf, "-C{") && !strcmp(cond1, "<>")) {
                soutput(SendBuf, "\tloopne\t?Els%04X\n", BlkStack[BlkPtr]);
            } else if(!strcmp(ibuf, "-C{") && !strcmp(cond1, "==")) {
                soutput(SendBuf, "\tloope\t?Els%04X\n", BlkStack[BlkPtr]);
            } else goto ps_blkerr;
            soutput(SendBuf, "?Top%04X:\n", BlkStack[BlkPtr]);
        } else if(strchr(Stat, ';')) {

////////////////////////////////////////////////////// END OF BLOCK

            if(BlkPtr < 0) goto ps_blkerr;          // no block here?
            if(!strcmp(Stat, "};"))                 // nothing
                ;
            else if(Stat[0] != '}') {
                i = true_blk;                       // find the penultimate block
                if(--i < 0) goto ps_noblk;
                if(BlkType[i] == 0) i--;

                if(!strcmp(Stat, ".};") || !strcmp(Stat, "..};"))
                    soutput(SendBuf, "\tjmp\t%s?End%04X\n", Stat[1] == '.' ? "" : "short ", BlkStack[i]);
                else if(!strcmp(Stat, "?C};") && !strcmp(cond1, "=="))
                    soutput(SendBuf, "\tjcxz\t?End%04X\n", BlkStack[i]);
                else if(!strcmp(Stat, "-C};") && !strcmp(cond1, "=="))
                    soutput(SendBuf, "\tloopz\t?End%04X\n", BlkStack[i]);
                else if(!strcmp(Stat, "-C};") && !strcmp(cond1, "<>"))
                    soutput(SendBuf, "\tloopnz\t?End%04X\n", BlkStack[i]);
                else if(!strcmp(Stat, "-.};"))
                    soutput(SendBuf, "\tloop\t?End%04X\n", BlkStack[i]);
                else {
                    ParseCond(cond1, sbuf, 0);      // parse conditions
                    if(!strcmp(Stat, "C};") || !strcmp(Stat, ".C};"))
                        soutput(SendBuf, "\tj%s\t%s?End%04X\n", sbuf, Stat[0] == '.' ? "" : "short ", BlkStack[i]);
                    else goto ps_blkerr;
                }
            } else {
                ParseCond(cond1, sbuf, 0);          // parse other conditions
                     if(!strcmp(Stat, "}C;"))   soutput(SendBuf, "\tj%s\t?Top%04X\n", sbuf, BlkStack[BlkPtr]);
                else if(!strcmp(Stat, "}.;"))   soutput(SendBuf, "\tjmp\t?Top%04X\n", BlkStack[BlkPtr]);
                else if(!strcmp(Stat, "}-.;"))  soutput(SendBuf, "\tloop\t?Top%04X\n", BlkStack[BlkPtr]);
                else if(!strcmp(Stat, "}.C;")) {    // distant loop
                    ParseCond(cond1, sbuf, 1);      // parse as reverse
                    soutput(SendBuf, "\tj%s\t?Els%04X\n", sbuf, BlkStack[BlkPtr]);
                    soutput(SendBuf, "\tjmp\t?Top%04X\n", BlkStack[BlkPtr]);
                } else if(!strcmp(Stat, "}?C;") && !strcmp(cond1, "==")) {
                    soutput(SendBuf, "\tjcxz\t?Top%04X\n", BlkStack[BlkPtr]);
                } else if(!strcmp(Stat, "}-C;") && !strcmp(cond1, "==")) {
                    soutput(SendBuf, "\tloopz\t?Top%04X\n", BlkStack[BlkPtr]);
                } else if(!strcmp(Stat, "}-C;") && !strcmp(cond1, "<>")) {
                    soutput(SendBuf, "\tloopnz\t?Top%04X\n", BlkStack[BlkPtr]);
                } else goto ps_blkerr;
            }

            soutput(SendBuf, "?Els%04X:\n", BlkStack[BlkPtr]);
            if(BlkType[BlkPtr] == 0) BlkPtr--;
            soutput(SendBuf, "?End%04X:\n", BlkStack[BlkPtr--]);
        } else {

////////////////////////////////////////////////////// START OF BLOCK

            if(++BlkPtr >= 30) goto ps_nesterr;     // add a true block
            BlkStack[BlkPtr] = NextBlk++;
            BlkType[BlkPtr] = 1;
            if(!strcmp(Stat, "{"))                  // nothing
                ;
            else if(!strcmp(Stat, "C{")) {          // IF clause (short jump)
                ParseCond(cond1, sbuf, 1);
                soutput(SendBuf, "\tj%s\t?Els%04X\n", sbuf, BlkStack[BlkPtr]);
            } else if(!strcmp(Stat, ".C{")) {       // IF clause (near jump)
                ParseCond(cond1, sbuf, 0);
                soutput(SendBuf, "\tj%s\t?Top%04X\n", sbuf, BlkStack[BlkPtr]);
                soutput(SendBuf, "\tjmp\t?Els%04X\n", BlkStack[BlkPtr]);
            } else if(!strcmp(Stat, "?C{") && !strcmp(cond1, "<>")) {
                soutput(SendBuf, "\tjcxz\t?Els%04X\n", BlkStack[BlkPtr]);
            } else if(!strcmp(Stat, ".{")) {
                soutput(SendBuf, "\tjmp\tshort ?Els%04X\n", BlkStack[BlkPtr]);
            } else if(!strcmp(Stat, "..{")) {
                soutput(SendBuf, "\tjmp\t?Els%04X\n", BlkStack[BlkPtr]);
            } else if(!strcmp(Stat, "-.{")) {
                soutput(SendBuf, "\tloop\t?Els%04X\n", BlkStack[BlkPtr]);
            } else if(!strcmp(Stat, "-C{") && !strcmp(cond1, "<>")) {
                soutput(SendBuf, "\tloopne\t?Els%04X\n", BlkStack[BlkPtr]);
            } else if(!strcmp(Stat, "-C{") && !strcmp(cond1, "==")) {
                soutput(SendBuf, "\tloope\t?Els%04X\n", BlkStack[BlkPtr]);
            } else goto ps_blkerr;
            soutput(SendBuf, "?Top%04X:\n", BlkStack[BlkPtr]);
        }
    } else if(f_char == 'A') {

////////////////////////////////////////////////////// ALPHA STATEMENT

        if(!memcmp(Stat, "A=A=", 4)) {              // reverse-output command?
            p = Stat;
            while(!memcmp(p, "A=", 2))              // check for POP sequence
                p += 2;
            if(*p == ';') {                         // if POP sequence, then
                i = (p - 2 - Stat) / 2;
                for(; i >= 0; i--)                  // output the POPs
                    soutput(SendBuf, "\tpop\t%s\n", Strs[i]);
                goto ps_output;
            } else {                                // chained assignments
                j = (p - 2 - Stat) / 2;             // j = work register
                p = Stat; i = 0;
                for(i = 0; i < j; i++) {            // output in order
                    soutput(FollowBuf, "\tmov\t%s,%s\n",
                        Strs[i], Strs[j]);
                }
                for(i = 0; i < 32 - j; i++)         // shift out assignment commands
                    strcpy(Strs[i], Strs[i + j]);
                memmove(Stat, Stat + j * 2, 64 - j * 2);
                to_follow = 1;                      // set follow flag
            }
        }

        j = 1;                                      // current operand
        sshift = 0;                                 // no shift for now

////////////////////////////////////////////////////// First-op-only commands

        if(!memcmp(Stat, "A,", 2)) {
            if(!memcmp(Stat, "A,A*A", 5)) {             // three-operand IMUL
                soutput(SendBuf, "\timul\t%s,%s,%s\n", Strs[0], Strs[1], Strs[2]);
                sshift = 4; j++;
            } else if(!strcmp(Stat, "A,A<A;")) {        // shift left double
                soutput(SendBuf, "\tshld\t%s,%s,%s\n", Strs[0], Strs[1], Strs[2]);
                goto ps_output;
            } else if(!strcmp(Stat, "A,A>A;")) {        // shift right double
                soutput(SendBuf, "\tshrd\t%s,%s,%s\n", Strs[1], Strs[0], Strs[2]);
                goto ps_output;
            } else if(!strcmp(Stat, "A,A=A;")) {        // LDS, LES, etc.
                soutput(SendBuf, "\tl%s\t%s,%s\n", Strs[0], Strs[1], Strs[2]);
                goto ps_output;
            }
        } else if(!strcmp(Stat, "A=;")) {           // single POP
            soutput(SendBuf, "\tpop\t%s\n", Strs[0]); goto ps_output;
        } else if(!memcmp(Stat, "A=A",  3)) {   soutput(SendBuf, "\tmov\t%s,%s\n",  Strs[0], Strs[1]);  sshift = 2;
        } else if(!memcmp(Stat, "A=+A", 4)) {   soutput(SendBuf, "\tmovzx\t%s,%s\n",Strs[0], Strs[1]);  sshift = 3;
        } else if(!memcmp(Stat, "A=-A", 4)) {   soutput(SendBuf, "\tmovsx\t%s,%s\n",Strs[0], Strs[1]);  sshift = 4;
        } else if(!memcmp(Stat, "A=+-A",5)) {   soutput(SendBuf, "\tmovsx\t%s,%s\n",Strs[0], Strs[1]);  sshift = 4;
        } else if(!memcmp(Stat, "A==A", 4)) {   soutput(SendBuf, "\txchg\t%s,%s\n", Strs[0], Strs[1]);  sshift = 3;
        } else if(!memcmp(Stat, "A===A",5)) {   soutput(SendBuf, "\tlea\t%s,%s\n",  Strs[0], Strs[1]);  sshift = 4;
        } else if(!memcmp(Stat, "A=", 2)) {
            strcpy(ibuf, Stat + 2);                 // conditional set (SETNZ, SETBE, etc.)
            i = strlen(ibuf) - 1;
            if(ibuf[i] == ';') {
                ibuf[i] = 0;
                if(ParseCond(ibuf, sbuf, 0)) {
                    soutput(SendBuf, "\tset%s\t%s\n", sbuf, Strs[0]);
                    goto ps_output;
                }
            }
        }

////////////////////////////////////////////////////// General commands

        while(1) {
            if(sshift > 0) {                        // shift out first part
                memmove(Stat+1, Stat+1 + sshift, 63 - sshift);
                j++;                                // next operand
            }

            if(!strcmp(Stat, "A;") && j > 1) {
                goto ps_output;
            } else if(!strcmp(Stat, "A+;")) {   soutput(SendBuf, "\tinc\t%s\n", Strs[0]);               goto ps_output;
            } else if(!strcmp(Stat, "A-;")) {   soutput(SendBuf, "\tdec\t%s\n", Strs[0]);               goto ps_output;
            } else if(!strcmp(Stat, "A++;")) {  soutput(SendBuf, "\tinc\t%s\n\tinc\t%s\n", Strs[0], Strs[0]);
                                                                                                        goto ps_output;
            } else if(!strcmp(Stat, "A--;")) {  soutput(SendBuf, "\tdec\t%s\n\tdec\t%s\n", Strs[0], Strs[0]);
                                                                                                        goto ps_output;
            } else if(!strcmp(Stat, "A&A?")) {  soutput(SendBuf, "\ttest\t%s,%s\n", Strs[0], Strs[j]);  goto ps_output;
            } else if(!strcmp(Stat, "A-A?")) {  soutput(SendBuf, "\tcmp\t%s,%s\n",  Strs[0], Strs[j]);  goto ps_output;
            } else if(!strcmp(Stat, "A?")) {    soutput(SendBuf, "\ttest\t%s,%s\n", Strs[0], Strs[0]);  goto ps_output;
            } else if(!memcmp(Stat, "A+++", 4)) {   soutput(SendBuf, "\tinc\t%s\n", Strs[0]);          j--; sshift = 1;
            } else if(!memcmp(Stat, "A---", 4)) {   soutput(SendBuf, "\tdec\t%s\n", Strs[0]);          j--; sshift = 1;
            } else if(!memcmp(Stat, "A+A",  3)) {   soutput(SendBuf, "\tadd\t%s,%s\n", Strs[0], Strs[j]);   sshift = 2;
            } else if(!memcmp(Stat, "A++A", 4)) {   soutput(SendBuf, "\tadc\t%s,%s\n", Strs[0], Strs[j]);   sshift = 3;
            } else if(!memcmp(Stat, "A-A",  3)) {   soutput(SendBuf, "\tsub\t%s,%s\n", Strs[0], Strs[j]);   sshift = 2;
            } else if(!memcmp(Stat, "A--A", 4)) {   soutput(SendBuf, "\tsbb\t%s,%s\n", Strs[0], Strs[j]);   sshift = 3;
            } else if(!memcmp(Stat, "A&A",  3)) {   soutput(SendBuf, "\tand\t%s,%s\n", Strs[0], Strs[j]);   sshift = 2;
            } else if(!memcmp(Stat, "A|A",  3)) {   soutput(SendBuf, "\tor\t%s,%s\n",  Strs[0], Strs[j]);   sshift = 2;
            } else if(!memcmp(Stat, "A^A",  3)) {   soutput(SendBuf, "\txor\t%s,%s\n", Strs[0], Strs[j]);   sshift = 2;
            } else if(!memcmp(Stat, "A*A",  3)) {   soutput(SendBuf, "\timul\t%s,%s\n",Strs[0], Strs[j]);   sshift = 2;
            } else if(!memcmp(Stat, "A<A",  3)) {   soutput(SendBuf, "\tshl\t%s,%s\n", Strs[0], Strs[j]);   sshift = 2;
            } else if(!memcmp(Stat, "A>A",  3)) {   soutput(SendBuf, "\tshr\t%s,%s\n", Strs[0], Strs[j]);   sshift = 2;
            } else if(!memcmp(Stat, "A+->A",5)) {   soutput(SendBuf, "\tsar\t%s,%s\n", Strs[0], Strs[j]);   sshift = 4;
            } else if(!memcmp(Stat, "A<<A", 4)) {   soutput(SendBuf, "\trol\t%s,%s\n", Strs[0], Strs[j]);   sshift = 3;
            } else if(!memcmp(Stat, "A>>A", 4)) {   soutput(SendBuf, "\tror\t%s,%s\n", Strs[0], Strs[j]);   sshift = 3;
            } else if(!memcmp(Stat, "A<<<A",5)) {   soutput(SendBuf, "\trcl\t%s,%s\n", Strs[0], Strs[j]);   sshift = 4;
            } else if(!memcmp(Stat, "A>>>A",5)) {   soutput(SendBuf, "\trcr\t%s,%s\n", Strs[0], Strs[j]);   sshift = 4;
            } else if(!memcmp(Stat, "A**A", 4)) {   soutput(SendBuf, "\tmul\t%s,%s\n", Strs[0], Strs[j]);   sshift = 3;
            } else if(!memcmp(Stat, "A/A",  3)) {   soutput(SendBuf, "\tidiv\t%s,%s\n",Strs[0], Strs[j]);   sshift = 2;
            } else if(!memcmp(Stat, "A//A", 4)) {   soutput(SendBuf, "\tdiv\t%s,%s\n", Strs[0], Strs[j]);   sshift = 3;
            } else {
                if(j == 1) goto ps_passthru;       // pass-through?
                else goto ps_error;
            }
        }
    } else switch(f_char) {                        // OTHER STATEMENTS (by char)
        case '!':
                 if(!strcmp(Stat, "!A;"))           soutput(SendBuf, "\tint\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "!+;"))           soutput(SendBuf, "\tsti\n");
            else if(!strcmp(Stat, "!-;"))           soutput(SendBuf, "\tcli\n");
            else if(!strcmp(Stat, "!.=;"))          soutput(SendBuf, "\tiret\n");
            else if(!strcmp(Stat, "!+-;"))          soutput(SendBuf, "\tinto\n");
            else goto ps_error;
            break;

        case '\"':
                 if(!strcmp(Stat, "\"*;"))          soutput(SendBuf, "\taam\n");
            else if(!strcmp(Stat, "\"+;"))          soutput(SendBuf, "\taaa\n");
            else if(!strcmp(Stat, "\"-;"))          soutput(SendBuf, "\taas\n");
            else if(!strcmp(Stat, "\"/;"))          soutput(SendBuf, "\taad\n");
            else if(!strcmp(Stat, "\"*A;"))         soutput(SendBuf, "\tdb\t0D4h,%s\n", Strs[0]);
            else if(!strcmp(Stat, "\"/A;"))         soutput(SendBuf, "\tdb\t0D5h,%s\n", Strs[0]);
            else goto ps_error;
            break;

        case '#':
                 if(!strcmp(Stat, "#+-;"))          soutput(SendBuf, "\tfabs\n");
            else if(!strcmp(Stat, "#+;"))           soutput(SendBuf, "\tfadd\n");
            else if(!strcmp(Stat, "#+A;"))          soutput(SendBuf, "\tfadd\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#A+A;"))         soutput(SendBuf, "\tfadd\t%s,%s\n", Strs[0], Strs[1]);
            else if(!strcmp(Stat, "#+.;"))          soutput(SendBuf, "\tfaddp\n");
            else if(!strcmp(Stat, "#+A.;"))         soutput(SendBuf, "\tfaddp\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#A+A.;"))        soutput(SendBuf, "\tfaddp\t%s,%s\n", Strs[0], Strs[1]);
            else if(!strcmp(Stat, "#-+;"))          soutput(SendBuf, "\tfchs\n");
            else if(!strcmp(Stat, "#-?;"))          soutput(SendBuf, "\tfcom\n");
            else if(!strcmp(Stat, "#-A?;"))         soutput(SendBuf, "\tfcom\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#-?.;"))         soutput(SendBuf, "\tfcomp\n");
            else if(!strcmp(Stat, "#-A?.;"))        soutput(SendBuf, "\tfcomp\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#-?..;"))        soutput(SendBuf, "\tfcompp\n");
            else if(!strcmp(Stat, "#=-;"))          soutput(SendBuf, "\tfdecstp\n");
            else if(!strcmp(Stat, "#/;"))           soutput(SendBuf, "\tfdiv\n");
            else if(!strcmp(Stat, "#/A;"))          soutput(SendBuf, "\tfdiv\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#A/A;"))         soutput(SendBuf, "\tfdiv\t%s,%s\n", Strs[0], Strs[1]);
            else if(!strcmp(Stat, "#/.;"))          soutput(SendBuf, "\tfdivp\n");
            else if(!strcmp(Stat, "#/A.;"))         soutput(SendBuf, "\tfdivp\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#A/A.;"))        soutput(SendBuf, "\tfdivp\t%s,%s\n", Strs[0], Strs[1]);
            else if(!strcmp(Stat, "#//;"))          soutput(SendBuf, "\tfdivr\n");
            else if(!strcmp(Stat, "#//A;"))         soutput(SendBuf, "\tfdivr\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#A//A;"))        soutput(SendBuf, "\tfdivr\t%s,%s\n", Strs[0], Strs[1]);
            else if(!strcmp(Stat, "#//.;"))         soutput(SendBuf, "\tfdivrp\n");
            else if(!strcmp(Stat, "#//A.;"))        soutput(SendBuf, "\tfdivrp\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#A//A.;"))       soutput(SendBuf, "\tfdivrp\t%s,%s\n", Strs[0], Strs[1]);
            else if(!strcmp(Stat, "#&A;"))          soutput(SendBuf, "\tffree\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#>+A;"))         soutput(SendBuf, "\tfiadd\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#>-A?;"))        soutput(SendBuf, "\tficom\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#>-A?.;"))       soutput(SendBuf, "\tficomp\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#>/A;"))         soutput(SendBuf, "\tfidiv\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#>//A;"))        soutput(SendBuf, "\tfidivr\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#>=A;"))         soutput(SendBuf, "\tfild\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#>*A;"))         soutput(SendBuf, "\tfimul\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#=+;"))          soutput(SendBuf, "\tfincstp\n");
            else if(!strcmp(Stat, "#;"))            soutput(SendBuf, "\tfinit\n");
            else if(!strcmp(Stat, "#!;"))           soutput(SendBuf, "\tfninit\n");
            else if(!strcmp(Stat, "#>A=;"))         soutput(SendBuf, "\tfist\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#>A=.;"))        soutput(SendBuf, "\tfistp\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#>-A;"))         soutput(SendBuf, "\tfisub\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#>--A;"))        soutput(SendBuf, "\tfisubr\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#=A;"))          soutput(SendBuf, "\tfld\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#*;"))           soutput(SendBuf, "\tfmul\n");
            else if(!strcmp(Stat, "#*A;"))          soutput(SendBuf, "\tfmul\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#A*A;"))         soutput(SendBuf, "\tfmul\t%s,%s\n", Strs[0], Strs[1]);
            else if(!strcmp(Stat, "#*.;"))          soutput(SendBuf, "\tfmulp\n");
            else if(!strcmp(Stat, "#*A.;"))         soutput(SendBuf, "\tfmulp\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#A*A.;"))        soutput(SendBuf, "\tfmulp\t%s,%s\n", Strs[0], Strs[1]);
            else if(!strcmp(Stat, "#%;"))           soutput(SendBuf, "\tfprem\n");
            else if(!strcmp(Stat, "#%%;"))          soutput(SendBuf, "\tfprem1\n");
            else if(!strcmp(Stat, "#<>;"))          soutput(SendBuf, "\tfrndint\n");
            else if(!strcmp(Stat, "#**;"))          soutput(SendBuf, "\tfscale\n");
            else if(!strcmp(Stat, "#A=;"))          soutput(SendBuf, "\tfst\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#A=.;"))         soutput(SendBuf, "\tfstp\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#A=?;"))         soutput(SendBuf, "\tfstsw\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#!A=?;"))        soutput(SendBuf, "\tfnstsw\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#-;"))           soutput(SendBuf, "\tfsub\n");
            else if(!strcmp(Stat, "#-A;"))          soutput(SendBuf, "\tfsub\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#A-A;"))         soutput(SendBuf, "\tfsub\t%s,%s\n", Strs[0], Strs[1]);
            else if(!strcmp(Stat, "#-.;"))          soutput(SendBuf, "\tfsubp\n");
            else if(!strcmp(Stat, "#-A.;"))         soutput(SendBuf, "\tfsubp\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#A-A.;"))        soutput(SendBuf, "\tfsubp\t%s,%s\n", Strs[0], Strs[1]);
            else if(!strcmp(Stat, "#--;"))          soutput(SendBuf, "\tfsubr\n");
            else if(!strcmp(Stat, "#--A;"))         soutput(SendBuf, "\tfsubr\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#A--A;"))        soutput(SendBuf, "\tfsubr\t%s,%s\n", Strs[0], Strs[1]);
            else if(!strcmp(Stat, "#--.;"))         soutput(SendBuf, "\tfsubrp\n");
            else if(!strcmp(Stat, "#--A.;"))        soutput(SendBuf, "\tfsubrp\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#A--A.;"))       soutput(SendBuf, "\tfsubrp\t%s,%s\n", Strs[0], Strs[1]);
            else if(!strcmp(Stat, "#?;"))           soutput(SendBuf, "\tftst\n");
            else if(!strcmp(Stat, "#<>?;"))         soutput(SendBuf, "\tfucom\n");
            else if(!strcmp(Stat, "#<>A?;"))        soutput(SendBuf, "\tfucom\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#<>?.;"))        soutput(SendBuf, "\tfucomp\n");
            else if(!strcmp(Stat, "#<>A?.;"))       soutput(SendBuf, "\tfucomp\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "#<>?..;"))       soutput(SendBuf, "\tfucompp\n");
            else if(!strcmp(Stat, "#.;"))           soutput(SendBuf, "\tfwait\n");
            else if(!strcmp(Stat, "#??;"))          soutput(SendBuf, "\tfxam\n");
            else if(!strcmp(Stat, "#==;"))          soutput(SendBuf, "\tfxch\n");
            else if(!strcmp(Stat, "#==A;"))         soutput(SendBuf, "\tfxch\t%s\n", Strs[0]);
            else goto ps_error;
            break;

        case '%':
            if(!strcmp(Stat, "%.A;"))
                soutput(SendBuf, "\textrn\t%s:proc\n\tcall\t%s\n", Strs[0], Strs[0]);
            else if(!strcmp(Stat, "%=;"))           soutput(SendBuf, "\tpopa\n");
            else goto ps_error;
            break;

        case '&':
                 if(!strcmp(Stat, "&&A;"))          goto ps_parsejcc0;
            else if(!strcmp(Stat, "&&;"))           goto ps_parsebrk0;
            else if(!strcmp(Stat, "&;"))            soutput(SendBuf, "\tclc\n");
            else if(!strcmp(Stat, "&A;"))           soutput(SendBuf, "\tsub\t%s,%s\n", Strs[0], Strs[0]);
            else goto ps_error;
            break;

        case '\'':
                 if(!strcmp(Stat, "\'+;"))          soutput(SendBuf, "\tdaa\n");
            else if(!strcmp(Stat, "\'-;"))          soutput(SendBuf, "\tdas\n");
            else goto ps_error;
            break;

        case '*':
                 if(!strcmp(Stat, "**A;"))          soutput(SendBuf, "\tmul\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "*A;"))           soutput(SendBuf, "\timul\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "*;"))            soutput(SendBuf, "\tcbw\n");
            else if(!strcmp(Stat, "**;"))           soutput(SendBuf, "\tcwd\n");
            else if(!strcmp(Stat, "****;"))         soutput(SendBuf, "\tcdq\n");
            else if(!strcmp(Stat, "*=;"))           soutput(SendBuf, "\tstosb\n");
            else if(!strcmp(Stat, "**=;"))          soutput(SendBuf, "\tstosw\n");
            else if(!strcmp(Stat, "****=;"))        soutput(SendBuf, "\tstosd\n");
            else if(!strcmp(Stat, "*=*;"))          soutput(SendBuf, "\tmovsb\n");
            else if(!strcmp(Stat, "**=**;"))        soutput(SendBuf, "\tmovsw\n");
            else if(!strcmp(Stat, "****=****;"))    soutput(SendBuf, "\tmovsd\n");
            else if(!strcmp(Stat, "*-?"))           soutput(SendBuf, "\tscasb\n");
            else if(!strcmp(Stat, "**-?"))          soutput(SendBuf, "\tscasw\n");
            else if(!strcmp(Stat, "****-?"))        soutput(SendBuf, "\tscasd\n");
            else if(!strcmp(Stat, "*-*?"))          soutput(SendBuf, "\tcmpsb\n");
            else if(!strcmp(Stat, "**-**?"))        soutput(SendBuf, "\tcmpsw\n");
            else if(!strcmp(Stat, "****-****?"))    soutput(SendBuf, "\tcmpsd\n");
            else if(!strcmp(Stat, "*=@;"))          soutput(SendBuf, "\tinsb\n");
            else if(!strcmp(Stat, "**=@;"))         soutput(SendBuf, "\tinsw\n");
            else if(!strcmp(Stat, "****=@;"))       soutput(SendBuf, "\tinsd\n");
            else if(!strcmp(Stat, "**=@@;"))        soutput(SendBuf, "\tinsw\n");
            else if(!strcmp(Stat, "****=@@@@;"))    soutput(SendBuf, "\tinsd\n");
            else if(!strcmp(Stat, "*A=;"))          soutput(SendBuf, "\tstos\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "*A=*A;"))        soutput(SendBuf, "\tmovs\t%s,%s\n", Strs[0], Strs[1]);
            else if(!strcmp(Stat, "*A-?"))          soutput(SendBuf, "\tscas\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "*A-*A?"))        soutput(SendBuf, "\tcmps\t%s,%s\n", Strs[0], Strs[1]);
            else if(!strcmp(Stat, "*A=@;"))         soutput(SendBuf, "\tins\t%s\n", Strs[0]);
            else goto ps_error;
            break;

        case '+':
                 if(!strcmp(Stat, "++A;"))          goto ps_parsejcc0;
            else if(!strcmp(Stat, "+-A;"))          goto ps_parsejcc0;
            else if(!strcmp(Stat, "++;"))           goto ps_parsebrk0;
            else if(!strcmp(Stat, "+-;"))           goto ps_parsebrk0;
            else if(!strcmp(Stat, "+;"))            soutput(SendBuf, "\tcld\n");
            else goto ps_error;
            break;

        case '-':
            if(!strcmp(Stat, "-.;")) {              // Break by LOOP
                if(true_blk < 0) goto ps_noblk;
                soutput(SendBuf, "\tloop\t?End%04X\n", BlkStack[true_blk]);
            } else if(!strcmp(Stat, "-==;")) {      // Break by LOOPZ
                if(true_blk < 0) goto ps_noblk;
                soutput(SendBuf, "\tloopz\t?End%04X\n", BlkStack[true_blk]);
            } else if(!strcmp(Stat, "-<>;")) {      // Break by LOOPNZ
                if(true_blk < 0) goto ps_noblk;
                soutput(SendBuf, "\tloopnz\t?End%04X\n", BlkStack[true_blk]);
            }
            else if(!strcmp(Stat, "--A;"))          goto ps_parsejcc0;
            else if(!strcmp(Stat, "-+A;"))          goto ps_parsejcc0;
            else if(!strcmp(Stat, "--;"))           goto ps_parsebrk0;
            else if(!strcmp(Stat, "-+;"))           goto ps_parsebrk0;
            else if(!strcmp(Stat, "-;"))            soutput(SendBuf, "\tstd\n");
            else if(!strcmp(Stat, "-A;"))           soutput(SendBuf, "\tneg\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "-.A;"))          soutput(SendBuf, "\tloop\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "-==A;"))         soutput(SendBuf, "\tloopz\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "-<>A;"))         soutput(SendBuf, "\tloopnz\t%s\n", Strs[0]);
            else goto ps_error;
            break;

        case '.':
            if(!strcmp(Stat, ".A;") || !strcmp(Stat, "..A;")) {
                if(Strs[0][1] == 0 && isdigit(Strs[0][0])) {
                    j = Strs[0][0] - '0';           // break multi-level
                    for(i = 0; i < j; i++) {
                        if(--true_blk < 0) goto ps_noblk;
                        if(BlkType[true_blk] == 0) true_blk--;
                    }
                    soutput(SendBuf, "\tjmp\t%s?End%04X\n",
                        Stat[1] == '.' ? "" : "short ", BlkStack[true_blk]);
                } else {
                    soutput(SendBuf, "\tjmp\t%s%s\n",
                        Stat[1] == '.' ? "" : "short ", Strs[0]);
                }
            } else if(!strcmp(Stat, ".;") || !strcmp(Stat, "..;")) {
                if(true_blk < 0) goto ps_noblk;     // break out of block
                soutput(SendBuf, "\tjmp\t%s?End%04X\n",
                    Stat[1] == '.' ? "" : "short ", BlkStack[true_blk]);
            }
            else if(!strcmp(Stat, ".=;"))           soutput(SendBuf, "\tret\n");
            else if(!strcmp(Stat, ".=A;"))          soutput(SendBuf, "\tret\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "...;"))          soutput(SendBuf, "\twait\n");
            else if(!strcmp(Stat, "....;"))         soutput(SendBuf, "\thlt\n");
            else if(strchr(Stat, 'A'))
                goto ps_parsejcc0;
            else goto ps_parsebrk0;
            break;

        case '/':
                 if(!strcmp(Stat, "//A;"))          soutput(SendBuf, "\tdiv\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "/A;"))           soutput(SendBuf, "\tidiv\t%s\n", Strs[0]);
            else goto ps_error;
            break;

        case '<':
                 if(!strcmp(Stat, "<<A;"))          goto ps_parsejcc0;
            else if(!strcmp(Stat, "<<=A;"))         goto ps_parsejcc0;
            else if(!strcmp(Stat, "<A;"))           goto ps_parsejcc0;
            else if(!strcmp(Stat, "<=A;"))          goto ps_parsejcc0;
            else if(!strcmp(Stat, "<>A;"))          goto ps_parsejcc0;
            else if(!strcmp(Stat, "<<;"))           goto ps_parsebrk0;
            else if(!strcmp(Stat, "<<=;"))          goto ps_parsebrk0;
            else if(!strcmp(Stat, "<;"))            goto ps_parsebrk0;
            else if(!strcmp(Stat, "<=;"))           goto ps_parsebrk0;
            else if(!strcmp(Stat, "<>;"))           goto ps_parsebrk0;
            else if(!strcmp(Stat, "<>=*;"))         soutput(SendBuf, "\trep\tlodsb\n");
            else if(!strcmp(Stat, "<>=**;"))        soutput(SendBuf, "\trep\tlodsw\n");
            else if(!strcmp(Stat, "<>=****;"))      soutput(SendBuf, "\trep\tlodsd\n");
            else if(!strcmp(Stat, "<>*=;"))         soutput(SendBuf, "\trep\tstosb\n");
            else if(!strcmp(Stat, "<>**=;"))        soutput(SendBuf, "\trep\tstosw\n");
            else if(!strcmp(Stat, "<>****=;"))      soutput(SendBuf, "\trep\tstosd\n");
            else if(!strcmp(Stat, "<>*=*;"))        soutput(SendBuf, "\trep\tmovsb\n");
            else if(!strcmp(Stat, "<>**=**;"))      soutput(SendBuf, "\trep\tmovsw\n");
            else if(!strcmp(Stat, "<>****=****;"))  soutput(SendBuf, "\trep\tmovsd\n");
            else if(!strcmp(Stat, "<>*-?"))         soutput(SendBuf, "\trepne\tscasb\n");
            else if(!strcmp(Stat, "<>**-?"))        soutput(SendBuf, "\trepne\tscasw\n");
            else if(!strcmp(Stat, "<>****-?"))      soutput(SendBuf, "\trepne\tscasd\n");
            else if(!strcmp(Stat, "<>*-*?"))        soutput(SendBuf, "\trepne\tcmpsb\n");
            else if(!strcmp(Stat, "<>**-**?"))      soutput(SendBuf, "\trepne\tcmpsw\n");
            else if(!strcmp(Stat, "<>****-****?"))  soutput(SendBuf, "\trepne\tcmpsd\n");
            else if(!strcmp(Stat, "<>*=@;"))        soutput(SendBuf, "\trep\tinsb\n");
            else if(!strcmp(Stat, "<>**=@@;"))      soutput(SendBuf, "\trep\tinsw\n");
            else if(!strcmp(Stat, "<>****=@@@@;"))  soutput(SendBuf, "\trep\tinsd\n");
            else if(!strcmp(Stat, "<>**=@;"))       soutput(SendBuf, "\trep\tinsw\n");
            else if(!strcmp(Stat, "<>****=@;"))     soutput(SendBuf, "\trep\tinsd\n");
            else if(!strcmp(Stat, "<>@=*;"))        soutput(SendBuf, "\trep\toutsb\n");
            else if(!strcmp(Stat, "<>@=**;"))       soutput(SendBuf, "\trep\toutsw\n");
            else if(!strcmp(Stat, "<>@=****;"))     soutput(SendBuf, "\trep\toutsd\n");
            else if(!strcmp(Stat, "<>@@=**;"))      soutput(SendBuf, "\trep\toutsw\n");
            else if(!strcmp(Stat, "<>@@@@=****;"))  soutput(SendBuf, "\trep\toutsd\n");
            else if(!strcmp(Stat, "<>=*A;"))        soutput(SendBuf, "\trep\tlods %s\n", Strs[0]);
            else if(!strcmp(Stat, "<>*A=;"))        soutput(SendBuf, "\trep\tstos %s\n", Strs[0]);
            else if(!strcmp(Stat, "<>*A=*A;"))      soutput(SendBuf, "\trep\tmovs %s,%s\n", Strs[0], Strs[1]);
            else if(!strcmp(Stat, "<>*A-?"))        soutput(SendBuf, "\trepne\tscas %s\n", Strs[0]);
            else if(!strcmp(Stat, "<>*A-*A?"))      soutput(SendBuf, "\trepne\tcmps %s,%s\n", Strs[0], Strs[1]);
            else if(!strcmp(Stat, "<>*A=@;"))       soutput(SendBuf, "\trep\tins  %s\n", Strs[0]);
            else if(!strcmp(Stat, "<>@=*A;"))       soutput(SendBuf, "\trep\touts %s\n", Strs[0]);
            else goto ps_error;
            break;

        case '=':
            if(!memcmp(Stat, "=A", 2)) {           // PUSH sequence
                i = 0; p = Stat;
                while(!memcmp(p, "=A", 2)) {
                    soutput(SendBuf, "\tpush\t%s\n", Strs[i]);
                    p += 2; i++;
                };
                if(*p != ';') goto ps_error;
            }
            else if(!strcmp(Stat, "==A;"))          goto ps_parsejcc0;
            else if(!strcmp(Stat, "=<<A;"))         goto ps_parsejcc0;
            else if(!strcmp(Stat, "=>>A;"))         goto ps_parsejcc0;
            else if(!strcmp(Stat, "=<A;"))          goto ps_parsejcc0;
            else if(!strcmp(Stat, "=>A;"))          goto ps_parsejcc0;
            else if(!strcmp(Stat, "==;"))           goto ps_parsebrk0;
            else if(!strcmp(Stat, "=<<;"))          goto ps_parsebrk0;
            else if(!strcmp(Stat, "=<;"))           goto ps_parsebrk0;
            else if(!strcmp(Stat, "=>>;"))          goto ps_parsebrk0;
            else if(!strcmp(Stat, "=>;"))           goto ps_parsebrk0;
            else if(!strcmp(Stat, "=.A;"))          soutput(SendBuf, "\tcall\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "=??;"))          soutput(SendBuf, "\tpushf\n");
            else if(!strcmp(Stat, "=????;"))        soutput(SendBuf, "\tpushfd\n");
            else if(!strcmp(Stat, "=?;"))           soutput(SendBuf, "\tlahf\n");
            else if(!strcmp(Stat, "=;"))            soutput(SendBuf, "\tdb\t0D6h\n");
            else if(!strcmp(Stat, "=+A;"))          soutput(SendBuf, "\tenter\t%s,0\n", Strs[0]);
            else if(!strcmp(Stat, "=-;"))           soutput(SendBuf, "\tleave\n");
            else if(!strcmp(Stat, "=%;"))           soutput(SendBuf, "\tpusha\n");
            else if(!strcmp(Stat, "=@;"))           soutput(SendBuf, "\tin\tal,dx\n");
            else if(!strcmp(Stat, "=@@;"))          soutput(SendBuf, "\tin\tax,dx\n");
            else if(!strcmp(Stat, "=@@@@;"))        soutput(SendBuf, "\tin\teax,dx\n");
            else if(!strcmp(Stat, "=@A;"))          soutput(SendBuf, "\tin\tal,%s\n", Strs[0]);
            else if(!strcmp(Stat, "=@@A;"))         soutput(SendBuf, "\tin\tax,%s\n", Strs[0]);
            else if(!strcmp(Stat, "=@@@@A;"))       soutput(SendBuf, "\tin\teax,%s\n", Strs[0]);
            else if(!strcmp(Stat, "=*;"))           soutput(SendBuf, "\tlodsb\n");
            else if(!strcmp(Stat, "=**;"))          soutput(SendBuf, "\tlodsw\n");
            else if(!strcmp(Stat, "=****;"))        soutput(SendBuf, "\tlodsd\n");
            else if(!strcmp(Stat, "=*A;"))          soutput(SendBuf, "\tlods\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "===*;"))         soutput(SendBuf, "\trep\tlodsb\n");
            else if(!strcmp(Stat, "===**;"))        soutput(SendBuf, "\trep\tlodsw\n");
            else if(!strcmp(Stat, "===****;"))      soutput(SendBuf, "\trep\tlodsd\n");
            else if(!strcmp(Stat, "==*=;"))         soutput(SendBuf, "\trep\tstosb\n");
            else if(!strcmp(Stat, "==**=;"))        soutput(SendBuf, "\trep\tstosw\n");
            else if(!strcmp(Stat, "==****=;"))      soutput(SendBuf, "\trep\tstosd\n");
            else if(!strcmp(Stat, "==*=*;"))        soutput(SendBuf, "\trep\tmovsb\n");
            else if(!strcmp(Stat, "==**=**;"))      soutput(SendBuf, "\trep\tmovsw\n");
            else if(!strcmp(Stat, "==****=****;"))  soutput(SendBuf, "\trep\tmovsd\n");
            else if(!strcmp(Stat, "==*-?"))         soutput(SendBuf, "\trepe\tscasb\n");
            else if(!strcmp(Stat, "==**-?"))        soutput(SendBuf, "\trepe\tscasw\n");
            else if(!strcmp(Stat, "==****-?"))      soutput(SendBuf, "\trepe\tscasd\n");
            else if(!strcmp(Stat, "==*-*?"))        soutput(SendBuf, "\trepe\tcmpsb\n");
            else if(!strcmp(Stat, "==**-**?"))      soutput(SendBuf, "\trepe\tcmpsw\n");
            else if(!strcmp(Stat, "==****-****?"))  soutput(SendBuf, "\trepe\tcmpsd\n");
            else if(!strcmp(Stat, "==*=@;"))        soutput(SendBuf, "\trep\tinsb\n");
            else if(!strcmp(Stat, "==**=@;"))       soutput(SendBuf, "\trep\tinsw\n");
            else if(!strcmp(Stat, "==****=@;"))     soutput(SendBuf, "\trep\tinsd\n");
            else if(!strcmp(Stat, "==**=@@;"))      soutput(SendBuf, "\trep\tinsw\n");
            else if(!strcmp(Stat, "==****=@@@@;"))  soutput(SendBuf, "\trep\tinsd\n");
            else if(!strcmp(Stat, "==@=*;"))        soutput(SendBuf, "\trep\toutsb\n");
            else if(!strcmp(Stat, "==@=**;"))       soutput(SendBuf, "\trep\toutsw\n");
            else if(!strcmp(Stat, "==@=****;"))     soutput(SendBuf, "\trep\toutsd\n");
            else if(!strcmp(Stat, "==@@=**;"))      soutput(SendBuf, "\trep\toutsw\n");
            else if(!strcmp(Stat, "==@@@@=****;"))  soutput(SendBuf, "\trep\toutsd\n");
            else if(!strcmp(Stat, "===*A;"))        soutput(SendBuf, "\trep\tlods %s\n", Strs[0]);
            else if(!strcmp(Stat, "==*A=;"))        soutput(SendBuf, "\trep\tstos %s\n", Strs[0]);
            else if(!strcmp(Stat, "==*A=*A;"))      soutput(SendBuf, "\trep\tmovs %s,%s\n", Strs[0], Strs[1]);
            else if(!strcmp(Stat, "==*A-?"))        soutput(SendBuf, "\trepe\tscas %s\n", Strs[0]);
            else if(!strcmp(Stat, "==*A-*A?"))      soutput(SendBuf, "\trepe\tcmps %s,%s\n", Strs[0], Strs[1]);
            else if(!strcmp(Stat, "==*A=@;"))       soutput(SendBuf, "\trep\tins  %s\n", Strs[0]);
            else if(!strcmp(Stat, "==@=*A;"))       soutput(SendBuf, "\trep\touts %s\n", Strs[0]);
            else goto ps_error;
            break;

        case '>':
                 if(!strcmp(Stat, ">>A;"))          goto ps_parsejcc0;
            else if(!strcmp(Stat, ">>=A;"))         goto ps_parsejcc0;
            else if(!strcmp(Stat, ">A;"))           goto ps_parsejcc0;
            else if(!strcmp(Stat, ">=A;"))          goto ps_parsejcc0;
            else if(!strcmp(Stat, ">>;"))           goto ps_parsebrk0;
            else if(!strcmp(Stat, ">>=;"))          goto ps_parsebrk0;
            else if(!strcmp(Stat, ">;"))            goto ps_parsebrk0;
            else if(!strcmp(Stat, ">=;"))           goto ps_parsebrk0;
            else if(!strcmp(Stat, "><;"))           soutput(SendBuf, "\txlatb\n");
            else if(!strcmp(Stat, "><A;"))          soutput(SendBuf, "\txlat\t%s\n", Strs[0]);
            else goto ps_error;
            break;

        case '?':
            if(!strcmp(Stat, "?==;")) {             // Break on CXZ
                if(true_blk < 0) goto ps_noblk;
                soutput(SendBuf, "\tjcxz\t?End%04X\n", BlkStack[true_blk]);
            }
            else if(!strcmp(Stat, "?=;"))           soutput(SendBuf, "\tsahf\n", Strs[1]);
            else if(!strcmp(Stat, "?==A;"))         soutput(SendBuf, "\tjcxz\t%s\n", Strs[0]);
            else if(!strcmp(Stat, "??=;"))          soutput(SendBuf, "\tpopf\n");
            else if(!strcmp(Stat, "????=;"))        soutput(SendBuf, "\tpopfd\n");
            else goto ps_error;
            break;

        case '@':
                 if(!strcmp(Stat, "@=;"))           soutput(SendBuf, "\tout\tdx,al\n");
            else if(!strcmp(Stat, "@@=;"))          soutput(SendBuf, "\tout\tdx,ax\n");
            else if(!strcmp(Stat, "@@@@=;"))        soutput(SendBuf, "\tout\tdx,eax\n");
            else if(!strcmp(Stat, "@A=;"))          soutput(SendBuf, "\tout\t%s,al\n", Strs[0]);
            else if(!strcmp(Stat, "@@A=;"))         soutput(SendBuf, "\tout\t%s,ax\n", Strs[0]);
            else if(!strcmp(Stat, "@@@@A=;"))       soutput(SendBuf, "\tout\t%s,eax\n", Strs[0]);
            else if(!strcmp(Stat, "@=*;"))          soutput(SendBuf, "\toutsb\n");
            else if(!strcmp(Stat, "@=**;"))         soutput(SendBuf, "\toutsw\n");
            else if(!strcmp(Stat, "@=****;"))       soutput(SendBuf, "\toutsd\n");
            else if(!strcmp(Stat, "@@=**;"))        soutput(SendBuf, "\toutsw\n");
            else if(!strcmp(Stat, "@@@@=****;"))    soutput(SendBuf, "\toutsd\n");
            else if(!strcmp(Stat, "@=*A;"))         soutput(SendBuf, "\touts\t%s\n", Strs[0]);
            else goto ps_error;
            break;

        case '^':
                 if(!strcmp(Stat, "^;"))            soutput(SendBuf, "\tcmc\n");
            else if(!strcmp(Stat, "^A;"))           soutput(SendBuf, "\tnot\t%s\n", Strs[0]);
            else goto ps_error;
            break;

        case '|':
                 if(!strcmp(Stat, "||A;"))          goto ps_parsejcc0;
            else if(!strcmp(Stat, "||;"))           goto ps_parsebrk0;
            else if(!strcmp(Stat, "|;"))            soutput(SendBuf, "\tstc\n");
            else goto ps_error;
            break;

        case ';':
            break;

        default:
            goto ps_error;
    }

////////////////////////////////////////////// OUTPUT SEQUENCE

ps_output:
    fputs(SendBuf, OutFile);                // send output buffer
    if(to_follow)
        fputs(FollowBuf, OutFile);          // send follow codes (if any)
    return 1;

////////////////////////////////////////////// CONDITIONAL JUMP

ps_parsejcc0:
    if(!FindCond(Stat, cond1))              // find the condition code
        goto ps_error;
    if(Strs[0][1] == 0 && isdigit(Strs[0][0])) {
        j = Strs[0][0] - '0';               // break, multi-level
        for(i = 0; i < j; i++) {
            if(--true_blk < 0) goto ps_noblk;
            if(BlkType[true_blk] == 0) true_blk--;
        }
        sprintf(ibuf, "?End%04X", BlkStack[true_blk]);
    } else strcpy(ibuf, Strs[0]);
    if(Stat[0] == '.') {
        ParseCond(cond1, sbuf, 1);
        soutput(SendBuf, "\tj%s\t?End%04X\n", sbuf, NextBlk);
        soutput(SendBuf, "\tjmp\t%s\n", ibuf);
        soutput(SendBuf, "?End%04X:\n", NextBlk++);
    } else {
        ParseCond(cond1, sbuf, 0);
        soutput(SendBuf, "\tj%s\t%s\n", sbuf, ibuf);
    }
    goto ps_output;

////////////////////////////////////////////// CONDITIONAL BREAK

ps_parsebrk0:
    if(true_blk < 0) goto ps_noblk;
    FindCond(Stat, cond1);
    if(Stat[0] == '.') {
        ParseCond(cond1, sbuf, 1);
        soutput(SendBuf, "\tj%s\t?End%04X\n", sbuf, NextBlk);
        soutput(SendBuf, "\tjmp\t?End%04X\n", BlkStack[true_blk]);
        soutput(SendBuf, "?End%04X:\n", NextBlk++);
    } else {
        ParseCond(cond1, sbuf, 0);
        soutput(SendBuf, "\tj%s\t?End%04X\n", sbuf, BlkStack[true_blk]);
    }
    goto ps_output;

////////////////////////////////////////////// ERROR CONDITIONS

ps_error:
    sprintf(ErrorBuf, "syntax error at or near line %ld", LineCtr);
    xerror(2);

ps_nesterr:
    sprintf(ErrorBuf, "nesting too deep at or near line %ld", LineCtr);
    xerror(5);

ps_blkerr:
    sprintf(ErrorBuf, "block syntax error at or near line %ld", LineCtr);
    xerror(6);

ps_noblk:
    sprintf(ErrorBuf, "block does not exist at or near line %ld", LineCtr);
    xerror(7);

////////////////////////////////////////////// PASS-THROUGH CODE

ps_passthru:
    p = Stat; i = 0;                        // p = pointer, i = string ctr.
    soutput(SendBuf, "\t");
    if(*p == 0) return 1;                   // empty statement?
    while(*(p+1) != 0) {                    // send each piece
        if(*p == 'A') soutput(SendBuf, "%s ", Strs[i++]);
        else soutput(SendBuf, "%c ", *p);
        p++;
    }
    fprintf(OutFile, "%s\n", SendBuf);      // send output buffer
    return 1;
}

/********************************************************************/
/* Parse pointer bumping (if any)                                   */
/********************************************************************/

int ParseBumping(void)
{
    int i, j, n, d, l, r = 0;
    char *s, *p, a[128];

    l = strlen(Stat);                               // get string length
    for(i = n = 0; i < l; i++)                      // count the strings
        if(Stat[i] == 'A') n++;

    for(n--; n >= 0; n--) {
        s = Strs[n];
        do {
            d = 0;
            if((p = strchr(s, '[')) != NULL) {      // look for '[+' or '[-'
                 l = strlen(s);
                 if(*(p+1) == '+' || *(p+1) == '-') {
                    i = (p+2) - s;                  // extract alphanumeric string
                    for(; i < l; i++) if(isxalpha(s[i])) break;
                    for(j = 0; i+j < l; j++) {
                        if(!isxalpha(s[i+j])) break;
                        a[j] = s[i+j];
                    }
                    a[j] = 0;                       // finish up
                    soutput(SendBuf, "\t%s\t%s\n",
                        *(p+1) == '+' ? "inc" : "dec", a);
                    memmove(p+1, p+2, 126 - (p - s)); d = 1;
                }
            }
            if((p = strchr(s+1, ']')) != NULL) {    // look for '+]' or '-]'
                l = strlen(s);
                if(*(p-1) == '+' || *(p-1) == '-') {
                    i = (p-2) - s;                  // extract alpha string
                    for(; i >= 0; i--) if(isxalpha(s[i])) break;
                    a[0] = 0;
                    for(; i >= 0; i--) {
                        if(!isxalpha(s[i])) break;
                        memmove(a+1, a, 127);
                        a[0] = s[i];
                    }
                    soutput(FollowBuf, "\t%s\t%s\n", // finish up
                        *(p-1) == '+' ? "inc" : "dec", a);
                    memmove(p-1, p, 128 - (p - s)); d = r = 1;
                }
            }
        } while(d);
    }

    return(r);
}

/********************************************************************/
/* Parse a conditional string                                       */
/********************************************************************/

int ParseCond(char *in, char *out, int flip)
{
    static char *outs[16] = {               // output strings
        "o", "no", "b", "ae", "z", "nz", "be", "a",
        "s", "ns", "pe", "po", "l", "ge", "le", "g" };
    static char *ins[20] = {                // input strings
        "+-", "-+", "<<", ">>=", "=>>", "==", "<>", "<<=", "=<<", ">>",
        "--", "++", "&&", "||", "<", ">=", "=>", "<=", "=<", ">" };
    static int inv[20] = {                  // string values
        0, 1, 2, 3, 3, 4, 5, 6, 6, 7, 8,
        9, 10, 11, 12, 13, 13, 14, 14, 15 };

    int i, n = -1;

    for(i = 0; i < 20; i++)                 // find the string
        if(!strcmp(in, ins[i]))
            n = inv[i];
    if(n == -1) {                           // not a condition?
        *out = 0;                           // return a blank string
        return 0;
    }
    if(flip) n ^= 1;                        // opposite condition if needed
    strcpy(out, outs[n]);                   // return the condition string
    return 1;
}

/********************************************************************/
/* Find a conditional in a statement                                */
/********************************************************************/

int FindCond(char *in, char *out)
{
    static char *conds[20] = {                  // List of conditions
        ">>=", "=>>", "<<=", "=<<", ">=", "=>", "<=", "=<", "+-", "-+",
        "--", "++", "<>", "<<", ">>", "<", ">", "==", "&&", "||" };

    static unsigned char cond_len[20] = {       // Length of each condition
        3,3,3,3,2,2,2,2,2,2, 2,2,2,2,2,1,1,2,2,2 };

    int i, j, l = strlen(in), m;

    for(i = 0; i < l; i++) {
        for(j = 0; j < 20; j++) {
            m = cond_len[j];                    // get length of string
            if(!memcmp(in + i, conds[j], m)) {  // found a condition?
                strcpy(out, conds[j]);          // copy it into the output buffer
                memmove(in + i + 1, in + i + m, l - i - m + 1);
                in[i] = 'C';                    // replace it by a 'C' in the main string
                return 1;
            }
        }
    }

    out[0] = 0;                                 // not found, return a blank string
    return 0;
}

/********************************************************************/
/* Get one statement                                                */
/********************************************************************/

int GetStatement(void)
{
    static char buf[300];
    char *p = Stat, oc = -1, c = -1;
    int stn = 0;

    do {
        if(Stat[0] != '#') oc = c;              // oc = prev. char unless FPU instruction
        if(!GetToken(buf, p - Stat)) return 0;  // get a token
        if(isxalpha(*buf) || buf[1] != 0) {     // if alphanumeric or string,
            strcpy(Strs[stn++], buf);           // then add it to string the list
            *p++ = c = 'A';                     // and code it as an 'A'
        } else *p++ = c = *buf;                 // otherwise, code it as itself
        if(p - Stat > 60 || stn > 30) {         // out of space?
            sprintf(ErrorBuf, "statement too big at or near line %d", LineCtr);
            xerror(3);
        }
    } while(c != ';' && c != '{' &&             // terminators are ';' and '{', sometines '?'.
            (c != '?' || !strchr("A-*", oc)));  // '?' is terminator only if after 'A', '-', or '*'.
    *p++ = 0;
    return 1;
}

/********************************************************************/
/* Init token parsing                                               */
/********************************************************************/

void InitToken(void)
{
    GetLine(LineBuf);
    LinePos = 0;
}

/********************************************************************/
/* Return one token                                                 */
/********************************************************************/

int GetToken(char *buf, int flg)
{
    int is_bracket, level, is_string = 0;
    int c, i, p = 0, is_alpha = 0;
    char deli[5] = "([\'\"";

    if(!flg) deli[2] = 0;                       // strings OK?

    while(1) {
        c = LineBuf[LinePos++];                 // get char
        if(c == 0) {                            // end of line?
            if(!GetLine(LineBuf)) return 0;     // get line
            LinePos = 0;                        // reset line pos
        } else if(isspace(c)) {                 // skip spaces
        } else if(isxalpha(c) || strchr(deli, c)) {

            is_string = 1;                      // set is_string flag

            if(flg && (c == '\'' || c == '\"')) {
                i = c;                          // handle quoted strings
                do {
                    if(i == 0) goto gt_strerr;  // end of line?
                    buf[p++] = i;               // add char to string
                } while((i = LineBuf[LinePos++]) != c);
                buf[p++] = i; continue;         // add last char, continue
            }

            level = !isxalpha(c);               // expression/alphanumeric string

            if(c == '(' && is_alpha) {          // opening parenthesis needs space
                buf[p++] = ' ';                 // if last one was alpha
            }
            if(c == '[') {                      // handle opening bracket
                is_bracket = 1; buf[p++] = c;
            } else is_bracket = 0;

            if(isxalpha(c)) {                   // need first char if alpha string
                if(is_alpha) buf[p++] = ' ';    // last one was alpha, separate with space
                is_alpha = 1; buf[p++] = c;
            } else is_alpha = 0;

            while(1) {                          // string handling loop
                c = LineBuf[LinePos++];             // get char
                if(isspace(c) || c == 0) {          // process white space:
                    if(level == 0) break;           // end of alpha string
                    buf[p++] = ' ';                 // encode as a single space
                    do {                            // white space loop
                        if(c == 0) {                // process newlines
                            if(!GetLine(LineBuf)) return 0;
                            LinePos = 0;
                        }
                        c = LineBuf[LinePos++];     // get next char
                    } while(isspace(c) || c == 0);  // loop while whitespace
                }
                buf[p++] = c;                       // add character to buffer

                if(c == '(') { ++level; continue; } // opening parenthesis
                if(c == ')') if(--level == 0) {     // closing parenthesis
                    if(is_bracket) goto gt_error;   // should be bracket, generate error
                    if(!is_alpha) p--;              // if it didn't begin as alpha, remove parenthesis
                    is_alpha = 1; break;            // need space in all cases, break
                }

                if(c == '[' && level == 0) {        // process opening bracket
                   is_bracket = level = 1;
                   continue;
                }
                if(c == ']' && level == 1 &&        // process ending bracket
                   is_bracket) break;

                if(c == '\'' || c == '\"') {        // quoted strings
                    while((i = LineBuf[LinePos++]) != c) {
                        if(i == 0) goto gt_strerr;  // end of line?
                        buf[p++] = i;               // add char to string
                    }
                    buf[p++] = i; continue;         // add last char, continue
                }

                if(!isxalpha(c) && level == 0) {    // end of alpha string, recycle last char
                    p--; LinePos--; break;
                }
            }
        } else {                                // special char
            if(is_string) LinePos--;            // terminates a string
            else buf[p++] = c;                  // not string, add char
            buf[p++] = 0;                       // add terminating null
            return 1;                           // break
        }
    }

gt_error:                                       // error in expression
    sprintf(ErrorBuf, "error in expression at or near line %ld", LineCtr);
    xerror(3);

gt_strerr:                                      // end of line in quoted string
    sprintf(ErrorBuf, "unterminated quoted string at or near line %ld", LineCtr);
    xerror(4);
    return 0;                                   // to fix compiler warning
}

/********************************************************************/
/* Return the next token without removing it from the stream        */
/********************************************************************/

int PeekToken(char *p)
{
    int c, lp = LinePos;

    while(1) {
        c = LineBuf[lp++];                      // get char
        if(c == 0) {                            // end of line?
            if(!GetLine(LineBuf)) return 0;     // get line
            LinePos = lp = 0;                   // reset line pos
            continue;
        } else if(isspace(c)) {                 // skip spaces
            continue;
        } else {
            if(isxalpha(c) || strchr("([", c))  // identifier, expression,
                *p = 'A';                       // or address = return an 'A'
            else *p = c;                        // otherwise, return the char
            return 1;
        }
    }
}

/********************************************************************/
/* Get line with full pass-through, stripping comments, etc.        */
/********************************************************************/

int GetLine(char *buf)
{
    int i;

    do {
        if(!ReadLine(buf)) return 0;                    // read a line
        if(!isspace(buf[0])) {
            i = 0;                                      // statement starts line, label, etc.
            if(strchr(buf, ':')) {                      // if there's a ':', then
                while(isalnum(buf[i]) ||                // check for a label
                      strchr("$_", buf[i])) i++;
                if(buf[i] == ':') {                     // If a label, then pass it through:
                    i = 0;
                    while(1) {
                        fputc(buf[i], OutFile);         // output one char
                        if(buf[i] == ':') break;        // char is ':', break
                        i++;
                    }
                }
            }
            if(buf[i] != ':') {                         // if no label, then
                i = 0;
                while(buf[i] != ';') {                  // while no semicolon,
                    if(buf[i] == 0) {                   // if end of line, then
                        if(!ReadLine(buf)) return 0;    // read a line, reset the counter
                        i = 0; continue;                // and continue
                    }
                    fputc(buf[i++], OutFile);           // output the char
                }
            }
            fputs("\n", OutFile);                       // output newline
            memmove(buf, buf + i + 1, 300 - i - 1);     // shift over buffer
        }
    } while(IsEmpty(buf));
    return 1;
}

/********************************************************************/
/* Read a line, passing delimited lines                             */
/********************************************************************/

int ReadLine(char *buf)
{
    char *p;

    while(1) {
        if(!fgets(buf, 300, InFile)) return 0;          // read one line
        if(!(++LineCtr & 0x3F))                         // increment counter, put count every 64 lines
            fprintf(stderr, "\rlines in: %06ld", LineCtr);
        if(buf[0] == '!') {                             // is it a pass-through line?
            fputs(buf + 1, OutFile);                    // if so, then send it, and loop back for another
            continue;                                   // make sure string is empty...
        }
        if((p = strchr(buf, 0x0D)) != NULL) *p = 0;     // strip off CR and/or LF at the end
        if((p = strchr(buf, 0x0A)) != NULL) *p = 0;
        StripComments(buf);                             // strip off comments (if any)
        if(!IsEmpty(buf)) return 1;
    }
}

/********************************************************************/
/* Strip comments (and trailing spaces) from end of line            */
/********************************************************************/

void StripComments(char *buf)
{
    char c, e = 0;
    int i = -1;

    while((c = buf[++i]) != 0) {            // while not null, if in a string ignore
        if(e) {                             // everything except the delimiter char;
            if(c == e) e = 0;               // otherwise cut the string if '\' found.
        } else {
            if(c == '\'' || c == '\"') {
                e = c;
            } else if(c == '\\') {
                buf[i] = 0;
                break;
            }
        }
    }
    i = strlen(buf) - 1;                    // remove trailing spaces
    while(isspace(buf[i])) buf[i--] = 0;
}

/********************************************************************/
/* Check whether line is empty                                      */
/********************************************************************/

int IsEmpty(char *buf)
{
    int i = 0;

    while(buf[i] != 0) {
        if(!isspace(buf[i++]))
            return 0;
    }
    return 1;
}

/********************************************************************/
/* Error handling                                                   */
/********************************************************************/

void xerror(int en)
{
    fprintf(stderr, "\nerror %02x: %s\n\n", en, ErrorBuf);
    if(InFile != NULL) fclose(InFile);
    if(OutFile != NULL) fclose(OutFile);
    exit(en);
}

/********************************************************************/
/* String printf + concatenation                                    */
/********************************************************************/

void soutput(char *s, char *fmt, ...)
{
    va_list ap;

    va_start(ap, fmt);
    vsprintf(s + strlen(s), fmt, ap);
    va_end(ap);
}
