#include "stdio.h"
#include "assm.d1"
#include "assm.d2"

extern  int optab[];
extern  int step[];

/* translate source line to machine language */

assemble()
{
    int flg;
    int i;      /* prlnbuf pointer */

    if ((prlnbuf[SFIELD] == ';') | (prlnbuf[SFIELD] == 0)) {
        if (pass == LAST_PASS)
            println();
        return;
    }
    lablptr = -1;
    i = SFIELD;
    udtype = UNDEF;
    if (colsym(&i) != 0 && (lablptr = stlook()) == -1)
        return;
    while (prlnbuf[++i] == ' ');    /* find first non-space */
    if ((flg = oplook(&i)) < 0) {   /* collect operation code */
        labldef(loccnt);
        if (flg == -1)
            error("Invalid operation code");
        if ((flg == -2) && (pass == LAST_PASS)) {
            if (lablptr != -1)
                loadlc(loccnt, 1, 0);
            println();
        }
        return;
    }
    if (opflg == PSEUDO)
        pseudo(&i);
    else if (labldef(loccnt) == -1)
        return;
    else {
        if (opflg == CLASS1)
            class1();
        else if (opflg == CLASS2)
            class2(&i);
        else class3(&i);
    }
}

/****************************************************************************/

/* printline prints the contents of prlnbuf */

println()
{
    if (lflag > 0)
        fprintf(stdout, "%s\n", prlnbuf);
}

/* colsym() collects a symbol from prlnbuf into symbol[],
 *    leaves prlnbuf pointer at first invalid symbol character,
 *    returns 0 if no symbol collected
 */

colsym(ip)
    int *ip;
{
    int valid;
    int i;
    char    ch;

    valid = 1;
    i = 0;
    while (valid == 1) {
        ch = prlnbuf[*ip];
        if (ch == '_' || ch == '.');
        else if (ch >= 'a' && ch <= 'z');
        else if (ch >= 'A' && ch <= 'Z');
        else if (i >= 1 && ch >= '0' && ch <= '9');
        else if (i == 1 && ch == '=');
        else valid = 0;
        if (valid == 1) {
            if (i < SBOLSZ - 1)
                symbol[++i] = ch;
            (*ip)++;
        }
    }
    if (i == 1) {
        switch (symbol[1]) {
        case 'A': case 'a':
        case 'X': case 'x':
        case 'Y': case 'y':
            error("Symbol is reserved (A, X or Y)");
            i = 0;
        }
    }
    symbol[0] = i;
    return(i);
}

/* symbol table lookup
 *  if found, return pointer to symbol
 *  else, install symbol as undefined, and return pointer
 */

stlook()
{
    int found;
    int hptr;
    int j;
    int nptr;
    int pptr;
    int ptr;

    hptr = 0;
    for (j = 0; j < symbol[0]; j++)
        hptr += symbol[j];
    hptr %= 128;
    ptr = hash_tbl[hptr];
    if (ptr == -1) {        /* no entry for this link */
        hash_tbl[hptr] = nxt_free;
        return(stinstal());
    }
    while (symtab[ptr] != 0) {  /* 0 count = end of table */
        found = 1;
        for (j = 0; j <= symbol[0]; j++) {
            if (symbol[j] != symtab[ptr + j]) {
                found = 0;
                pptr = ptr + symtab[ptr] + 4;
                nptr = (symtab[pptr + 1] << 8) + (symtab[pptr] & 0xff);
                nptr &= 0xffff;
                if (nptr == 0) {
                    symtab[ptr + symtab[ptr] + 4] = nxt_free & 0xff;
                    symtab[ptr + symtab[ptr] + 5] = (nxt_free >> 8) & 0xff;
                    return(stinstal());
                }
                ptr = nptr;
                break;
            }
        }
        if (found == 1)
            return(ptr);
    }
    error("Symbol not found");
    return(-1);
}

/*  instal symbol into symtab
 */
stinstal()
{
register    int j;
register    int ptr1;
register    int ptr2;

    ptr1 = ptr2 = nxt_free;
    if ((ptr1 + symbol[0] + 6) >= STABSZ) {
        error("Symbol table full");
        return(-1);
    }
    for (j = 0; j <= symbol[0]; j++)
        symtab[ptr1++] = symbol[j];
    symtab[ptr1] = udtype;
    nxt_free = ptr1 + 5;
    return(ptr2);
}

/* operation code table lookup
 *  if found, return pointer to symbol,
 *  else, return -1
 */

oplook(ip)
   int  *ip;
{
register    char    ch;
register    int i;
register    int j;
    int k;
    int temp[2];

    i = j = 0;
    temp[0] = temp[1] = 0;
    while((ch=prlnbuf[*ip])!= ' ' && ch!= 0 && ch!= '\t' && ch!= ';') {
        if (ch >= 'A' && ch <= 'Z')
            ch &= 0x1f;
        else if (ch >= 'a' && ch <= 'z')
            ch &= 0x1f;
        else if (ch == '.')
            ch = 31;
        else if (ch == '*')
            ch = 30;
        else if (ch == '=')
            ch = 29;
        else return(-1);
        temp[j] = (temp[j] * 0x20) + (ch & 0xff);
        if (ch == 29)
            break;
        ++(*ip);
        if (++i >= 3) {
            i = 0;
            if (++j >= 2) {
                return(-1);
            }
        }
    }
    if ((j = temp[0]^temp[1]) == 0)
        return(-2);
    k = 0;
    i = step[k] - 3;
    do {
        if (j == optab[i]) {
            opflg = optab[++i];
            opval = optab[++i];
            return(i);
        }
        else if (j < optab[i])
            i -= step[++k];
        else i += step[++k];
    } while (step[k] != 0);
    return(-1);
}

/* error printing routine */

error(stptr)
   char *stptr;
{
    loadlc(loccnt, 0, 1);
    loccnt += 3;
    loadv(0,0,0);
    loadv(0,1,0);
    loadv(0,2,0);
    fprintf(stderr, "%s\n", prlnbuf);
    fprintf(stderr, "%s\n", stptr);
    errcnt++;
}

/* load 16 bit value in printable form into prlnbuf */

loadlc(val, f, outflg)
    int val;
    int f;
    int outflg;
{
    int i;

    i = 6 + 7*f;
    hexcon(4, val);
    if (nflag == 0) {
        prlnbuf[i++]  = hex[3];
        prlnbuf[i++]  = hex[4];
        prlnbuf[i++]  = ':';
        prlnbuf[i++]  = hex[1];
        prlnbuf[i] = hex[2];
    }
    else {
        prlnbuf[i++] = hex[1];
        prlnbuf[i++] = hex[2];
        prlnbuf[i++] = hex[3];
        prlnbuf[i] = hex[4];
    }
    if ((pass == LAST_PASS)&&(oflag != 0)&&(objcnt <= 0)&&(outflg != 0)) {
        fprintf(optr, "\n;%c%c%c%c", hex[3], hex[4], hex[1], hex[2]);
        objcnt = 16;
    }
}



/* load value in hex into prlnbuf[contents[i]] */
/* and output hex characters to obuf if LAST_PASS & oflag == 1 */

loadv(val,f,outflg)
   int  val;
   int  f;      /* contents field subscript */
   int  outflg;     /* flag to output object bytes */
{

    hexcon(2, val);
    prlnbuf[13 + 3*f] = hex[1];
    prlnbuf[14 + 3*f] = hex[2];
    if ((pass == LAST_PASS) && (oflag != 0) && (outflg != 0)) {
        fputc(hex[1], optr);
        fputc(hex[2], optr);
        --objcnt;
    }
    out_obj(val,outflg);  /* atari object file output */
}

/* convert number supplied as argument to hexadecimal in hex[digit] (lsd)
        through hex[1] (msd)        */

hexcon(digit, num)
    int digit;
   int  num;
{

    for (; digit > 0; digit--) {
        hex[digit] = (num & 0x0f) + '0';
        if (hex[digit] > '9')
            hex[digit] += 'A' -'9' - 1;
        num >>= 4;
    }
}

/* assign <value> to label pointed to by lablptr,
 *  checking for valid definition, etc.
 */

labldef(lval)
    int lval;
{
    int i;

    if (lablptr != -1) {
        lablptr += symtab[lablptr] + 1;
        if (pass == FIRST_PASS) {
            if (symtab[lablptr] == UNDEF) {
                symtab[lablptr + 1] = lval & 0xff;
                i = symtab[lablptr + 2] = (lval >> 8) & 0xff;
                if (i == 0)
                    symtab[lablptr] = DEFZRO;
                else    symtab[lablptr] = DEFABS;
            }
            else if (symtab[lablptr] == UNDEFAB) {
                symtab[lablptr] = DEFABS;
                symtab[lablptr + 1] = lval & 0xff;
                symtab[lablptr + 2] = (lval >> 8) & 0xff;
            }
            else {
                symtab[lablptr] = MDEF;
                symtab[lablptr + 1] = 0;
                symtab[lablptr + 2] = 0;
                error("Label multiply defined");
                return(-1);
            }
        }
        else {
            i = (symtab[lablptr + 2] << 8) +
                (symtab[lablptr+1] & 0xff);
            i &= 0xffff;
            if (i != lval && pass == LAST_PASS) {
                error("Sync error");
                return(-1);
            }
        }
    }
    return(0);
}

/* determine the value of the symbol,
 * given pointer to first character of symbol in symtab
 */

symval(ip)
    int *ip;
{
    int ptr;
    int svalue;

    svalue = 0;
    colsym(ip);
    if ((ptr = stlook()) == -1)
        undef = 1;      /* no room error */
    else if (symtab[ptr + symtab[ptr] + 1] == UNDEF)
        undef = 1;
    else if (symtab[ptr + symtab[ptr] + 1] == UNDEFAB)
        undef = 1;
    else svalue = ((symtab[ptr + symtab[ptr] + 3] << 8) +
        (symtab[ptr + symtab[ptr] + 2] & 0xff)) & 0xffff;
    if (symtab[ptr + symtab[ptr] + 1] == DEFABS)
        zpref = 1;
    if (undef != 0)
        zpref = 1;
    return(svalue);
}
