
#include "ass.h"

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

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

    indx=0;
    optsep();
    if (line[indx]==';' || !line[indx])
        return FALSE;
    indx=0;
    if (line[0]>='a' && line[0]<='z')
        gettok(symb);
    else
        *symb='\0';
    if (*symb && line[indx]!=':')
        return FALSE;
    if (*symb)
    {
        indx++;
        val=indx;
        optsep();
        if (!line[indx] || line[indx]==';')
            return FALSE;
        indx=val;
    }
    optsep();
    if (line[indx] == '.')
    {
        indx++;
        gettok(direc);
        if (!strcmp("word",direc))
        {
            sep();
            do
            {
                optsep();
                val=strexpr(tok,&rel,&def);
                putexpr(val,tok,rel,FALSE);
                lc+=2;
                optsep();
            }
            while (line[indx++] == ',');
            indx--;
        }
        else if (!strcmp("byte",direc))
        {
            sep();
            do
            {
                optsep();
                val=strexpr(tok,&rel,&def);
                if (!def || rel)
                    error("bytes must be absolute and defined");
                putbyte(val);
                lc++;
                optsep();
            }
            while (line[indx++] == ',');
            indx--;
        }
        else if (!strcmp("blkw",direc))
        {
            sep();
            val=expr(&rel,&def,&globl,TRUE);
            lc+=val<<1;
            putoct('#',val<<1);
        }
        else if (!strcmp("blkb",direc))
        {
            sep();
            val=expr(&rel,&def,&globl,TRUE);
            lc+=val;
            putoct('#',val);
        }
        else if (!strcmp("even",direc))
        {
            if (lc&1)
            {
                putbyte(0);
                ++lc;
            }
        }
        else if (!strcmp("ascii",direc))
        {
            sep();
            del=oldline[indx++];
            while (oldline[indx]!=del)
            {
                putbyte(oldline[indx++]);
                lc++;
            }   
            indx++;
        }
        else if (!strcmp("end",direc))
            return TRUE;
        else
            return FALSE;
    }
    else
        mne2();
    if (line[indx])
    {
        sep();
        if (line[indx] && line[indx]!=';')
            error("only comment allowed here");
    }        
    return FALSE;
}

int pc;

mne2()
{
    extern MNETYPE mnetab[];

    register offs,op,r,i;
    int val,def,rel,globl,mode;
    char tok[9];
    
    pc=lc+2;
    gettok(tok);
    i=findmne(tok);
    if (mnetab[i].mode != NONE)
        sep();
    op=mnetab[i].opc;
    switch (mnetab[i].mode)
    {
        case NONE:
            break;
        case ONE:
            r=operand2(&mode);
            immed(r,mode);
            if (op==0000100 && mode==0)
                error("you can't jump into a register");
            op|=((mode<<3)|r);
            break;
        case TWO:
            r=operand2(&mode);
            op|=((mode<<3)|r)<<6;
            comma();
            r=operand2(&mode);
            if ((op&0070000) != 0020000 && (op&0070000) != 0030000)
                immed(r,mode);
            op|=((mode<<3)|r);
            break;
        case REG1ST:
            r=mustreg();
            op|=(r<<6);
            comma();
            r=operand2(&mode);
            immed(r,mode);
            if (op==0004000 && mode==0)
                error("you can't jump into a register");
            op|=((mode<<3)|r);
            break;
        case REG2ND:
            r=operand2(&mode);
            op|=((mode<<3)|r);
            comma();
            r=mustreg();
            op|=(r<<6);
            break;
        case BRANCH:
            val=expr(&rel,&def,&globl,TRUE);
            if (!rel)
                error("branch destination must be relocatable");
            if (!def)
                error("branch destination must not be global");
            offs=val-pc;
            if (offs&1)
                error("odd branch destination");
            offs=offs>>1;
            if (offs<-128 || offs>127)
                error("branch to long");
            op|=(offs&0xff);
            break;
        case REGONLY:
            r=mustreg();
            op|=r;
            break;
        case SOB:
            r=mustreg();
            op|=(r<<6);
            comma();
            val=expr(&rel,&def,&globl,TRUE);
            if (!rel)
                error("branch destination must be relocatable");
            if (!def)
                error("branch destination must not be global");
            offs=pc-val;
            if (offs <= 0)
                error("sob must branch backwards");
            if (offs&1)
                error("odd branch destination");
            offs=offs>>1;
            if (offs > 077)
                error("branch to long");
            op|=offs;
            break;
    }
    putexpr(op,"",FALSE,FALSE);
    lc=pc;
}

immed(r,mode)
int r,mode;
{
    if (mode==2 && r==7)
        error("immediate mode not allowed here");
}

strexpr(s,rel,def)
char *s;
int *rel,*def;
{
    int globl;
    register i,val;

    i=indx;
    val=expr(rel,def,&globl,TRUE);
    pc+=2;
    if (!*def)
    {
        if (!globl)
            error("can't evaluate expression");
        indx=i;
        if (line[indx]<'a' || line[indx]>'z')
            error("global symbol may not be used within expression");
        gettok(s);
        return 0;
    }
    else
    {
        *s='\0';
        return val;
    }
}

stroct(s,w)
register char *s;
register unsigned w;
{
    register c;
    
    c=15;
    while (c>=0)
    {
        *(s++)=(w>>c)+'0';
        w=(w<<(16-c))>>(16-c);
        c-=3;
    }
    *s='\0';
}
 
char buf[50]="";
int buffered=FALSE;

putstr(c,s)
char c,*s;
{
    extern FILE *outfile;

    char *t;
    
    if (buffered)
    {
        t=buf;
        if (*t)
        {
            while (*t)
                ++t;
            *(t++)='\n';
        }
        if (c)
            *(t++)=c;
        while (*s)
            *(t++)=*(s++);
        *t='\0';
    }
    else
    {
        if (c)
            putc(c,outfile);
        fputs(s,outfile);
        putc('\n',outfile);
        if (*buf)
        {
            fputs(buf,outfile);
            putc('\n',outfile);
            *buf='\0';
        }
    }
}

