/*****************************************************************************
*           Change Log
*  Date     | Change
*-----------+-----------------------------------------------------------------
* 27-Nov-85 | [1.20] Created stub
*  1-Dec-85 | [1.92] Upgrade to handle DS
*  4-Dec-85 | [1.104] star is set to dot - 1
* 24-Nov-91 | [1.177] <jmn> converted to C6.0
*****************************************************************************/
#include <boolean.h>
#include <stdio.h>
#include <err.h>
#include <expr.h>
#include <operands.h>

#include <pos.h>
#include <ste.h>
#include <sym.h>
#include <pass1.h>
#include <operand.h>
#include <error.h>
#include <list.h>
#include <ds.h>

/****************************************************************************
*                                   dslabel
* Inputs:
*       int pass: Pass we are processing
*	int val: Operand value of DS, amount of space to reserve.  
*	int len: If an indented label is found, for dc/dcw, this is
*		 the amount of negative offset from dot to the left
*		 end of the data.  This will be 0 if an indented label
*		 is not permitted.  Note that for DC/DCW, val is always 0
* Result: int
*	offset of label: 0 if left-justified label
*			 len-1 if indented label
* Effect: 
*       Assigns the label.  The label is assigned to dot+val-1 unless the
*	label is indented, in which case it is assigned to dot
****************************************************************************/

int dslabel(int pass,int val,int len)
    {
     getlabelval * v;
     
     ste * sy;
     int sval;

     v = getlabel();

     if(v == NULL) 
	return 0;	/* No label, skip it */

     if(v->left)
        { /* left-end it */
	 if(len == 0)
	    { /* indented label not allowed */
	     if(pass == 2)
		error(err_label,"Indented label not allowed");
	    } /* indented label not allowed */
	} /* left-end it */

     if(v->left)
	sval = dot-len;
     else
	sval = dot+val-1;

     switch(pass)
        { /* pass decode */
	 case 1:  /* Define */
		sy = lookup(v->name);		/* see if it exists */
		if(sy == NULL)
		   { /* not found */
		    sy = enter(v->name,sval);	/* Create label */
		   } /* not found */
		else
		   { /* possibly duplicate? */
		    if(sy->val != sval)
			sy->muldef = true;
		   } /* possibly duplicate? */
		break;
	 case 2:  /* Check */
	 	sy = lookup(v->name);
		if(sy==NULL)
			return 0;      	       /* error, should not be NULL */
                if(sy->val != sval)
		   { /* redef */
		    char msg[80];
		    if(sy->muldef)
		       { /* multiply-defined */
		        muldef(sy,NULL);
		       } /* multiply-defined */
		    else
		       { /* phase error */
			sprintf(msg,"Phase error: symbol '%s'==%s (pass 1), %s (pass 2)",
					v->name,valstr(sy->val),valstr(val));
                        error(err_phase,msg);
		       } /* phase error */
	            
		   } /* redef */
	} /* pass decode */

     if(v->left)
	return len - 1;
     else
	return 0; 
    }

/****************************************************************************
*                                    do_ds
* Inputs:
*       int pass: Current pass number
* Effect: 
*       Processes DS operation
****************************************************************************/

void do_ds(int pass)
    {
     int val;
     int noperands;

     /* Check the operand.
        Skip over that much space.
	This requires that the symbols involved be defined
     */

     noperands = scan_operands();

     /* There must be only one value */

     if(noperands > 1)
        { /* bogus */
	 error(err_operand,"DS takes only one operand");
	 return;
	} /* bogus */

     if(noperands == 0)
        { /* bogus zero */
	 error(err_operand,"DS requires an operand");
	 return;
	} /* bogus zero */

     if(!expr(operands[0],&val,true,expr_lit_illegal,pass,false))
        { /* failed */
	 return;
	} /* failed */

     dslabel(pass,val,0);

     dot += val;

     sdot = dot;
     star = dot - 1;
    }

/****************************************************************************
*                                    dsop
* Inputs:
*       int opindex: (not used)
*	int pass: 1 or 2
* Effect: 
*       Defines storage area
* Syntax:
*	DS - Define Symbol
*	
*	<label>	DS	<expr>
*
*	The label is optional, and applies to the low-order position of
*	the bypassed area.  No information is created in the area.
****************************************************************************/

void dsop(int opindex,int pass)
    {
     do_ds(pass);

     if(pass==2)
        { /* list it */
	 list_addr(dot-1);
	 list_line();
	 emit_listing();
	} /* list it */


     return;
    }
