
/*
   This software is copyright 1989 by John Dunning.  See the file
   'COPYLEFT.JRD' for the full copyright notice.
*/


/* pseudo ops */

#include "util.h"
#include "gen.h"
#include "parse.h"
#include "symtab.h"
#include "global.h"
#include "eval.h"

struct pseudo
	{
	char * pname;		/* opname */
	int (* func)();		/* fun to call */
	};

/* forward decls */
extern dirbyte();
extern dirword();
extern dirsetpc();
extern equate();
extern blkb();

#ifdef LIST
extern title();
extern sbttl();
#endif

extern ifzero();
extern ifnonzero();
extern endcond();
extern dirdbyte();
extern dirend();
extern globalsym();
extern ldax();
extern lbeq();
extern lbne();
extern lbcs();
extern lbcc();
extern lbpl();
extern lbmi();

struct pseudo ps[] =
	{
	{".byte", dirbyte},
	{".word", dirword},
	{"*=", dirsetpc},
	{"org", dirsetpc},
	{"=", equate},
	{".blkb", blkb},
#ifdef LIST
	{".title", title},
	{".page", title},
	{".sbttl", sbttl},
#endif
	{".dbyt", dirdbyte},
	{".if", ifnonzero},
	{".ifnz", ifnonzero},
	{".ifne", ifnonzero},
	{".ifeq", ifzero},
	{".ifz", ifzero},
	{".endc", endcond},
	{".end", dirend},
	{".globl", globalsym},
	{"ldax", ldax},			/* kludge til get macroes */
	{"lbeq", lbeq},
	{"lbne", lbne},
	{"lbcs", lbcs},
	{"lbcc", lbcc},
	{"lbpl", lbpl},
	{"lbmi", lbmi},
	/* more later */
	{0, 0}
	};

int do_pseudo()			/* return t if did one */
{
  int i;
  int (* f)();

  for (i = 0 ; ps[i].pname ; i++)
	{
	if (string_equal(ps[i].pname, p.opcode))
		{
		f = ps[i].func;
		(*f)();
		return(1);
		}
	}
  return(0);
}

dirbyte()
{
  int i, j, val, expr_flags;
  struct sym * rel_to_sym;
  char * arg;

  if (!disabled)
	{
	gen_label();
	if (!p.arg[0])
/*		pc += 1;		/* no args, just count a byte */
		genlit(0);
	    else
		for (i = 0 ; (arg = p.arg[i]) ; i++)
			if (arg[0] == '"')
				{
				for (j = 1 ; (arg[j] != '"') ; j++)
					{
					genlit(arg[j]);
					}
				}
			    else
				{
				val = eval(arg, &expr_flags, &rel_to_sym);
				genbyte(val, expr_flags, rel_to_sym);
				}
	}
}

dirdbyte()
{
  int i, val, expr_flags;
  struct sym * rel_to_sym;

  if (!disabled)
	{
	gen_label();
	for (i = 0 ; p.arg[i] ; i++)
		{
		val = eval(p.arg[i], &expr_flags, &rel_to_sym);
		genlit(val >> 8);
		genlit(val & 0xFF);
		}
	}
}

dirword()
{
  int i, val, expr_flags;
  struct sym * rel_to_sym;

  if(!disabled)
	{
	gen_label();
	if (!p.arg[0])
/*		pc += 2;		/* just count a word */
		{
		genlit(0);
		genlit(0);
		}
	    else
		for (i = 0 ; p.arg[i] ; i++)
			{
			val = eval(p.arg[i], &expr_flags, &rel_to_sym);
			genword(val, expr_flags, rel_to_sym);
			}
	}
}

dirsetpc()
{
  int val, expr_flags;
  struct sym * rel_to_sym;

  barf("not in relocatable mode you don't!");
/*
  if (!disabled)
	{
	val = eval(p.arg[0], &expr_flags, &rel_to_sym);
	pc = val;
	list_pc = pc;
	list_pc_p = 1;
	}
*/
}

equate()
{
  int val, expr_flags;
  struct sym * rel_to_sym;
  struct sym * sy;

  if (!disabled)
	{
	if (!p.label)
		barf("label required");
	    else
		{
		val = eval(p.arg[0], &expr_flags, &rel_to_sym);
		sy = find_sym(p.label, 1);
/* check for redefinition ... */
		sy->flags = DEFINED | ABS;
		list_v = sy->value = val;
		list_v_p = 1;
		}
	}
}

blkb()
{
  int i, val, expr_flags;
  struct sym * rel_to_sym;

  if (!disabled)
	{
	gen_label();
	val = eval(p.arg[0], &expr_flags, &rel_to_sym);

	list_v = val;
	list_v_p = 1;
/*	pc += val;	*/
	for (i = 0 ; i < val ; i++)
		genlit(0);
	}
}

#ifdef LIST
/* util routine for title hacking routines */
append_args(target)
char * target;
{
  int i;

  *target = '\0';
  for (i = 0 ; p.arg[i] ; i++)
	{
	strcat(target, p.arg[i]);
	strcat(target, " ");
	}
}

strip_quotes(target, source)
char * target;
char * source;
{
  if (*source == '"')
	source++;
  while (*source && (*source != '"'))
	*target++ = *source++;
  *target = '\0';
}

title()
{
  if (!disabled)
	{
/*  if (p.arg[0])
	if (*p.arg[0] == '"')
		strip_quotes(page_title, p.arg[0]);
	    else
		append_args(page_title);
/*  line_listed_p = 1;		/* don't list it */
	if (pass > 0)
		new_page();
	}
}

sbttl()
{
  if (!disabled)
	{
/*  if (p.arg[0])
	if (*p.arg[0] == '"')
		strip_quotes(page_subttl, p.arg[0]);
	    else
		append_args(page_subttl);
	if (pass > 0)
		new_page();
/*  line_listed_p = 1;		/* don't list it */
	}
}

#endif

ifzero()
{
  int val, e_flags;
  struct sym * unused;

  if (!disabled)
	{
	val = eval(p.arg[0], &e_flags, &unused);
	list_v = val;
	list_v_p = 1;
	if (val)
		disabled = 1;
	}
}

ifnonzero()
{
  int val, e_flags;
  struct sym * unused;

  if (!disabled)
	{
	val = eval(p.arg[0], &e_flags, &unused);
	list_v = val;
	list_v_p = 1;
	if (!val)
		disabled = 1;
	}
}

endcond()
{
  disabled = 0;
}

dirend()
{
/* zzz later, maybe deal with setting start addr here? */
  end_file = 1;
}

/* make symbol(s) global */
globalsym()
{
  char * name;
  int i;
  struct sym * sym;

  for (i = 0 ; name = p.arg[i] ; i++)
	{
	sym = find_sym(name, 1);
	sym->flags |= GLOBAL;
	}
}

ldax()
{
  int val, e_flags;
  struct sym * sy;

  if (*p.arg[0] != '#')
	barf("operand must be immediate");
  val = eval(p.arg[0]+1, &e_flags, &sy);
  genlit(0xA9);		/* lda immed */
  if (e_flags & E_REL)
	genbyte(val, e_flags | E_LO_BYTE, sy);
    else
	genlit(val & 0xFF);
  genlit(0xA2);		/* ldx immed */
  if (e_flags & E_REL)
  	genbyte(val, e_flags | E_HI_BYTE, sy);
    else
	genlit(val >> 8);
}

lbr(basecode)
int basecode;
{
  int val, e_flags;
  struct sym * sy;

  val = eval(p.arg[0], &e_flags, &sy);
  gen_lbr(basecode, sy);
}

lbeq() { lbr(0xF0); }  
lbne() { lbr(0xD0); }  
lbcs() { lbr(0xB0); }  
lbcc() { lbr(0x90); }  
lbpl() { lbr(0x10); }  
lbmi() { lbr(0x30); }  
