
#include "ass.h"
 
extern indx;
extern char line[];

expr(rel,def,globl,must)
int *rel,*def,*globl;
int must;
{
    char op='+';
    register val,val2;
    int rel2,globl2,def2,rel_error;

    val=0;
    *globl=FALSE;
    *def=TRUE;
    *rel=FALSE;
    if (line[indx]=='-')
    {
        indx++;
        op='-';
    }
    do
    {
        if (line[indx]=='[')
        {
            indx++;
            val2=expr(&rel2,&def2,&globl2,must);
            if (line[indx]!=']')
                error("']' expected");
            else
                indx++;
        }
        else
            val2=simpl_expr(&rel2,&def2,&globl2,must);
        *def=(*def && def2);
        *globl=(*globl || globl2);
        switch (op)
        {
            case '+':
                rel_error=(*rel && rel2);
                *rel=(*rel || rel2);
                val=val+val2;
                break;
            case '-':
                rel_error=(!(*rel) && rel2);
                *rel=(*rel && !rel2);
                val=val-val2;
                break;
            case '*':
                rel_error=(*rel || rel2);
                val=val*val2;
                break;
            case '/':
                if (val2 == 0)
                    if (must)
                        error("division by zero");
                    else
                        val2=1;
                rel_error=(*rel || rel2);
                val=val/val2;
                break;
        }
        if (rel_error && must)
            error("relocation error");
        op=line[indx++];
    }
    while (op=='+' || op=='-' || op=='*' || op=='/');
    indx--;
    return val;
}
        
simpl_expr(rel,def,globl,must)
int *rel,*def,*globl;
int must;
{
    extern lc;
    extern SYMBTYPE symbtab[];

    register i;

    if (line[indx]>='a' && line[indx]<='z')
        if ((i=symbol(must)) == -1)
            *def=FALSE;
        else
        {
            *rel=symbtab[i].rel;
            *def=symbtab[i].def;
            *globl=symbtab[i].globl;
            return symbtab[i].val;
        }
    else
    {
        *def=TRUE;
        *globl=FALSE;
        if (line[indx]=='.')
        {
            *rel=TRUE;
            indx++;
            return lc;
        }
        else
        {
            *rel=FALSE;
            if (line[indx]=='\'')
                return quote();
            else if (line[indx]=='"')
                return double_quote();
            else if (line[indx]>='0' && line[indx]<='9')
                return number();
            else
                error("simple expression expected");
        }
    }
}

symbol(must)
int must;
{
    extern symbtab_len;
    extern SYMBTYPE symbtab[];
    
    char tok[9];
    register i=0;
    
    gettok(tok);
    while (i<symbtab_len)
        if (!strcmp(tok,symbtab[i].name))
            return i;
        else
            i++;
    if (must)
        error("unknown symbol");
    else
        return -1;
}

findsymb(tok)
register char *tok;
{
    extern symbtab_len;
    extern SYMBTYPE symbtab[];
    
    register i=0;
    
    while (i<symbtab_len)
        if (!strcmp(tok,symbtab[i].name))
            return i;
        else
            i++;
    return -1;
}

extern char oldline[];

quote()
{
    if (line[indx+1])
    {
        indx+=2;
        return (oldline[indx-1]);
    }
    else
        error("illegal quote");
}

double_quote()
{
    if (line[indx+1] && line[indx+2])
    {
        indx+=3;
        return ((oldline[indx-2]<<8) | oldline[indx-1]);
    }
    else
        error("illegal doubleqoute");
}

number()
{
    register n=0,i,base;
    register char high;
    
    i=indx;
    while (line[i]>='0' && line[i]<='9')
        i++;
    if (line[i] == '.')
        base=10;
    else
        base=8;
    high='0'+base-1;
    if (base==8 && line[indx]>'7')
        error("octal digit expected");
    while (line[indx]>='0' && line[indx]<=high)
        n=n*base+line[indx++]-'0';
    if (base==10)
        indx++;
    return n;
} 

gettok(s)
register char *s;
{
    register count=8;

    while (((line[indx]>='a' && line[indx]<='z') ||
            (line[indx]>='0' && line[indx]<='9')) && count--) 
        *(s++)=line[indx++];
    *s='\0';    
    while ((line[indx]>='a' && line[indx]<='z') ||
           (line[indx]>='0' && line[indx]<='9'))    
        indx++;
}

error(s)
char *s;
{
    extern line_no;

    fprintf(stderr,"\nerror in line %d:\n%s\n",line_no,line);
    while (indx--)
        putc(' ',stderr);
    fprintf(stderr,"^\n%s\n",s);
    exit(1);
}


