
#include "ass.h"

extern indx,lc;
extern char oldline[],line[];

pass1()
{
    char symb[9],direc[9];
    register val;
    int rel,def,globl;
    char del;

    indx=0;
    optsep();
    if (line[indx]==';' || !line[indx])
        return -1;
    indx=0;
    if (line[0]>='a' && line[0]<='z')
        gettok(symb);
    else
        *symb='\0';
    if (*symb && line[indx]!=':')
    {
        optsep();
        if (line[indx] != '=')
            error("'=' expected");
        else
            indx++;
        optsep();
        val=expr(&rel,&def,&globl,TRUE);
        if (!def)
            error("can't evaluate expression");
        else
            defsymb(symb,val,rel);
    }
    else
    {
        if (*symb)
        {
            indx++;
            defsymb(symb,lc,TRUE);
            val=indx;
            optsep();
            if (!line[indx] || line[indx]==';')
                return -1;
            indx=val;
        }
        else
            sep();
        optsep();
        if (line[indx] == '.')
        {
            indx++;
            gettok(direc);
            if (!strcmp("word",direc) || !strcmp("byte",direc))
            {
                if (*direc == 'w')
                    musteven();
                sep();
                do
                {
                    optsep();
                    expr(&rel,&def,&globl,FALSE);
                    lc+=(*direc=='w' ? 2 : 1);
                    optsep();
                }
                while (line[indx++] == ',');
                indx--;
            }
            else if (!strcmp("blkw",direc) || !strcmp("blkb",direc))
            {
                if (direc[3]=='w')
                    musteven();
                sep();
                val=expr(&rel,&def,&globl,TRUE);
                if (!def)
                    error("can't evaluate expression");
                if (rel)
                    error("expression must not be relocatable");
                if ((direc[3]=='b' ? val : val<<1) < 0)
                    error("lc may only be moved forward");
                lc+=(direc[3]=='b' ? val : val<<1);
            }
            else if (!strcmp("even",direc))
            {
                if (lc&1)
                    ++lc;
            }
            else if (!strcmp("ascii",direc))
            {
                sep();
                if (!(del=oldline[indx++]))
                    error("ascii-expression expected");
                while (line[indx] && oldline[indx]!=del)
                {
                    indx++;
                    lc++;
                }
                if (!line[indx])
                    error("right delimiter is missing");
                else
                    indx++;
            }
            else if (!strcmp("globl",direc))
            {
                sep();
                do
                {
                    if (line[indx]<'a' || line[indx]>'z')
                        error("symbol expected");
                    gettok(symb);
                    makeglob(symb);
                }
                while (line[indx++] == ',');
                indx--;
            }
            else if (!strcmp("end",direc))
            {
                optsep();
                if (line[indx] && line[indx]!=';')
                {
                    val=expr(&rel,&def,&globl,TRUE);
                    if (!def)
                        error("can't evaluate expression");
                    if (!rel)
                        error("starting adress must be relocatable");
                    return val;
                }
                else
                    return 0;
            }
            else
                error("no valid directive");
        }
        else
            mne1();
    }
    if (line[indx])
    {
        sep();
        if (line[indx] && line[indx]!=';')
            error("only comment allowed here");
    }
    return -1;
}

mne1()
{
    register i;
    int dummy;
    char tok[9];
    
    extern MNETYPE mnetab[];

    musteven();
    if (line[indx]<'a' || line[indx]>'z')
        error("mnemonic expected");
    gettok(tok);
    i=findmne(tok);
    if (mnetab[i].mode != NONE)
        sep();
    switch (mnetab[i].mode)
    {
        case NONE:
            break;
        case ONE:
            if (operand1())
                lc+=2;
            break;
        case TWO:
            if (operand1())
                lc+=2;
            comma();
            if (operand1())
                lc+=2;
            break;
        case REG1ST:
            mustreg();
            comma();
            if (operand1())
                lc+=2;
            break;
        case REG2ND:
            if (operand1())
                lc+=2;
            comma();
            mustreg();
            break;
        case BRANCH:
            expr(&dummy,&dummy,&dummy,FALSE);
            break;
        case REGONLY:
            mustreg();
            break;
        case SOB:
            mustreg();
            comma();
            expr(&dummy,&dummy,&dummy,FALSE);
            break;
    }
    lc+=2;
}

comma()
{
    if (line[indx] != ',')
        error("',' expected");
    indx++;
}

findmne(s)
register char *s;
{
    extern mnetab_len;
    extern MNETYPE mnetab[];

    register i,c;

    i=0;
    while (i<mnetab_len)
        if (!(c=strcmp(mnetab[i].name,s)))
            return i;
        else if (c>0)
            error("unknown mnemonic");
        else
            i++;
    error("unknown mnemonic");
}

musteven()
{
    if (lc & 1)
        error("location counter must be even");
}

sep()
{
    if (line[indx]!=' ' && line[indx]!='\t')
        error("seperator expected");
    optsep();
} 
        
optsep()
{
    while (line[indx]==' ' || line[indx]=='\t')
        indx++;
}

defsymb(symb,val,rel)
char *symb;
int val,rel;
{
    extern symbtab_len;
    extern SYMBTYPE symbtab[]; 

    register i;
    
    i=findsymb(symb);
    if (i == -1)
    {
        if (symbtab_len >= MAXSYMB)
            error("too many symbols");
        strcpy(symbtab[symbtab_len].name,symb);
        symbtab[symbtab_len].val=val;
        symbtab[symbtab_len].def=TRUE;
        symbtab[symbtab_len].rel=rel;
        symbtab[symbtab_len].globl=FALSE;
        symbtab_len++;
    }
    else
    {
        if (symbtab[i].def)
            error("trying do redefine symbol");
        symbtab[i].def=TRUE;
        symbtab[i].val=val;
        symbtab[i].rel=rel;
    }
}

makeglob(symb)
char *symb;
{
    extern symbtab_len;
    extern SYMBTYPE symbtab[];

    register i;
    
    i=findsymb(symb);
    if (i == -1)
    {
        if (symbtab_len >= MAXSYMB)
            error("too many symbols");
        strcpy(symbtab[symbtab_len].name,symb);
        symbtab[symbtab_len].globl=TRUE;
        symbtab[symbtab_len].def=FALSE;
        symbtab_len++;
    }
    else
    {
        if (symbtab[i].globl)
            error("symbol is already global");
        symbtab[i].globl=TRUE;
    }
}
