/*
 *      pseudo.c	-	pseudo op processing
 *
 *	From Motorola BBS.
 *	See ../doc/ChangeLog to examine and/or add change descriptions.
 */

#define RMB     0       /* Reserve Memory Bytes         */
#define FCB     1       /* Form Constant Bytes          */
#define FDB     2       /* Form Double Bytes (words)    */
#define FCC     3       /* Form Constant Characters     */
#define ORG     4       /* Origin                       */
#define EQU     5       /* Equate                       */
#define ZMB     6       /* Zero memory bytes            */
#define FILL    7       /* block fill constant bytes    */
#define OPT     8       /* assembler option             */
#define NULL_OP 9       /* null pseudo op               */
#define PAGE    10      /* new page                     */
#define END     11      /* end directive                */
#define IF      12      /* if directive                 */
#define ENDIF   13      /* endif directive              */
#define SETDBG	14	/* set debug characteristic	*/

/*
 *	Keep this table SORTED by pseudo-op name, or
 *	else the binary search algorithm won't work.
 */
struct oper pseudo[] = {
"bsz",  PSEUDO, ZMB,    0,
"debug",PSEUDO, SETDBG, 0,
"end",  PSEUDO, END,    0,
"endif",PSEUDO, ENDIF,  0,
"equ",  PSEUDO, EQU,    0,
"fcb",  PSEUDO, FCB,    0,
"fcc",  PSEUDO, FCC,    0,
"fdb",  PSEUDO, FDB,    0,
"fill", PSEUDO, FILL,   0,
"if",   PSEUDO, IF,     0,
"nam",  PSEUDO, NULL_OP,0,
"name", PSEUDO, NULL_OP,0,
"opt",  PSEUDO, OPT,    0,
"org",  PSEUDO, ORG,    0,
"pag",  PSEUDO, PAGE,   0,
"page", PSEUDO, PAGE,   0,
"rmb",  PSEUDO, RMB,    0,
"spc",  PSEUDO, NULL_OP,0,
"ttl",  PSEUDO, NULL_OP,0,
"zmb",  PSEUDO, ZMB,    0
};

/*
 *      do_pseudo --- do pseudo op processing
 */
void
do_pseudo(int op)
{
        char    fccdelim;
        int     j;
        int     fill;
        char    *skip_white(char *ptr);

#ifdef  DEBUG
	if (DebugMess)
        	printf("pseudo--%2d-\n",op);
#endif
         if( op == IF ){
                if( eval() ){
                        Old_pc = Result;
                        if( !Result ){
                                Incondition++;
                        }
                        return;
               }
         }
         if( op == ENDIF ){
                Old_pc = Incondition;
                if( Incondition ){
                        Incondition--;
                }
                return;
        }

         if( Incondition )return;

        if( op != EQU && *Label )
                install(Label,Pc);

        P_force++;
        switch(op){
                case RMB:                       /* reserve memory bytes */
                        if( eval() ){
                                Pc +=  Result;
                                f_record();     /* flush out bytes */
                                }
                        break;
                case ZMB:                       /* zero memory bytes */
			if( eval() ) {
				if( Result > P_LIMIT )
					note("Many bytes; listing abbreviated");
                                while( Result-- )
					emit(0);
				}
                        break;
                case FILL:                      /* fill memory with constant */
			eval();
                        fill = Result;
                        if( *Optr++ != ',' )
				error("Missing comma in fill statement");
                        else{
                                Optr = skip_white(Optr);
				if( !eval() ) break;
				if( Result > P_LIMIT )
					note("Many bytes; listing abbreviated");
                                while( Result-- )
                                        emit(fill);
                                }
                        break;
                case FCB:                       /* form constant byte(s) */
                        do{
                                Optr = skip_white(Optr);
				eval();
				if( Result > 0xFF ){
                                        if(!Force_byte)
                                                warn("Value truncated");
                                        Result = lobyte(Result);
                                        }
                                emit(Result);
                        }while( *Optr++ == ',' );
                        break;
                case FDB:                       /* form double byte(s) */
                        do{
                                Optr = skip_white(Optr);
				eval();
                                eword(Result);
                        }while( *Optr++ == ',' );
                        break;
                case FCC:                       /* form constant characters */
			if( delim(*Optr) ) {
				error("No characters specified");
				break;
				}
                        fccdelim = *Optr++;
                        while( *Optr != EOS && *Optr != fccdelim)
                                emit(*Optr++);
			if(*Optr != fccdelim)
                                error("Missing Delimiter");
                        break;
                case ORG:                       /* origin */
                        if( eval() ){
                                Old_pc = Pc = Result;
                                f_record();     /* flush out any bytes */
                                }
                        break;
                case EQU:                       /* equate */
                        if(*Label==EOS){
                                error("EQU requires label");
                                break;
                                }
			eval();
			install(Label,Result);
			Old_pc = Result;        /* override normal */
				/* above makes Result show on listing */
                        break;
                case OPT:                       /* assembler option */
			P_force=0;
			for( j=0; Operand[j]; j++ )
			   Operand[j] = mapdn( Operand[j] );
			if( Lflag ) Cpflag |= 2;
                        do {
                            Optr = skip_white(Optr);
			    if( head(Optr,"l") )
                                    Lflag=1;
			    else if( head(Optr,"nol"))
                                    Lflag=0;
			    else if( head(Optr,"c")){
                                    Cflag=1;
                                    Ctotal=0;
                                    }
			    else if( head(Optr,"noc")) {
				    Cflag=0;
				    Cpflag |= 1;
				    }
			    else if( head(Optr,"contc"))
                                    Cflag=1;
			    else if ( head(Optr,"s"))
                                    Sflag = 1;
			    else if ( head(Optr,"cre"))
                                    CREflag = 1;
                            else
                                    error("Unrecognized or missing OPT");
			    while( alpha(*Optr) ) Optr++;
                        } while( *Optr++ == ',' );
                        break;
                case PAGE:                      /* go to a new page */
                        P_force=0;
                        N_page = 1;
			if (Pass == 2 )
                         if (Lflag)  
                          {
                           printf ("\f");
			   printf ("%-40s",Argv[Cfn]);
			   printf ("     ");
                           printf ("page %3d\n",Page_num++);
			  }
			break;
		case END:               /* END directive */
			End = YES;
			if( !delim(*Optr) ) {
			   if( eval() ) {
					if((unsigned long int)Result > (unsigned long int)0xFFFF)
				 error("Entry point value > 16 bits");
			      if( Entry_set ) {
				 if( Result == Entry_pt )
				    warn("Entry point already specified");
				 else error("Entry point redefined");
			      }
			      else {
				 Entry_pt = Result;
				 Entry_set = YES;
			      }
			   }
			   else warn("Comments following END should start with semicolon");
			}
			break;
                case NULL_OP:                   /* ignored psuedo ops */
                        P_force=0;
                        break;
                case SETDBG:   /* set optional debug characteristics */
			for( j=0; Operand[j]; j++ )
			   Operand[j] = mapdn( Operand[j] );
                        do {
                            Optr = skip_white(Optr);
			    if( head(Optr,"del_err") )
                                    DelErr=1;	/* del output file on error */
			    else if( head(Optr,"no_del_err") )
                                    DelErr=0;
			    else if( head(Optr,"debug_mess") )
                                    DebugMess=1;
			    else if( head(Optr,"no_debug_mess") )
                                    DebugMess=0;
                            else
                                    error("Unrecognized or missing DEBUG");
			    while( alpha(*Optr) ) Optr++;
                        } while( *Optr++ == ',' );
                        break;
                default:
                        fatal("Pseudo error");
                }
}
