/*****************************************************************************
*           Change Log
*  Date     | Change
*-----------+-----------------------------------------------------------------
* 26-Nov-85 | [1.151] Created
*  4-Dec-85 | [1.105] Let compare operation have literal as second operand
* 28-Dec-85 | [1.174] Allow implicit d-char on no-operand instructions (WM)
* 24-Nov-91 | [1.177] <jmn> memory.h => automem.h
* 24-Nov-91 | [1.177] <jmn> converted to C6.0
* 24-Nov-91 | [1.177] <jmn> mach.h => machmem.h
* 26-Nov-91 | [1.204] <jmn> better checking for multiply-defined labels
*           | use startloc.h
* 26-Nov-91 | [1.212] <jmn> allow for propagation of DC/DCW declarations
*****************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <boolean.h>
#include <string.h>

#include <line.h>
#include <err.h>
#include <asmops.h>
#include <automem.h>
#include <machmem.h>
#include <ste.h>
#include <operands.h>
#include <expr.h>
#include <pass1.h>
#include <pass2.h>
#include <autocode.h>
#include <list.h>
#include <sym.h>
#include <expr.h>
#include <bcd.h>
#include <error.h>
#include <operand.h>
#include <startloc.h>
#include <da.h>

static boolean compare;

/* Assembler state */

extern int dot;	/* current location counter */
extern int star;	/* Value of '*' */
extern int sdot;
extern unsigned maxdot;
extern unsigned litpool;
extern unsigned litoffset;
extern FILE * reader;
extern char line[81];
extern boolean saw_end;

static int lastop = 0;

/****************************************************************************
*                                    pass2
* Effect: 
*       Runs pass 2 of the assembler
****************************************************************************/

void pass2()
    {
     star = sdot = dot = STARTLOC;
     maxdot = 0;
     saw_end = false;
     lastop = 0;

     while(true)
        { /* pass2 loop */
	 int opindex;
	 
	 if(saw_end) 
	    break;

	 readline();
	 if(feof(reader)) 
	    break;

	 if(line[0]=='*') 
	    { /* comment */
	     list_line();
	     emit_listing();
	     continue;	/* comment card */
	    } /* comment */

	 sdot = dot;

	 if(blankop() && lastop != 0)
	    { /* propagate it */
	     opindex = lastop + 1;
	    } /* propagate it */
         else
	    { /* new op */
	     opindex = opcode_2();
	     lastop = (optable[opindex].propagate ? opindex : 0);
	    } /* new op */

	 (*optable[opindex].processor)(opindex,2);
	 check_sym("end of processing line in pass 2");
	 fix_da();
	} /* pass2 loop */
     fprintf(stderr,"End of Pass 2\n");

    }

/****************************************************************************
*                                    label_2
* Effect: 
*       Checks the label in the symbol table.  Phase error if different
****************************************************************************/

void label_2()
    {
     getlabelval * v;
     ste * sy;

     v = getlabel();

     if(v != NULL)
        { /* check label */
	 if(v->left)
	    { /* indented */
	     list_err(err_label);
	     return NULL;
	    } /* indented */

	 sy = lookup(v->name);
	 if(sy==NULL)
	    { /* whoops */
	     char msg[80];
	     sprintf(msg,"Pass 2 failed to find label '%s'",v->name);
	     error(err_label,msg);
	     free(v->name);
	     return;
	    } /* whoops */
	 else
	 if(sy->val != dot || sy->muldef)
	    { /* whoops again */
	     char msg[80];
#if 0
	     sprintf(msg,"Pass 2 attempted to redefine label '%s'==%d to %d",
	     			v->name,sy->val,dot);
#else
	     muldef(sy,NULL);
#endif
	     error(err_label,msg);
	     free(v->name);
	     return;
	    } /* whoops again */
	} /* check label */
     free(v->name);
    }

/****************************************************************************
*                                   opcode_2
* Result: int
*	Index into opcode table
* Effect: 
*       Processes the opcode
****************************************************************************/

int opcode_2()
    {
     int i;
     boolean found = false;
     
     compare = false;

     for(i=0;strlen(optable[i].mnemonic)>0;i++)
        { /* check op */

	 found = legal_op(i);
	 if(found) 
	    break;

	} /* check op */

     /* Don't bother to report error, reported in pass 1 */

     if(!found)
        { /* punt opcode */
	 i = 0;
	 list_err(err_opcode);
	} /* punt opcode */

     if(strcmp(optable[i].mnemonic,"C    ") == 0) 
	compare = true;

     return i;
    }

/****************************************************************************
*                                  operands_2
* Inputs:
*	int opindex: Index of op table
* Effect: 
*       Processes the operands field
*
*	noperands	options		eval as
*					0th	1st	2nd
*	0		N/A		N/A	N/A	N/A
*	1		A		expr
*	1		A,B		expr
*	1		A,d		dchar
*	1		A,B,d		expr	
*	2		A		error
*	2		A,B		expr	expr
*	2		A,d		expr	dchar
*	2		A,B,d		expr	expr
*	3		A		error
*	3		A,d		error
*	3		A,B		error
*	3		A,B,d		expr	expr	dchar
****************************************************************************/

void operands_2(int opindex)
    {
     int i;
     int noperands;
     unsigned val1;
     unsigned val2;
     char d;

     noperands = scan_operands();

     /* Update the value of '*' */

     switch(noperands)
        { /* noperand decode */
	 case 0: /* No operands */
		if(optable[opindex].d != ' ')
		   { /* implicit d-char */
		    star++;
		   } /* implicit d-char */
		star++;
	 	break;	
	 case 1:
	 	switch(optable[opindex].format)
		   { /* format decode */
/* d */		    case op_d:
			star ++;
			break;
			break;
/* AAA */	    case op_A:
		        star += 3;
			break;
/* III */	    case op_I:
		        star += 3;
			if(optable[opindex].d != ' ')
			   { /* implicit d-char */
			    star++;
			   } /* implicit d-char */
			break;
/* AAA d */	    case op_A|op_d:
		        star++;
			break;
/* III d */	    case op_I|op_d:
		        star++;
			break;
/* AAA BBB */	    case op_A|op_B:
		        star += 3;
			break;
/* III BBB */	    case op_I|op_B:
		        star += 3;
			if(optable[opindex].d != ' ')
			   { /* implicit d-char */
			    star++;
			   } /* implicit d-char */
			break;
/* AAA BBB d */	    case op_A|op_B|op_d:
		        star += 3;
			break;
/* III BBB d */	    case op_I|op_B|op_d:
		        star += 3;
			break;
		    default: printf("operands_2.advance[1]: Format decode error (%d)\n",optable[opindex].format);
		   } /* format decode */
		break;
	 case 2:
	 	switch(optable[opindex].format)
		   { /* format decode */
/* d */		    case op_d:
			star +=4;
			break;
/* AAA */	    case op_A:
			star += 3;
			break;
/* III */	    case op_I:
			star += 3;
			if(optable[opindex].d != ' ')
			   { /* implicit d-char */
			    star++;
			   } /* implicit d-char */
			break;
/* AAA d */	    case op_A|op_d:
		        star += 4;
			break;
/* III d */	    case op_I|op_d:
		        star += 4;
			break;
/* AAA BBB */	    case op_A|op_B:
		    	star += 6;
			break;
/* III BBB */	    case op_I|op_B:
		    	star += 6;
			if(optable[opindex].d != ' ')
			   { /* implicit d-char */
			    star++;
			   } /* implicit d-char */
			break;
/* AAA BBB d */	    case op_A|op_B|op_d:
		        star += 6;
			break;
/* III BBB d */	    case op_I|op_B|op_d:
		        star += 6;
			break;
		    default: printf("operands_2.advance[2]: Format decode error (%d)\n",optable[opindex].format);
		   } /* format decode */
		break;
	 case 3:
	 	switch(optable[opindex].format)
		   { /* format decode */
/* d */		    case op_d:
			star += 7;
			break;
/* AAA */	    case op_A:
			star += 7;
			break;
/* AAA BBB */	    case op_A|op_B:
			star += 7;
			break;
/* AAA d */	    case op_A|op_d:
			star += 7;
			break;
/* III d */	    case op_I|op_d:
			star += 7;
			break;
/* AAA BBB d */	    case op_A|op_B|op_d:
		        star += 7;
			break;
/* III BBB d */	    case op_I|op_B|op_d:
		        star += 7;
			break;
		    default: printf("operands_2.advance[3]: Format decode error (%d)\n",optable[opindex].format);
		   } /* format decode */
		break;
	} /* noperand decode */

     /* Now write the operands out */
     switch(noperands)
        { /* noperand decode */
	 case 0: /* No operands */
		if(optable[opindex].d != ' ')
		   { /* implicit d-char */
		    write_dchar((unsigned char)ascii_to_bcd(optable[opindex].d));
		   } /* implicit d-char */
	 	break;	/* do nothing */
	 case 1:
	 	switch(optable[opindex].format)
		   { /* format decode */

/* d */		    case op_d:
			write_dchar(dchar(operands[0]));
			break;
/* III */	    case op_I:		    /* valid form is  'op III' */
		    	expr(operands[0],&val1,true,expr_lit_illegal,2,false);
			write_operand(val1);
			if(optable[opindex].d != ' ')
			   { /* implicit d-char */
			    write_dchar((unsigned char)ascii_to_bcd(optable[opindex].d));
			   } /* implicit d-char */
			break;

/* III d */	    case op_I|op_d:	/* valid form is 'op d' or 
		    					 'op AAA,d' */
							 
			write_dchar(dchar(operands[0]));
			break;
/* AAA BBB */	    case op_A|op_B:	   /* valid form is 'op AAA' or
		    					    'op AAA,BBB' */
		    	expr(operands[0],&val1,true,expr_lit_pool,2,false);
			write_operand(val1);
			break;

/* III BBB */	    case op_I|op_B:	   /* valid form is 'op AAA' or
		    					    'op AAA,BBB' */
		    	expr(operands[0],&val1,true,expr_lit_illegal,2,false);
			write_operand(val1);
			if(optable[opindex].d != ' ')
			   { /* implicit d-char */
			    write_dchar((unsigned char)ascii_to_bcd(optable[opindex].d));
			   } /* implicit d-char */
			break;

/* AAA BBB d */	    case op_A|op_B|op_d:
		    	expr(operands[0],&val1,true,expr_lit_pool,2,false);
			write_operand(val1);
			break;
/* III BBB d */	    case op_I|op_B|op_d:
		    	expr(operands[0],&val1,true,expr_lit_illegal,2,false);
			write_operand(val1);
			break;
		    default: printf("operands_2.generate[1]: Format decode error (%d)\n",optable[opindex].format);
		   } /* format decode */
		break;
	 case 2:
	 	switch(optable[opindex].format)
		   { /* format decode */
/* d */		    case op_d:
		    	error(err_operand,"Too many operands");
			dot += 4;
			break;
/* AAA */	    case op_A:
		    	error(err_operand,"Too many operands");
			dot += 3;
			break;
/* III */	    case op_I:
		    	error(err_operand,"Too many operands");
			dot += 3;
			break;
/* AAA d */	    case op_A|op_d:
		    	expr(operands[0],&val1,true,expr_lit_illegal,2,false);
			write_operand(val1);
			write_dchar(dchar(operands[1]));
			break;
/* III d */	    case op_I|op_d:
		    	expr(operands[0],&val1,true,expr_lit_illegal,2,false);
			write_operand(val1);
			write_dchar(dchar(operands[1]));
			break;
/* AAA BBB */	    case op_A|op_B:
		    	expr(operands[0],&val1,true,expr_lit_pool,2,false);
			write_operand(val1);
		    	expr(operands[1],&val2,true,
			      (compare ? expr_lit_pool : expr_lit_illegal),2,
			      	false);
			write_operand(val2);
			break;
/* III BBB */	    case op_I|op_B:
		    	expr(operands[0],&val1,true,expr_lit_illegal,2,false);
			write_operand(val1);
		    	expr(operands[1],&val2,true,expr_lit_illegal,2,false);
			write_operand(val2);
			if(optable[opindex].d != ' ')
			   { /* implicit d-char */
			    write_dchar((unsigned char)ascii_to_bcd(optable[opindex].d));
			   } /* implicit d-char */
			break;
/* AAA BBB d */	    case op_A|op_B|op_d:
		    	expr(operands[0],&val1,true,expr_lit_pool,2,false);
			write_operand(val1);
		    	expr(operands[1],&val2,true,expr_lit_illegal,2,false);
			write_operand(val2);
			break;
/* III BBB d */	    case op_I|op_B|op_d:
		    	expr(operands[0],&val1,true,expr_lit_illegal,2,false);
			write_operand(val1);
		    	expr(operands[1],&val2,true,expr_lit_illegal,2,false);
			write_operand(val2);
			break;
		    default: printf("operands_2.generate[2]: Format decode error (%d)\n",optable[opindex].format);
		   } /* format decode */
		break;
	 case 3:
	 	switch(optable[opindex].format)
		   { /* format decode */
/* d */		    case op_d:
			dot += 7;
			break;
/* AAA */	    case op_A:
		    	error(err_operand,"Too many operands");
			dot += 7;
			break;
/* AAA BBB */	    case op_A|op_B:
		    	error(err_operand,"Too many operands");
			dot += 7;
			break;
/* III BBB */	    case op_I|op_B:
		    	error(err_operand,"Too many operands");
			dot += 7;
			break;
/* AAA d */	    case op_A|op_d:
		    	error(err_operand,"Too many operands");
			dot += 7;
			break;
/* AAA BBB d */	    case op_A|op_B|op_d:
			expr(operands[0],&val1,true,expr_lit_pool,2,false);
			write_operand(val1);
		    	expr(operands[1],&val2,true,expr_lit_illegal,2,false);
			write_operand(val2);
			write_dchar(dchar(operands[2]));
			break;
/* III BBB d */	    case op_I|op_B|op_d:
			expr(operands[0],&val1,true,expr_lit_illegal,2,false);
			write_operand(val1);
		    	expr(operands[1],&val2,true,expr_lit_illegal,2,false);
			write_operand(val2);
			write_dchar(dchar(operands[2]));
			break;
		    default: printf("operands_2.generate[3]: Format decode error (%d)\n",optable[opindex].format);
		   } /* format decode */
		break;
	} /* noperand decode */
     
    }
