/* xa65 - 65xx/65816 cross-assembler and utility suite
 *
 * Copyright (C) 1989-1997 André Fachat (a.fachat@physik.tu-chemnitz.de)
 * maintained by Cameron Kaiser
 *
 * Core tokenizing module/pass 1 and pass 2
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/* enable this to turn on (copious) optimization output */

#undef LISTING_DEBUG
#undef DEBUG_CONV
#undef DEBUG_CAST
#undef DEBUG_RELOC
#undef DEBUG_AM

#include <ctype.h>
#include <stdio.h>
#include <string.h>

#include "xad.h"
#include "xah.h"
#include "xah2.h"

#include "xar.h"
#include "xa.h"
#include "xaa.h"
#include "xal.h"
#include "xat.h"
#include "xao.h"
#include "xap.h"
#include "xacharset.h"
#include "xalisting.h"

int dsb_len = 0;

static int t_conv(signed char*,signed char*,int*,int,int*,int*,int*,int,int*);
static int t_keyword(signed char*,int*,int*);
static int tg_asc(signed char*,signed char*,int*,int*,int*,int*,int);
static void tg_dez(signed char*,int*,int*);
static void tg_hex(signed char*,int*,int*);
static void tg_oct(signed char*,int*,int*);
static void tg_bin(signed char*,int*,int*);
static int t_p2(signed char *t, int *ll, int fl, int *al);
//static void do_listing(signed char *listing, int listing_len, signed char *bincode, int bincode_len);

void list_setbytes(int number_of_bytes_per_line);

/* assembly mnemonics and pseudo-op tokens */
/* ina and dea don't work yet */
/* Note AF 20110624: added some ca65 compatibility pseudo opcodes,
 * many are still missing (and will most likely never by supported in this
 * code base). Potential candidates are .hibytes, .lobytes, .asciiz,
 * .addr, .charmap, .dbyt, .faraddr, .bankbytes, .segment (at least for the known ones)
 * .incbin is similar to our .bin, but with parameters reversed (argh...)
 * I like the .popseg/.pushseg pair; 
 * .global/.globalzp is equivalent to forward-defining a label in the global block
 * .export/.exportzp could be implemented with a commandline switch to NOT export
 * global labels, where .exported labels would still be exported in an o65 file.
 */
char *kt[] ={ 
/*    1     2     3    4      5     6      7   8      9     10   */
     "adc","and","asl","bbr","bbs","bcc","bcs","beq","bit","bmi",
     "bne","bpl","bra","brk","bvc","bvs","brl","clc","cld","cli",
/*
     "clv","cmp","cpx","cpy","cop","dea","dec","dex","dey","eor",
*/
     "clv","cmp","cpx","cpy","cop",/*"dea",*/"dec","dex","dey","eor",

/*
     "ina","inc","inx","iny","jmp","jsr","lda","ldx","ldy","lsr",
*/
     /*"ina",*/"inc","inx","iny","jmp","jsr","lda","ldx","ldy","lsr",
     "mvp","mvn","nop","ora","pha","php","phx","phy","pla","plp",
     "plx","ply","phb","phd","phk","plb","pld","pea","pei","per",

     "rmb","rol","ror","rti","rts","rep","rtl","sbc","sec","sed",
     "sei","smb","sta","stx","sty","stz","sep","stp","tax","tay",
     "trb","tsb","tsx","txa","txs","tya","txy","tyx","tcd","tdc",

     "tcs","tsc","wai","wdb","xba","xce", 

     ".byt",".word",".asc",".dsb", ".(", ".)", "*=", ".text",".data",".bss",
     ".zero",".fopt", ".byte", ".end", ".list", ".xlist", ".dupb", ".blkb", ".db", ".dw",
     ".align",".block", ".bend",".al",".as",".xl",".xs", ".bin", ".aasc", ".code",
     ".include", ".import", ".importzp", ".proc", ".endproc",
     ".zeropage", ".org", ".reloc", ".listbytes",
     ".scope", ".endscope", ".assert"

};

/* arithmetic operators (purely for listing, parsing is done programmatically */
char *arith_ops[] = {
	"", "+", "-",			// 0,1,2
	"*", "/",			// 3,4
	">>", "<<",			// 5,6
	"<", ">", "=",			// 7,8,9
	"<=", ">=", "<>",		// 10,11,12
	"&", "^", "|",			// 13,14,15
	"&&", "||", "==", "!=", "!"	// 16,17,18 (9),19 (12),20 (NYI)
};

/* length of arithmetic operators indexed by operator number */
static int lp[]= { 0,1,1,1,1,2,2,1,1,1,2,2,2,1,1,1,2,2,2,2,1 };

/* mvn and mvp are handled specially, they have a weird syntax */
#define  Kmvp 38
#define  Kmvn Kmvp+1

/* index into token array for pseudo-ops */
/* last valid mnemonic */
#define   Lastbef   93

#define   Kbyt      Lastbef+1
#define   Kword     Lastbef+2
#define   Kasc      Lastbef+3
#define   Kdsb      Lastbef+4
#define   Kopen     Lastbef+5  	/* .(      */
#define   Kclose    Lastbef+6  	/* .)      */
#define   Kpcdef    Lastbef+7  	/* *=value */
#define	  Ktext     Lastbef+8
#define	  Kdata     Lastbef+9
#define	  Kbss      Lastbef+10
#define	  Kzero     Lastbef+11
#define	  Kfopt     Lastbef+12
#define	  Kbyte	    Lastbef+13	/* gets remapped to Kbyt */
#define	  Kend      Lastbef+14	/* ignored (MASM compat.) */
#define	  Klist     Lastbef+15	/* ignored (MASM compat.) */
#define	  Kxlist    Lastbef+16	/* ignored (MASM compat.) */
#define	  Kdupb     Lastbef+17	/* gets remapped to Kdsb */
#define	  Kblkb     Lastbef+18	/* gets remapped to Kdsb */
#define	  Kdb       Lastbef+19	/* gets remapped to Kbyt */
#define	  Kdw       Lastbef+20	/* gets remapped to Kword */
#define	  Kalign    Lastbef+21
#define	  Kblock    Lastbef+22	/* gets remapped to .( */
#define	  Kbend	    Lastbef+23	/* gets remapped to .) */

#define   Kalong    Lastbef+24
#define   Kashort   Lastbef+25
#define   Kxlong    Lastbef+26
#define   Kxshort   Lastbef+27

#define   Kbin      Lastbef+28
#define   Kaasc     Lastbef+29

#define	  Kcode	    Lastbef+30	/* gets remapped to Ktext */

/* 93 + 30 -> 123 */

#define	  Kinclude  Lastbef+31
#define   Kimport   Lastbef+32
#define   Kimportzp Lastbef+33
#define	  Kproc     Lastbef+34	/* mapped to Kopen */
/* 93 + 35 -> 128 */
#define	  Kendproc  Lastbef+35	/* mapped to Kclose */
#define	  Kzeropage Lastbef+36	/* mapped to Kzero */
#define	  Korg      Lastbef+37	/* mapped to Kpcdef - with parameter equivalent to "*=$abcd" */
#define	  Krelocx   Lastbef+38	/* mapped to Kpcdef - without parameter equivalent to "*=" */
#define	  Klistbytes (Lastbef+39-256)
#define	  Kscope    (Lastbef+40) /* mapped to Kopen */
#define	  Kendscope (Lastbef+41) /* mapped to Kclose */

#define   Kassert   (Lastbef+42-256)

/* last valid token+1 */
#define	  Anzkey    Lastbef+43	/* define last valid token number; last define above plus one */


#define   Kreloc    (Anzkey-256)   	/* *= (relocation mode) */
#define   Ksegment  (Anzkey+1-256)	/* this actually now is above 127, which might be a problem as char is signed ... */

int number_of_valid_tokens = Anzkey;

/* array used for hashing tokens (26 entries, a-z) */

static int ktp[]={ 0,3,17,25,28,29,29,29,29,32,34,34,38,40,41,42,58,
               58,65,76,90,90,90,92,94,94,94,Anzkey };

#define   Admodes   24

/* 
 * opcodes for each addressing mode
 * high byte: supported architecture (no bits = original NMOS 6502)
 *  bit 1: R65C02
 *  bit 2: 65816 and allows 16-bit quantity (accum only)
 *  bit 3: 65816 and allows 16-bit quantity (index only)
 * low byte: opcode itself
 *
 * each opcode is indexed in this order: *=65816, ^=R65C02
 * 00 = implied
 * 01 = zero page
 * 02 = zero page,x
 * 03 = direct page,y*
 * 04 = direct page (indirect)*
 * 05 = (indirect,x)
 * 06 = (indirect),y
 * 07 = immediate (8-bit)
 * 08 = absolute
 * 09 = absolute,x
 * 10 = absolute,y
 * 11 = relative
 * 12 = (indirect-16) i.e., jmp (some_vector)
 * 13 = (absolute,x)*
 * 14 = zero page+relative test'n'branch ^
 * 15 = zero page clear'n'set'bit ^
 * 16 = relative long*
 * 17 = absolute long*
 * 18 = absolute long,x*
 * 19 = stack relative*
 * 20 = stack relative (indirect),y*
 * 21 = direct page (indirect long)*
 * 22 = direct page (indirect long),y*
 * 23 = (indirect long)
 */

static int ct[Lastbef+1][Admodes] ={
/*     0    1    2    3    4    5    6    7    8    9   10   11   12   13   14   15   16   17   18   19   20   21   22   23   imm */
{     -1,  0x65,0x75,-1,0x172,0x61,0x71,0x469,0x6d,0x7d,0x79,-1,  -1,  -1,  -1,  -1,  -1,0x26f,0x27f,0x263,0x273,0x267,0x277,-1 },  /*adc*/
{     -1,  0x25,0x35,-1,0x132,0x21,0x31,0x429,0x2d,0x3d,0x39,-1,  -1,  -1,  -1,  -1,  -1,0x22f,0x23f,0x223,0x233,0x227,0x237,-1 },  /*and*/
{     0x0a,0x06,0x16,-1,  -1,  -1,  -1,  -1,  0x0e,0x1e,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*asl*/
{     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, 0x10f,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*bbr*/
{     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, 0x18f,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*bbs*/
{     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  0x90,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*bcc*/
{     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  0xb0,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*bcs*/
{     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  0xf0,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*beq*/
{     -1,  0x24,0x134,-1, -1,  -1,  -1, 0x589,0x2c,0x13c,-1, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*bit*/
{     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  0x30,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*bmi*/
{     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  0xd0,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*bne*/
{     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  0x10,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*bpl*/
{     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  0x180,-1, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*bra*/
{     0x00,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*brk*/
{     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  0x50,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*bvc*/
{     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  0x70,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*bvs*/
{     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,0x282, -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*brl*/
{     0x18,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*clc*/
{     0xd8,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*cld*/
{     0x58,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*cli*/
{     0xb8,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*clv*/
{     -1,  0xc5,0xd5,-1, 0x1d2,0xc1,0xd1,0x4c9,0xcd,0xdd,0xd9,-1, -1,  -1,  -1,  -1,-1,0x2cf,0x2df,0x2c3,0x2d3,0x2c7,0x2d7,-1 },  /*cmp*/
{     -1,  0xe4,-1,  -1,  -1,  -1,  -1, 0x8e0,0xec,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*cpx*/
{     -1,  0xc4,-1,  -1,  -1,  -1,  -1, 0x8c0,0xcc,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*cpy*/
{     -1,  -1,  -1,  -1,  -1,  -1,  -1,  0x202,-1,  -1,  -1, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*cop*/
/*
{     0x13a,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },*/ /*dea*/
{     0x13a,0xc6,0xd6,-1,  -1,  -1,  -1,  -1,  0xce,0xde,-1,  -1, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*dec*/
{     0xca,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*dex*/
{     0x88,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*dey*/
{     -1,  0x45,0x55,-1, 0x152,0x41,0x51,0x449,0x4d,0x5d,0x59,-1, -1,  -1,  -1,  -1,-1,0x24f,0x25f,0x243,0x253,0x247,0x257,-1 },  /*eor*/
/*
{     0x11a,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },*/ /*ina*/
{     0x11a,0xe6,0xf6,-1,  -1,  -1,  -1,  -1,  0xee,0xfe,-1,  -1, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*inc*/
{     0xe8,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*inx*/
{     0xc8,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*iny*/
{     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  0x4c,-1,  -1,  -1, 0x6c,0x17c,-1,  -1,  -1,0x25c, -1,  -1,  -1,  -1,  -1,0x2dc},  /*jmp*/
{     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  0x20,-1,  -1,  -1,  -1, 0x2fc,-1,  -1,  -1,0x222, -1,  -1,  -1,  -1,  -1,  -1 },  /*jsr*/
{     -1,  0xa5,0xb5,-1, 0x1b2,0xa1,0xb1,0x4a9,0xad,0xbd,0xb9,-1, -1,  -1,  -1,  -1,-1,0x2af,0x2bf,0x2a3,0x2b3,0x2a7,0x2b7,-1 },  /*lda*/
{     -1,  0xa6,-1,  0xb6,-1,  -1,  -1, 0x8a2,0xae,-1,  0xbe,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*ldx*/
{     -1,  0xa4,0xb4,-1,  -1,  -1,  -1, 0x8a0,0xac,0xbc,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*ldy*/
{     0x4a,0x46,0x56,-1,  -1,  -1,  -1,  -1,  0x4e,0x5e,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*lsr*/
{     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  0x244,-1,  -1,  -1 ,-1,  -1,  -1,  -1, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*mvp*/
{     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  0x254,-1,  -1,  -1 ,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*mvn*/
{     0xea,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*nop*/
{     -1,  0x05,0x15,-1, 0x112,0x01,0x11,0x409,0x0d,0x1d,0x19,-1, -1,  -1,  -1,  -1,-1,0x20f,0x21f,0x203,0x213,0x207,0x217,-1 },  /*ora*/
{     0x48,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*pha*/
{     0x08,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*php*/
{     0x1da,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*phx*/
{     0x15a,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*phy*/
{     0x68,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*pla*/
{     0x28,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*plp*/
{     0x1fa,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*plx*/
{     0x17a,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*ply*/
{     0x28b,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, -1  ,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*phb*/
{     0x20b,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, -1  ,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*phd*/
{     0x24b,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, -1  ,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*phk*/
{     0x2ab,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, -1  ,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*plb*/
{     0x22b,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1, -1  ,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*pld*/
{     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  0x2f4,-1,  -1, -1  ,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*pea*/
{     -1,  -1,  -1,  -1,0x2d4, -1,  -1,  -1,  -1,  -1,  -1,  -1  ,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*pei*/
{     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1  ,-1,  -1,  -1,  -1, 0x262,-1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*per*/
{     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,0x107, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*rmb*/
{     0x2a,0x26,0x36,-1,  -1,  -1,  -1,  -1,  0x2e,0x3e,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*rol*/
{     0x6a,0x66,0x76,-1,  -1,  -1,  -1,  -1,  0x6e,0x7e,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*ror*/
{     0x40,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*rti*/
{     0x60,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*rts*/
{     -1,  -1,  -1,  -1,  -1,  -1,  -1, 0x2c2,-1,  -1,  -1,  -1  ,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*rep*/
{     0x26b,-1, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1  ,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*rtl*/
{     -1,  0xe5,0xf5,-1, 0x1f2,0xe1,0xf1,0x4e9,0xed,0xfd,0xf9,-1, -1,  -1,  -1,  -1,-1,0x2ef,0x2ff,0x2e3,0x2f3,0x2e7,0x2f7,-1 },  /*sbc*/
{     0x38,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*sec*/
{     0xf8,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*sed*/
{     0x78,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*sei*/
{     -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,0x187, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*smb*/
{     -1,  0x85,0x95,-1,  0x192,0x81,0x91,-1,  0x8d,0x9d,0x99,-1, -1,  -1,  -1,  -1,-1,0x28f,0x29f,0x283,0x293,0x287,0x297,-1 },  /*sta*/
{     -1,  0x86,-1,  0x96,-1,  -1,  -1,  -1,  0x8e,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*stx*/
{     -1,  0x84,0x94,-1,  -1,  -1,  -1,  -1,  0x8c,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*sty*/
{     -1,  0x164,0x174,-1, -1,  -1,  -1,  -1, 0x19c,0x19e,-1, -1, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*stz*/
{     -1,  -1,  -1,  -1,  -1,  -1,  -1, 0x2e2,-1,  -1,  -1,  -1  ,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*sep*/
{     0x2db,-1, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1  ,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*stp*/
{     0xaa,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*tax*/
{     0xa8,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*tay*/
{     -1,  0x114,-1,  -1,  -1,  -1,  -1, -1, 0x11c,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*trb*/
{     -1,  0x104,-1,  -1,  -1,  -1,  -1, -1, 0x10c,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*tsb*/
{     0xba,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*tsx*/
{     0x8a,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*txa*/
{     0x9a,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*txs*/
{     0x98,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*tya*/
{     0x29b,-1, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1  ,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*txy*/
{     0x2bb,-1, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1  ,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*tyx*/
{     0x25b,-1, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1  ,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*tcd*/
{     0x27b,-1, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1  ,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*tdc*/
{     0x21b,-1, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1  ,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*tcs*/
{     0x23b,-1, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1  ,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*tsc*/
{     0x2cb,-1, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1  ,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*wai*/
{     0x242,-1, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1  ,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*wdb*/
{     0x2eb,-1, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1  ,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 },  /*xba*/
{     0x2fb,-1, -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1  ,-1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1 }   /*xce*/


} ;

#define   Syntax    14
#define   Maxbyt    4

/* grouped syntaxes. each row = operand type, column = bytes allowed */
static int at[Syntax][Maxbyt] ={
{     0,   -1,  -1  ,-1 },	/* implied: no operand */
{     -1,  7,   -1  ,-1 },	/* immediate: single byte operand only */
{     -1,  15,  -1  ,-1 },	/* relative: single byte operand only */
{     -1,  -1,  14  ,-1 },	/* test'n'branch: two bytes only */
{     -1,  1,    8  ,17 },	/* addressing: 1 byte for zp,
					2 for absolute,
					3 for absolute long */
{     -1,  2,    9  ,18 },	/* ,x: same */
{     -1,  3,   10  ,-1 },	/* ,y: 1 byte for dp,y,
					2 for absolute,y */
{     -1,  4,   12  ,-1 },	/* (indirect): 1 byte for (dp),
					2 for (absolute) */
{     -1,  5,   13  ,-1 },	/* (i,x): 1 byte for (zp,x),
					2 for (a,x) */
{     -1,  6,   -1  ,-1 },	/* (i),y: 1 byte only */
{     -1,  21,  23  ,-1 },	/* (indirect long): 1 byte for (dp),
					2 for (a) */
{     -1,  22,  -1  ,-1 },	/* (indirect long),y: 1 byte only */
{     -1,  19,  -1  ,-1 },	/* stack relative: 1 byte only */
{     -1,  20,  -1  ,-1 }	/* SR (in),y: 1 byte only */
};

#define   AnzAlt    5

/* disambiguation table. for example, arbitrary instruction xxx $0000 could
	be either interpreted as an absolute operand, or possibly relative.
	note: does not look at comma or after, if present. */
static int xt[AnzAlt][2] ={ /* Alternativ Adr-Modes  */
{     8,   11 },      /* abs -> rel  */
{     2,   3  },      /* z,x -> z,y  */
{     5,   6  },      /* ,x) -> ),y  */
{     9,   10 },      /* a,x -> a,y  */

{     8,   16 }       /* abs -> relong */
};

/* cross check: instruction should be this many bytes long in total */
/* indexed by addressing mode */
static int le[] ={ 1,2,2,2,2,2,2,2,3,3,3,2,3,3,3,2,
                /* new modes */ 3,4,4,2,2,2,2,3 };

/* indicates absolute->zp optimizable addressing modes (abs->zp) */
/* indexed by addressing mode */
static int opt[] ={ -1,-1,-1,-1,-1,-1,-1,-1,1,2,3,-1,4,5,-1,-1,
           /*new*/ -1,8,9,-1,-1,-1,-1,-1 }; /* abs -> zp */

/*********************************************************************************************/
/* pass 1 */
int t_p1(signed char *s, signed char *t, int *ll, int *al)
{
     static int er,l,n,v,nk,na1,na2,bl,am,sy,i,label,byte; /*,j,v2 ;*/
     int afl = 0;
     int tlen;	/* token listing length, to adjust length that is returned */
     int inp;	/* input pointer in t[] */
     unsigned char cast;

/* notes and typical conventions ... er = error code
	am = addressing mode in use
*/

     cast='\0';
     bl=0;
     *al = 0;

/*     printf("\n"); */

     /* convert the next token from string s */
#ifdef DEBUG_AM
fprintf(stderr, "- p1 %d starting -\n", pc[segment]);
#endif
    
     /* As the t_p1 code below always works through the tokens
      * from t_conv in such a way that it always produces a shorter
      * result, the conversion below takes place "in place".
      * This, however, means that the original token sequence, which
      * would be useful for some assembler listing, is overwritten.
      * While the original assumption was ok for a constrained 
      * environment like the Atari ST, this is no longer true.
      * Converting the code below to have separate input and output
      * areas would be error-prone, so we do some copy-magic here
      * instead...*/
     /* we keep three bytes buffer for "T_LISTING" and the length of the
      * token list
      */
     t[0]=T_LISTING;
     er=t_conv(s,t+6,&l,pc[segment],&nk,&na1,&na2,0,&byte);
     tlen = l+6;
     t[1]=tlen&255;
     t[2]=(tlen>>8)&255;
     t[3]=segment;
     t[4]=pc[segment]&255;
     t[5]=(pc[segment]>>8)&255;
     /* now we have to duplicate the token sequence from the T_LISTING buffer
      * to the end of "t", so we can then in-place convert it
      * below. Non-overlapping, size is known in advance, so 
      * using memcpy is fine here
      */
     inp = 0;
     /* discard label definitions before copying the buffer, so we don't get
      * label defined errors */
     while (inp<l && t[6+inp]==T_DEFINE) {
	inp+=3;
     }
     /* copy the buffer;
      * t+tlen is directly after the T_LISTING buffer
      * t+6+inp is the start of the T_LISTING buffer, after label defines
      * l-inp is the length of the T_LISTING buffer, without label defines
      */
     memcpy(t+tlen, t+6+inp, l-inp);

#ifdef DEBUG_CONV
     printf("t_conv s:%s\n",s);
     printf("t_conv (er=%d, t=%p, l=%d, tlen=%d, inp=%d):",er, t, l, tlen, inp);
     for(i=0;i<l;i++)
          printf("%02x,",t[i+6] & 0xff);
     printf("\n");
#endif

     // update pointers
     t=t+tlen;
     l-=inp;
     /* the result of this is that we always have a Klisting entry in the buffer
      * for each tokenization call */
     /* here continue as before, except for adjusting the returne *ll length 
      * in the end, just before return */

     /* return length default is input length */
     *ll=l;

     /* if text/data produced, then no more fopt allowed in romable mode */
     /* TODO: need to check, Kbyte is being remapped to Kbyt. What is the effect here? */
     if((romable>1) && (t[inp]<Kopen || t[inp]==Kbyte || t[inp]==Kpcdef)) {
       afile->base[SEG_TEXT] = pc[SEG_TEXT] = romaddr + h_length();
       romable=1;
     }
     if(!er)
     {

/*
 *
 * pseudo-op dispatch (except .byt, .asc)
 *
 */
	  // fix sign
          n=t[0]; // & 0xff;

	  /* TODO: make that a big switch statement... */
	  /* maybe later. Cameron */

	  if(n==Kend || n==Klist || n==Kxlist) {
	    *ll = 0;		/* ignore */
	  } else
	  if(n==Kinclude) {
	    *ll = 0;		/* no output length */
	    i=1;
            if(t[i]=='\"') {
	       int k,j=0;
	       char binfname[255];
               i++;
               k=t[i]+i+1;
               i++;
               while(i<k && !er) {
                 binfname[j++] = t[i++];
                 if (j > 255)
                    er = E_NOMEM; /* buffer overflow */
               }
               binfname[j] = '\0';
	       er=icl_open(binfname);
	    } else {
	       er=E_SYNTAX;
	    }
	  } else
	  if(n==Kfopt) {
	    if(romable==1) er=E_ROMOPT;
	    t[0] = Kbyt;
	    set_fopt(l,t,nk+1-na1+na2);
	    *ll = 0;
	  } else
          if(n==Klistbytes) {
	    int p = 0;
            if(!(er=a_term(t+1,&p,&l,pc[segment],&afl,&label,0))) {
                er=E_OKDEF;
	    }
	    *ll = 3;
	    t[0] = Klistbytes;
	    t[1] = p & 0xff;
	    t[2] = (p >> 8) & 0xff;
	    //printf("Klistbytes p1: er=%d, l=%d\n", er, l);
          } else
          if(n==Kpcdef)
          {
	       int tmp;
	       // get parameter for *=
	       er=a_term(t+1,&tmp,&l,pc[segment],&afl,&label,0);
	       // found?
               if(!er)
               {
                    i=1;
                    wval(i,tmp, 0);	/* writes T_VALUE, 3 bytes value, plus one byte */
                    t[i++]=T_END;
                    *ll=7;
                    er=E_OKDEF;
#ifdef DEBUG_RELOC
printf("set pc=%04x, oldsegment=%d, pc[segm]=%04x, ", 
				pc[SEG_ABS], segment, pc[segment]);
printf(" wrote %02x %02x %02x %02x %02x %02x, %02x, %02x\n",
				t[0],t[1],t[2],t[3],t[4],t[5],t[6],t[7]);
#endif
		    if(segment==SEG_TEXT) {
		      pc[SEG_ABS] = tmp;
		      r_mode(RMODE_ABS);
		    } else {
		      if(!relmode) {
		        pc[segment] = tmp;
		      } else {
			er = E_ILLSEGMENT;
		      }
		    }
/*printf("newsegment=%d, pc[ABS]=%04x\n", segment, pc[SEG_ABS]);*/
               } else {
		 // no param found, only "*=". 
		 // if we ABS, we switch back to reloc
#ifdef DEBUG_RELOC
printf("reloc: er=%d, l=%d, segment=%d, pc[%d]=%04x, pc[abs(%d)]=%04x, pc[text(%d)]=%04x\n",
			er, l, segment, segment, pc[segment], SEG_ABS, pc[SEG_ABS],SEG_TEXT, pc[SEG_TEXT]);
#endif
	         if((segment==SEG_ABS) && (er==E_SYNTAX && l==0)) {
		   t[0]=Kreloc;
		   i=1;
		   wval(i,pc[SEG_TEXT], 0);
		   t[i++]=T_END;
		   *ll=7;
	  	   er=E_OKDEF;
		   r_mode(RMODE_RELOC);
/*printf("     : newseg=%d, pc[newseg]=%04x, pc[abs]=%04x, pc[text]=%04x\n",
			segment, pc[segment], pc[SEG_ABS], pc[SEG_TEXT]);*/
	         }
	       }
          } else
          if(n==Kopen)
          {
	       if(showblk) fprintf(stderr, "%s line %d: .(\n", pp_getidat()->fname, pp_getidat()->fline);
               b_open();
               er=E_NOLINE;
          } else
          if(n==Kclose)
          {
	       if(showblk) fprintf(stderr, "%s line %d: .)\n", pp_getidat()->fname, pp_getidat()->fline);
               er=b_close();
               if(!er) er=E_NOLINE;
          } else
          if(n==Kalong)
          {
		if (!w65816) {
			er=E_65816;
		} else {
               memode=1;
               t[0]=Kalong;
               *ll=1;
               er=E_OKDEF;
		}
          } else
          if(n==Kashort)
          {
               memode=0;
               t[0]=Kashort;
               *ll=1;
               er=E_OKDEF;
          } else
          if(n==Kxlong)
          {
		if (!w65816) {
			er=E_65816;
		} else {
               xmode=1;
               t[0]=Kxlong;
               *ll=1;
               er=E_OKDEF;
		}
          } else
          if(n==Kxshort)
          {
               xmode=0;
               t[0]=Kxshort;
               *ll=1;
               er=E_OKDEF;
          } else
          if(n==Kdsb)
          {
	       dsb_len = 1;
               if(!(er=a_term(t+1,&bl,&l,pc[segment],&afl,&label,0))) {
                    er=E_OKDEF;
	       }
	       dsb_len = 0;
          } else
	  if(n==Ktext) {
	      r_mode(RMODE_RELOC); // use of segments restores previous segment / reloc mode
	      segment = relmode ? SEG_TEXT : SEG_ABS;
	      t[0]=Ksegment;
	      t[1]=segment;
	      *ll=2;
              er=E_OKDEF;
	  } else
	  if(n==Kdata) {
  	    if(relmode) {   
	      r_mode(RMODE_RELOC); // use of segments restores previous segment / reloc mode
	      segment = SEG_DATA;
	      t[0]=Ksegment;
	      t[1]=SEG_DATA;
	      *ll=2;
              er=E_OKDEF;
	    } else {
	      er=E_ILLSEGMENT;
	    } 
	  } else
	  if(n==Kbss) {
  	    if(relmode) { 
	      r_mode(RMODE_RELOC); // use of segments restores previous segment / reloc mode
	      segment = SEG_BSS;
	      t[0]=Ksegment;
	      t[1]=SEG_BSS;
	      *ll=2;
              er=E_OKDEF;
	    } else {
	      er=E_ILLSEGMENT;
	    } 
	  } else
	  if(n==Kzero) {
  	    if(relmode) {   
	      r_mode(RMODE_RELOC); // use of segments restores previous segment / reloc mode
	      segment = SEG_ZERO;
	      t[0]=Ksegment;
	      t[1]=SEG_ZERO;
	      *ll=2;
              er=E_OKDEF;
	    } else {
	      er=E_ILLSEGMENT;
	    }  
	  } else
	if (n==Kassert) { /* ignore this in first pass, just check syntax */
		int x;
		i = 1;

                /* XXX: sadly, can't implement unary logical not yet */
		if(!(er=a_term(t+i,&x,&l,pc[segment],&afl,&label,1))) {
			i += l;
		}
		if(t[i] == ',') { /* skip comma */
			i++;
		} else {
			er = E_SYNTAX;
		}
		/* get filename.
		   the tokenizer can either see it as a multichar string ... */
		if (!er) {
		   int k;
		
		   if(t[i]=='\"') {
			i++;
			k=t[i]+i+1;
			i++;
			while(i<k && !er) { i++; }
		/* or as a 'char' if it's a single character ("word" would
			have been caught by the above) */
		    } else
			if(!(er=a_term(t+i,&x,&l,pc[segment],&afl,&label,1))) {
			i += l;
		    }
		}

		/* two arguments only please */
		if (!er && t[i] != T_END && t[i] != T_COMMENT) {
			er = E_SYNTAX;
		}
		if (!er) {
			/* pass parameters back to xa.c */
			*ll=i+1;
			bl=0; /* zero length */
			er = E_OKDEF; /* defer to pass 2 */
		}
	} else
	if (n==Kbin) {
		int j;
		int l;

		/* this first pass just calculates a prospective length
			for pass 2. */
		char binfnam[255];
		int offset;
		int length;

		i = 1;
		j = 0;

		/* get offset */
		if(!(er=a_term(t+i,&offset,&l,pc[segment],&afl,&label,1))) {
			i += l;
		}
		if (offset < 0)
			er = E_ILLQUANT;
		if(t[i] == ',') { /* skip comma */
			i++;
		} else {
			er = E_SYNTAX;
		}

		/* get length */
		if (!er &&
			!(er=a_term(t+i,&length,&l,pc[segment],&afl,&label,1)))
		{
			i += l;
		}
		if (length < 0)
			er = E_ILLQUANT;
		if(t[i] == ',') { /* skip comma */
			i++;
		} else {
			er = E_SYNTAX;
		}

		/* get filename.
		   the tokenizer can either see it as a multichar string ... */
		if (!er) {
		   int k;
		
		   //fstart = i;
		   if(t[i]=='\"') {
			i++;
			k=t[i]+i+1;
			i++;
			while(i<k && !er) {
				binfnam[j++] = t[i++];
				if (j > 255)
					er = E_NOMEM; /* buffer overflow */
			}
			binfnam[j] = '\0';
		/* or as a 'char' if it's a single character ("word" would
			have been caught by the above) */
		    } else
			if(!(er=a_term(t+i,&v,&l,pc[segment],&afl,&label,1))) {
			binfnam[0] = v;
			binfnam[1] = '\0';
			i += l;
		    }
		}

		/* three arguments only please */
		if (!er && t[i] != T_END && t[i] != T_COMMENT) {
			er = E_SYNTAX;
		}

		if (!er) {
			FILE *foo;

#ifdef DEBUG_AM
			fprintf(stderr,
"binclude1 offset = %i len = %i filename = %s endchar = %i\n",
		offset, length, binfnam, i);
#endif
			if (!(foo = fopen(binfnam, "rb"))) {
				er = E_FNF;
			} else {
				fseek(foo, 0, SEEK_END);
				if ((length+offset) > ftell(foo)) {
					er = E_OUTOFDATA;
				} else {
					length = (length) ? length :
						(ftell(foo)-offset);
				}
				fclose(foo);
			}
			if (!er) {
				if (length > 65535 && !w65816) {
					errout(W_OVER64K);
				} else if (length > 16777215) {
					errout(W_OVER16M);
				}
				/* pass parameters back to xa.c */
				*ll=i+1;
/*
				bl=length+2;
*/
				bl=length;
				er = E_OKDEF; /* defer to pass 2 */
			}
		}
	} else
	  if(n==Kalign) {
	    int tmp;
	    if(segment!=SEG_ABS) {
              if(!(er=a_term(t+1,&tmp,&l,pc[segment],&afl,&label,0))) {
		if(tmp == 1 || tmp == 2 || tmp == 4 || tmp == 256) {
		  set_align(tmp);
		  if(pc[segment] & (tmp-1)) { /* not aligned */
		    int tmp2;
		    t[0]=Kdsb;
		    i=1;
		    bl=tmp=(tmp - (pc[segment] & (tmp-1))) & (tmp-1);
		    wval(i,tmp, 0);
                    t[i++]=',';
		    tmp2= 0xea;
		    wval(i,tmp2, 0);	/* nop opcode */
                    t[i++]=T_END;
		    *ll=9;
		    er=E_OKDEF;
		  } else {
		    *ll=0;	/* ignore if aligned right */
		  }
		} else {
		  er=E_ILLALIGN;
		}
	      }
	    } else {
	      er=E_ILLSEGMENT;
	    }
	  } else
            /* optimization okay on pass 1: use 0 for fl */
		{
#ifdef DEBUG_AM
fprintf(stderr, "E_OK ... t_p2 xat.c %i %i\n", t[0], *ll);
#endif
	       /* this actually calls pass2 on the current tokenization stream,
 		* but without including the Klisting token listing */
               er=t_p2(t,ll,(0 | byte), al);
#ifdef DEBUG_AM
fprintf(stderr, "... --> er=%d\n", er);
#endif
	}
          
     } else
     if(er==E_NODEF)
     {

     /*
      * no label was found from t_conv!
      * try to figure out most likely length
      *
      */

#ifdef DEBUG_AM
fprintf(stderr, "E_NODEF pass1 xat.c\n");
#endif
	er = E_OK; /* stuff error */
          n=t[0];	/* look at first token */

	/* mnemonic dispatch -- abbreviated form in t_p2, but changed here
		to not do anything other than 24-bit optimization since we
		don't know the value of the label */

		/* choose addressing mode; add commas found */

          if(n>=0 && n<=Lastbef && n != Kmvn && n != Kmvp) /* not for mvn/p */
          {
	       int inp = 1;	/* input pointer */

               if(t[inp]==T_END || t[inp]==T_COMMENT)
               {
                    sy=0;	/* implied */
		    inp++;
               } else
               if(t[inp]=='#')
               {
                    sy=1+nk;	/* immediate */
		    inp++;
               } else
               if(t[inp]=='(')
               {
                    sy=7+nk;	/* computed */
		    inp++;
               } else {
                    sy=4+nk;	/* absolute or zero page */
	       }

	       /* this actually finds the cast for all addressing modes,
 		  but t_conv() only puts it there for immediate (#) or absolute/
		  absolute indexed addressing modes */
	       if (t[inp] == T_CAST) {
		    inp++;
		    cast = t[inp];
		    inp++;
#ifdef DEBUG_CAST
	printf("Found cast to: %c\n", cast);
#endif
	       }

	       /* length counter set to maximum length + 1 */
	       if (w65816 || (t[l-1]=='@' || t[l-1] == '!')) {
		       	/* for 65816 allow addressing modes up to 4 byte overall length */
               		bl=Maxbyt+1;
	       } else {
		       	/* for other modes only check for addressing modes up to 3 byte overall length */
		 	bl=Maxbyt;
	       }
               
		/* find best fit for length of this operand */
               while(--bl)
               {

		/* look at syntax table (at) using syntax (sy) as index.
			is there an addressing mode for an operand
			of this length? am = addressing mode */

                    if((am=at[sy][bl-1])>=0)
                    {
                         if(am>Admodes-1) /* no, it's -1, syntax error */
                         {
                              er=E_SYNTAX;
                              break;
                         }
                         if(ct[n][am]>=0) /* yes, valid token *and* mode,
						so we're done */
                              break;

			/* no valid mode for this token, see if it's something
				ambiguous; if so, try to interpret in that
				context. */
                         for(v=0;v<AnzAlt;v++)
                              if(xt[v][0]==am && ct[n][xt[v][1]]>=0)
                                   break;
                         if(v<AnzAlt) /* got a match for another context */
                         {
                              am=xt[v][1];
                              break;
                         }
                    }
               }

		/* optimize operand length for 24-bit quantities */
		/* look at cast byte from t_conv */

               if (cast!='@' && cast!= '!')
               {
                     if(bl && !er && opt[am]>=0 && am>16) /* <<< NOTE! */
                          if(ct[n][opt[am]]>=0)
                               am=opt[am];
               }
		/* if ` is declared, force further optimization */
		if (cast=='`') {
			if (opt[am]<0 || ct[n][opt[am]]<0)
				errout(E_ADRESS);
			am=opt[am];
		}
		/* if ! is declared, force to 16-bit quantity */
		if (cast=='!' && am>16 && opt[am]>=0 && bl) {
			am=opt[am];
		}

		/* couldn't match anything for this opcode */
               if(!bl)
                    er=E_SYNTAX;
               else {
		/* ok, get length of instruction */
                    bl=le[am];
		/* and add one for 65816 special instruction modes */
                    if( ((ct[n][am]&0x400) && memode) ||
			((ct[n][am]&0x800) && xmode)) {
                          bl++;
			}
                }


		if (er == E_NODEF)
			er = E_OK;

		/* .byt, .asc, .word, .dsb, .fopt pseudo-op dispatch */

          } else
	  if(n==Kimportzp) {
	    int i;
	    *ll=0;		/* no output */
	    bl = 0;		/* no output length */
	    /* import labels; next follow a comma-separated list of labels that are
 	       imported. Tokenizer has already created label entries, we only need to
	       set the flags appropriately */
	    i=1;
/*printf("Kimport: t[i]=%d\n",t[i]);*/
	    while(t[i]==T_LABEL) {
		int n = (t[i+1] & 255) | (t[i+2] << 8); 	/* label number */
/*printf("lg_import: %d\n",n);*/
		lg_importzp(n);
		i+=3;
		while (t[i]==' ') i++;
		if (t[i]!=',') break;
		i++;
		while (t[i]==' ') i++;
	    }
	    er=E_NOLINE;
	  } else
	  if(n==Kimport) {
	    int i;
	    *ll=0;		/* no output */
	    bl = 0;		/* no output length */
	    /* import labels; next follow a comma-separated list of labels that are
 	       imported. Tokenizer has already created label entries, we only need to
	       set the flags appropriately */
	    i=1;
/*printf("Kimport: t[i]=%d\n",t[i]);*/
	    while(t[i]==T_LABEL) {
		int n = (t[i+1] & 255) | (t[i+2] << 8); 	/* label number */
/*printf("lg_import: %d\n",n);*/
		lg_import(n);
		i+=3;
		while (t[i]==' ') i++;
		if (t[i]!=',') break;
		i++;
		while (t[i]==' ') i++;
	    }
	    er=E_NOLINE;
	  } else
	  if(n==Kmvn || n==Kmvp)
	  {
               bl=3;
		if (!w65816) er = E_65816;
	  } else
          if(n==Kbyt || n==Kasc || n==Kaasc)
          {
#ifdef DEBUG_AM
fprintf(stderr, "byt pass 1 %i\n", nk+1-na1+na2);
#endif
               bl=nk+1-na1+na2;
          } else
          if(n==Kword)
          {
               bl=2*nk+2;
          } else
          if(n==Kdsb)
          {
               er=a_term(t+1,&bl,&l,pc[segment],&afl,&label,0);
          } else
	  if(n==Kfopt) 
	  {
	    set_fopt(l-1,t+1, nk+1-na1+na2);
	    *ll = 0;
	  } else
          if(n==T_OP)
          {
               er=E_OKDEF;
          } else
               er=E_NODEF;
          
          if(!er)
               er=E_OKDEF;
#ifdef DEBUG_AM
fprintf(stderr, "guessing instruction length is %d\n", bl);
#endif
     }
     if(er==E_NOLINE)
     {
          er=E_OK;
          *ll=0;
     }

     *al += bl;
     pc[segment]+=bl;
     if(segment==SEG_TEXT) pc[SEG_ABS]+=bl;
     if(segment==SEG_ABS) pc[SEG_TEXT]+=bl;

     /* adjust length by token listing buffer length */
#ifdef DEBUG_CONV 
     printf("converted: (er=%d, t=%p, ll=%d, tlen=%d):",er, t, *ll, tlen);
     for(i=0;i<*ll;i++)
          printf("%02x,",t[i] & 0xff);
     printf("\n");
     printf("adjusted len=%d\n", *ll+tlen);
#endif

     *ll = *ll + tlen;
     return(er);
}

/*********************************************************************************************/
/* t_pass 2
 *
 * *t is the token list as given from pass1
 * *ll is the returned length of bytes (doubles as 
 *     input for whether OK or OKDEF status from pass1)
 * fl defines if we allow zeropage optimization
 *
 * Conversion takes place "in place" in the *t array.
 */

/**
 * function called from the main loop, where "only" the
 * undefined labels have to be resolved and the affected 
 * opcodes are assembled, the rest is passed through from
 * pass1 (pass-through is done in t_p2, when *ll<0)
 * As this is not called from p1, assume that we do not
 * do length optimization
 *
 * *t	is the input token list
 * *ll	is the input length of the token list,
 * 	and the output of how many bytes of the buffer are to be taken
 * 	into the file; note that for .dsb and .bin, this does NOT match
 * 	the length in the internal data structures!
 */
int t_p2_l(signed char *t, int *ll, int *al)
{
	int er = E_OK;
	int l = *ll;

	if (l < 0) l = -l;

#if 0
     {
        printf("t_p2_l (ll=%d, t=%p):", *ll, t);
        for(int i=0;i<l;i++)
          printf("%02x,",t[i] & 0xff);
        printf("\n");
     }
#endif


	if (t[0] == T_LISTING) {
	    int tlen;
	    tlen=((t[2]&255)<<8) | (t[1]&255);
	    if (*ll<0) {
	    	*ll=(*ll) + tlen;
	    } else {
	    	*ll=(*ll) - tlen;
	    }

	    if (tlen > l) 
     	    {
		int i;

		// that is corrupt data and should not happen
		list_flush();
        	printf("corrupt: t_p2_l (l=%d, tlen=%d, ll=%d, t=%p):", l, tlen, *ll, t);
        	for(i=0;i<l;i++)
          	printf("%02x,",t[i] & 0xff);
        	printf("\n");
     	    }

	    if (*ll != 0) {
  	    	er = t_p2(t+tlen, ll, 1, al);
	    }

	    /* do the actual listing (*ll-2 as we need to substract the place for the tlen value) */
	    do_listing(t+3, tlen-3, t+tlen, *ll);

	    // adapt back, i.e. remove token listing 
	    // Use the input token length as delimiter.
	    if (*ll != 0) {
	 	memmove(t, t+tlen, l-tlen);
	    }

	} else {
	  er = t_p2(t, ll, 1, al);
	}
	return er;
}

/**
 * This method does not handle a token list. Thus it
 * is called internally from pass1 without the token listing, and 
 * from the t_p2_l() method that strips the token listing 
 * as well
 *
 * *t	is the input token list
 * *ll	is the input length of the token list,
 * 	and the output of how many bytes of the buffer are to be taken
 * 	into the file
 * fl	when set, do not do length optimization, when not set,
 * 	allow length optimization (when called from p1)
 */
int t_p2(signed char *t, int *ll, int fl, int *al)
{
     static int afl,nafl, i,j,k,er,v,n,l,bl,sy,am,c,vv[3],v2,label;
     static int rlt[3];	/* relocation table */
     static int lab[3];	/* undef. label table */


     er=E_OK;
     bl=0;
     if(*ll<0) /* <0 when E_OK, >0 when E_OKDEF     */
     {
          *ll=-*ll;
          bl=*ll;
          er=E_OK;
	
     } else
     {
          n=t[0];
          if(n==T_OP)
          {
               n=cval(t+1);
               er=a_term(t+4,&v,&l,pc[segment],&nafl,&label,0);

               if(!er)
               {
                    if(t[3]=='=')
                    {
                      v2=v;
                    } else {
                      if( (!(er=l_get(n,&v2, &afl))) 
				&& ((afl & A_FMASK)!=(SEG_UNDEF<<8)) 
				&& ((afl & A_FMASK)!=(SEG_UNDEFZP<<8)) )
                      {
                         if(t[3]=='+')
                         {
			      if(afl && nafl) { errout(E_WPOINTER); nafl=0; }
			      nafl = afl;
                              v2+=v;
                         } else
                         if(t[3]=='-')
                         {	
			      if( (((nafl & A_FMASK)>>8) != afl) 
					|| ((nafl & A_MASK)==A_HIGH) ) {
			        errout(E_WPOINTER); 
				nafl=0; 
			      } else {
				nafl = afl;
			      }
                              v2-=v;
                         } else
                         if(t[3]=='*')
                         {
			      if(afl || nafl) { errout(E_WPOINTER); nafl=0; }
                              v2*=v;
                         } else
                         if(t[3]=='/')
                         {
			      if(afl || nafl) { errout(E_WPOINTER); nafl=0; }
                              if(v)
                                   v2/=v;
                              else
                                   er=E_DIV;
                         } else
                         if(t[3]=='|')
                         {
			      if(afl || nafl) { errout(E_WPOINTER); nafl=0; }
                              v2=v|v2;
                         } else
                         if(t[3]=='&')
                         {
			      if(afl || nafl) { errout(E_WPOINTER); nafl=0; }
                              v2=v2&v;
                         }
                      }
		    }
                    l_set(n,v2,nafl>>8);	

                    *ll=0;
                    if(!er)
                         er=E_NOLINE;
               }
          } else
          if(n==Kword)
          {
               i=1;
               j=0;
               while(!er && t[i]!=T_END && t[i] != T_COMMENT)
               {
                    if(!(er=a_term(t+i,&v,&l,pc[segment],&afl,&label,1)))
                    {   
/*if(afl) printf("relocation 1 %04x at pc=$%04x, value now =$%04x\n",
							afl,pc[segment],v); */
			 if(afl) u_set(pc[segment]+j, afl, label, 2);
                         t[j++]=v&255;
                         t[j++]=(v>>8)&255;

                         i+=l;     
                         if(t[i]!=T_END && t[i] != T_COMMENT && t[i]!=',')
                              er=E_SYNTAX;
                         else
                         if(t[i]==',')
                              i++;

                    }
               }
               *ll=j;
               bl=j;
          } else
          if (n == Kassert)
          {
		int result = 0;
		int c;
		i = 1;

		/* this time, actually check something */
		if(!(er=a_term(t+i,&result,&l,pc[segment],&afl,&label,1))) {
			i += l;
		}
		if(t[i] == ',') { /* skip comma */
			i++;
		} else {
			er = E_SYNTAX;
		}
		/* get filename.
		   the tokenizer can either see it as a multichar string ... */
		if (!er) {
		   int k;

		   if (!result)
			fprintf(stderr, "Assertion failed: ");
		   if(t[i]=='\"') {
			i++;
			k=t[i]+i+1;
			i++;
			while(i<k && !er) {
				if (!result)
					fprintf(stderr, "%c", t[i]);
				i++;
			}
		/* or as a 'char' if it's a single character ("word" would
			have been caught by the above) */
		    } else
			if(!(er=a_term(t+i,&c,&l,pc[segment],&afl,&label,1))) {
			if (!result) fprintf(stderr, "%c", c);
			i += l;
		    }
		}

		/* two arguments only please */
		if (!er && !result && t[i] != T_END && t[i] != T_COMMENT) {
			er = E_SYNTAX;
		}
		if (!er && !result) {
			fprintf(stderr, "\n");
			return E_AERROR; /* assertion failed, fail now */
		}
		*ll = 0;
		bl = 0;
          } else
          if (n == Kbin)
          {
		int j;
		int l;

		/* figure out our parameters again. repeat most of
			the error checking since we might not be over
			the total number of bogosities */
		char binfnam[255];
		int offset;
		int length;
		int fstart;
		int flen;

		i = 1;
		j = 0;
		flen = 0;

		/* get offset */
		if(!(er=a_term(t+i,&offset,&l,pc[segment],&afl,&label,1))) {
			i += l;
		}
		if (offset < 0)
			er = E_ILLQUANT;
		if(t[i] == ',') { /* skip comma */
			i++;
		} else {
			er = E_SYNTAX;
		}

		/* get length */
		if (!er &&
			!(er=a_term(t+i,&length,&l,pc[segment],&afl,&label,1)))
		{
			i += l;
		}
		if (length < 0)
			er = E_ILLQUANT;
		if(t[i] == ',') { /* skip comma */
			i++;
		} else {
			er = E_SYNTAX;
		}

		/* get filename.
		   the tokenizer can either see it as a multichar string ... */
		if (!er) {
		   int k;
		
		   fstart = i;
		   if(t[i]=='\"') {
			i++;
			k=t[i]+i+1;
			i++;
			while(i<k && !er) {
				binfnam[j++] = t[i++];
				if (j > 255)
					er = E_NOMEM; /* buffer overflow */
			}
			binfnam[j] = '\0';
			flen = j;
		/* or as a 'char' if it's a single character ("word" would
			have been caught by the above) */
		    } else
			if(!(er=a_term(t+i,&v,&l,pc[segment],&afl,&label,1))) {
			binfnam[0] = v;
			binfnam[1] = '\0';
			i += l;
			flen = 1;
		    }
		}

		/* three arguments only please */
		if (!er && t[i] != T_END && t[i] != T_COMMENT) {
			er = E_SYNTAX;
		}

		if (!er) {
			FILE *foo;

#ifdef DEBUG_AM
			fprintf(stderr,
"binclude2 offset = %i len = %i filename = %s endchar = %i\n",
		offset, length, binfnam, i);
#endif
			if (!(foo = fopen(binfnam, "rb"))) {
				er = E_FNF;
			} else {
				fseek(foo, 0, SEEK_END);
				if ((length+offset) > ftell(foo)) {
					er = E_OUTOFDATA;
				} else {
					length = (length) ? length :
						(ftell(foo)-offset);
				}
				fclose(foo);
			}
			if (!er) {
				if (length > 65535 && !w65816) {
					errout(W_OVER64K);
				} else if (length > 16777215) {
					errout(W_OVER16M);
				}
				/* pass parameters back to xa.c */
				*ll=length;
/*
				bl=length+2;
*/
				bl=length;
				t[0] = offset & 255;
				t[1] = (offset >> 8) & 255;
				t[2] = (offset >> 16) & 255;
				/* God help us if the index is > 65535 */
				t[3] = fstart & 255;
				t[4] = (fstart >> 8) & 255;
				t[5] = flen; /* to massage 'char' types */
				er = E_BIN;
			}
		}
	} else
	if (n==Kmvn || n==Kmvp)
	{
	/* special case these instructions' syntax */
		int wide=0;
		i=1;
		j=1;
		/* write opcode */
		t[0] = ((n == Kmvp) ? 0x44 : 0x54);
		while(!er && t[i]!=T_END && t[i]!=T_COMMENT)
		{
			if (wide) /* oops */
				er = E_SYNTAX;
#ifdef DEBUG_AM
fprintf(stderr, "mvn mvp: %i %i %i %i %i\n", t[0], t[i], wide, i, j);
#endif
			if(!(er=a_term(t+i,&v,&l,pc[segment],&afl,&label,1)))
			{   
/*if(afl) printf("relocation 1 %04x at pc=$%04x, value now =$%04x\n",
							afl,pc[segment],v); */
				if(afl) u_set(pc[segment]+j, afl, label, 2);
				i+=l;     
				if (v & 0xff00)
					er=E_ILLQUANT;
				else
					t[j++]=v;
			}
			if (j > 3)
				er=E_SYNTAX;
			if(t[i]!=T_END && t[i]!=T_COMMENT && t[i]!=',')
				er=E_SYNTAX;
			else
			if(t[i]==',')
                              i++;
		}
		if (j != 3) er = E_SYNTAX; /* oops */

		/* before we leave, swap the bytes. although disassembled as
			mv? src,dest it's actually represented as
			mv? $ddss -- see 
			http://6502org.wikidot.com/software-65816-memorymove */
		i = t[2];
		t[2] = t[1];
		t[1] = i;

		*ll = j;
		bl = j;
		if (!w65816) er = E_65816;
	} else if(n==Kasc || n==Kbyt || n==Kaasc) {
               i=1;
               j=0;
               while(!er && t[i]!=T_END && t[i] != T_COMMENT)
               {
                    if(t[i]=='\"')
                    {
                         i++;
                         k=t[i]+i+1;
                         i++;
                         while(i<k)
                              t[j++]=t[i++];
                    } else
                    {
                         if(!(er=a_term(t+i,&v,&l,pc[segment],&afl,&label,1)))
                         {
/*if(afl) printf("relocation 2 %04x at pc=$%04x, value now =$%04x\n",afl,pc[segment]+j,v); */
			      if(afl) u_set(pc[segment]+j, afl, label, 1);
                              if(v&0xff00)
                                   er=E_OVERFLOW;
                              else
                              {
                                   t[j++]=v;                        
                                   i+=l;     
                              }
                         }
                    }
                    if(t[i]!=T_END && t[i] != T_COMMENT && t[i]!=',')
                         er=E_SYNTAX;
                    else
                         if(t[i]==',')
                              i++;
               }
               *ll=j;
               bl=j;
          } else
          if(n==Kalong)
          {
               memode=1;
               *ll=0;
          } else
          if(n==Kashort)
          {
               memode=0;
               *ll=0;
          } else
          if(n==Kxlong)
          {
               xmode=1;
               *ll=0;
          } else
          if(n==Kxshort)
          {
               xmode=0;
               *ll=0;
          } else
          if(n==Kpcdef)
          {
	       int npc;
               er=a_term(t+1,&npc,&l,pc[segment],&afl,&label,0);
               bl=0;     
               *ll=0;
	       if(segment==SEG_TEXT) {
	         r_mode(RMODE_ABS);
	       }
	       pc[segment] = npc;
          } else
          if(n==Kreloc) {
	       int npc;
               er=a_term(t+1,&npc,&l,pc[segment],&afl,&label,0);
/*printf("Kreloc: segment=%d, pc[seg]=%04x\n", segment, pc[segment]);*/
               bl=0;     
               *ll=0;
	       r_mode(RMODE_RELOC);
	       pc[segment] = npc;
/*printf("Kreloc: newsegment=%d, pc[seg]=%04x\n", segment, pc[segment]);*/
	  } else
	  if(n==Klistbytes) {
	       int nbytes = (t[1] & 0xff) + (t[2] << 8);
	       //printf("Klistbytes --> er=%d, nbytes=%d\n", er, nbytes);
	       list_setbytes(nbytes);
	       l = 2;
	       *ll=0;
	       bl =0;
	  } else
	  if(n==Ksegment) {
	       segment = t[1];
	       *ll=0;
	       bl =0;
	  } else
          if(n==Kdsb)
          {
	       dsb_len = 1;
               if(!(er=a_term(t+1,&j,&i,pc[segment],&afl,&label,0)))
               {
                    if (j<0)
			er=E_NEGDSBLEN;
		    else
/*
                    if(t[i+1]!=',')
                         er=E_SYNTAX;
                    else
*/
/*
		    if((segment!=SEG_ABS) && afl) 
			 er=E_ILLPOINTER;
		    else
*/
                    {
			 dsb_len = 0;

			 if(t[i+1]==',') {
                           er=a_term(t+2+i,&v,&l,pc[segment],&afl,&label,0);
			 } else {
			   v=0;
			 }
                         if(!er && v>>8)
                              er=E_OVERFLOW;
                         t[0]=v&255;
                         if(!er)
                         {
                              *ll=j;
                              bl=j;
#ifdef DEBUG_AM
fprintf(stderr, "Kdsb E_DSB %i\n", j);
#endif
                              er=E_DSB;
                         }
                    }
                    if(!er)
                         bl=j;
               }
	       dsb_len = 0;
          } else
          if(n>=0 && n<=Lastbef)
          {
	       int inp = 1;		/* input pointer */
	       signed char cast = '\0';	/* cast value */

	       c = t[inp];

               if(c=='#')
               {
                    inp++;
		    if (t[inp] == T_CAST) {
			inp++;
			cast = t[inp];
			inp++;
#ifdef DEBUG_CAST
	printf("Found cast to (2): %c\n", cast);
#endif
		    }
                    sy=1;
                    if(!(er=a_term(t+inp,vv,&l,pc[segment],&afl,&label,1)))
                    {
/* if(1) printf("a_term returns afl=%04x\n",afl); */

			 rlt[0] = afl;
			 lab[0] = label;
                         inp+=l;
                         if(t[inp]!=T_END && t[inp] != T_COMMENT)
                         {
                              if(t[inp]!=',')
                                   er=E_SYNTAX;
                              else
                              {
                                   inp++;
                                   sy++;
                                   if(!(er=a_term(t+inp,vv+1,&l,pc[segment],&afl,&label,1)))
                                   {
			                rlt[1] = afl;
					lab[1] = label;
                                        inp+=l;
                                        if(t[inp]!=T_END && t[inp] != T_COMMENT)
                                        {
                                             if(t[inp]!=',')
                                                  er=E_SYNTAX;
                                             else
                                             {
                                                  inp++;
                                                  sy++;
                                                  if(!(er=a_term(t+inp,vv+2,&l,pc[segment],&afl,&label,1)))
                                                  {
			                               rlt[2] = afl;
						       lab[2] = label;
                                                       inp+=l;
                                                       if(t[inp]!=T_END && t[inp]!=T_COMMENT)
                                                            er=E_SYNTAX;
                                                  }
                                             }
                                        }
                                   }
                              }
                         }
                    }
               } else
               if(c==T_END || c==T_COMMENT)
               {
                    sy=0;
               } else
               if(c=='(')
               {
		    inp++;
		    if (t[inp] == T_CAST) {
			inp++;
			cast = t[inp];
			inp++;
#ifdef DEBUG_CAST
	printf("Found cast to (3): %c\n", cast);
#endif
		    }
                    sy=7;
                    if(!(er=a_term(t+inp,vv,&l,pc[segment],&afl,&label,1)))
                    {
			 inp += l;
			 rlt[0] = afl;
			 lab[0] = label;

                         if(t[inp]!=T_END && t[inp]!=T_COMMENT)
                         {
                              if(t[inp]==',')
                              {
				   inp++;
                                   if (tolower(t[inp])=='x')
                                        sy=8;
                                   else
                                        sy=13;

                              } else
                              if(t[inp]==')')
                              {
				   inp++;
                                   if(t[inp]==',')
                                   {
					inp++;
                                        if(tolower(t[inp])=='y')
                                             sy=9;
                                        else
                                             er=E_SYNTAX;
                                   } else
                                   if(t[inp]!=T_END && t[inp]!=T_COMMENT)
                                        er=E_SYNTAX;
                              } 
                         } else
                              er=E_SYNTAX;
                    }
               } else
               if(c=='[')
               {
		    inp++;
		    if (t[inp] == T_CAST) {
			inp++;
			cast = t[inp];
			inp++;
#ifdef DEBUG_CAST
	printf("Found cast to (4): %c\n", cast);
#endif
		    }
                    sy=10;
                    if(!(er=a_term(t+inp,vv,&l,pc[segment],&afl,&label,1)))
                    {
			 inp += l;
                         rlt[0] = afl;
			 lab[0] = label;

                         if(t[inp]!=T_END && t[inp]!=T_COMMENT)
                         {
                              if(t[inp]==']')
                              {
				   inp++;
                                   if(t[inp]==',')
                                   {
					inp++;
                                        if(tolower(t[inp])=='y')
                                             sy=11;
                                        else
                                             er=E_SYNTAX;
                                   } else
                                   if(t[inp]!=T_END && t[inp]!=T_COMMENT)
                                        er=E_SYNTAX;
                              } 
                         } else
                              er=E_SYNTAX;
                    }
               } else
               {
		    if (t[inp] == T_CAST) {
			inp++;
			cast = t[inp];
			inp++;
#ifdef DEBUG_CAST
	printf("Found cast to (5): %c\n", cast);
#endif
		    }
                    sy=4;
                    if(!(er=a_term(t+inp,vv,&l,pc[segment],&afl,&label,1)))
                    {
			 inp += l;
			 rlt[0] = afl;
			 lab[0] = label;
                         if(t[inp]!=T_END && t[inp]!=T_COMMENT)
                         {
                              if(t[inp]==',')
                              {
				   inp++;
                                   if(tolower(t[inp])=='y')
                                        sy=6;
                                   else
                                   if(tolower(t[inp])=='s')
                                        sy=12;
                                   else
                                        sy=5;
                              } else
                                   er=E_SYNTAX;
                         }
                    }
               }
               
	       /* set bl to maximum overall length +1 as while() below starts with decrementing it */
	       if (w65816 || cast=='@' || cast== '!') {
		       	/* for 65816 allow addressing modes up to 4 byte overall length */
               		bl=Maxbyt+1;
	       } else {
		       	/* for other modes only check for addressing modes up to 3 byte overall length */
		 	bl=Maxbyt;
	       }
              
#ifdef DEBUG_AM
	      printf("--- trying to find am using: (max+1) bl=%d, sy=%d\n", bl, sy); 
#endif
               while(--bl)
               {
                    if((am=at[sy][bl-1])>=0)
                    {
                         if(am>Admodes)
                         {
                              er=E_SYNTAX;
                              break;
                         }
                         if(ct[n][am]>=0)
                              break;

                         for(v=0;v<AnzAlt;v++)
                              if(xt[v][0]==am && ct[n][xt[v][1]]>=0)
                                   break;
                         if(v<AnzAlt) 
                         {
                              am=xt[v][1];
                              break;
                         }
                    }
               }

/* FIXIT1 
		fprintf(stderr, "t has: ");
		for(v=0;v<l;v++) {
			fprintf(stderr, "%02x ", t[v]);
		}
		fprintf(stderr, "\n");
*/

/* only do optimization if we're being called in pass 1 -- never pass 2 */
/* look at cast byte */
               if (cast!='@')
               {
#ifdef DEBUG_AM
fprintf(stderr,
"b4: pc= %d, am = %d and vv[0] = %d, optimize = %d, bitmask = %u, er=%d, bl=%d\n",
	pc[segment], am, vv[0], fl, (vv[0]&0xffff00), er, bl);
#endif

/* terrible KLUDGE!!!! OH NOES!!!1!
   due to the way this is constructed, you must absolutely always specify @ to
   get an absolute long or it will absolutely always be optimized down */
/* now also checks for negative overflow, resp. not-overflow */
                    if(bl 
			&& am>16 
			&& !er 
			&& (((vv[0]&0xff8000)==0xff8000) || !(vv[0]&0xff0000)) 
			&& opt[am]>=0)
                         if(ct[n][opt[am]]>=0)
                              am=opt[am];
#ifdef DEBUG_AM
fprintf(stderr,
"aftaa1: pc= %d, am = %d and vv[0] = %d, optimize = %d, bitmask = %d, bl = %d\n",
	pc[segment], am, vv[0], fl, (vv[0]&0xffff00), bl);
#endif
                    if(cast!='!') {
                         if(bl && !er && !(vv[0]&0xffff00) && opt[am]>=0) {
                              if(ct[n][opt[am]]>=0) {
				if (!fl || cast=='`') {
                                   	am=opt[am];
				} else {
					errout(W_FORLAB);
				}
			      }
			}
                    }
#ifdef DEBUG_AM
fprintf(stderr,
"aftaa2: pc=%d, am=%d and vv[0]=%d, optimize=%d, bitmask=%d, op=%d, bl=%d\n",
	pc[segment], am, vv[0], fl, (vv[0]&0xffff00), ct[n][opt[am]], bl);
#endif
               }

               if(!bl)
                    er=E_SYNTAX;
               else
               {
                    bl=le[am];
                    if( ((ct[n][am]&0x400) && memode) || ((ct[n][am]&0x800) && xmode)) {
                         bl++;
		    }
		    if ((am != 11 && am != 16) && (vv[0] > 255 || vv[0] < -256) && bl == 2) {
			    er = E_OVERFLOW;
		    } else
		    if ((am != 11 && am != 16) && (vv[0] > 65535 || vv[0] < -65536) && (bl == 2 || bl == 3)) {
			    er = E_OVERFLOW;
		    }
                    *ll=bl;
               }

#ifdef DEBUG_AM
fprintf(stderr, "byte length is now %d, am=%d, er=%d\n", bl, am, er);
#endif

               if(!er)
               {
                    t[0]=ct[n][am]&0x00ff;
                    if(ct[n][am]&0x0300)
                    {
                         if(ct[n][am]&0x100) {
                              ncmos++;
                              if(!cmosfl)
                                  er=E_CMOS;
                         } else {
                              n65816++;
                              if(!w65816) {
fprintf(stderr,"n=%d, am=%d\n", n, am);
                                  er=E_65816;
			      }
                         }
                    }
                    if(am!=0)
                    {
                         if((am<8 && !( ((ct[n][am]&0x400) && memode) || ((ct[n][am]&0x800) && xmode) )) || (am>=19 && am!=23))
                         {
                              if(vv[0]&0xff00) {
#ifdef DEBUG_AM
fprintf(stderr, "address mode: %i address: %i\n", am, vv[0]);
#endif
                                   er=E_OVERFLOW;
				}
                              else
                                   t[1]=vv[0];
/*if(rlt[0]) printf("relocation 1 byte %04x at pc=$%04x, value now =$%04x\n",rlt[0],pc[segment]+1,*vv); */
			      if(rlt[0]) u_set(pc[segment]+1, rlt[0], lab[0], 1);
                         } else
                         if(((am<14 || am==23) && am!=11) || am==7)
                         {
                              if (vv[0]>0xffff) {
#ifdef DEBUG_AM
fprintf(stderr, "address mode: %i address: %i\n", am, vv[0]);
#endif
                                   er=E_OVERFLOW;
				}
                              else {
                                   t[1]=vv[0]&255;
                                   t[2]=(vv[0]>>8)&255;
/*if(rlt[0]) printf("relocation 2 byte %04x at pc=$%04x, value now =$%04x\n",rlt[0],pc[segment]+1,*vv); */
			           if(rlt[0]) u_set(pc[segment]+1, rlt[0], lab[0], 2);
                              }
                         } else
                         if(am==11 || am==16) {
			   /* relative, relative long */
			   if((segment!=SEG_ABS) && (!rlt[0])) {
			     er=E_ILLPOINTER;
			   } else {
/*printf("am=11, pc=%04x, vv[0]=%04x, segment=%d\n",pc[segment],vv[0], segment);*/
                              v=vv[0]-pc[segment]-le[am];
                              if(((v&0xff80)!=0xff80) && (v&0xff80) && (am==11))
                                   er=E_RANGE;
                              else {
                                   t[1]=v&255;
                                   t[2]=(v>>8)&255;
                              }
			   }
                         } else
                         if(am==14) {
                              if(vv[0]&0xfff8 || vv[1]&0xff00)
                                   er=E_RANGE;
                              else
			      if((segment!=SEG_ABS) && (rlt[0] || !rlt[2])) {
				   er=E_ILLPOINTER;
			      } else {
/*if(rlt[1]) printf("relocation 1 byte %04x at pc=$%04x, value now =$%04x\n",rlt[1],pc[segment]+1,*vv); */
			           if(rlt[1]) u_set(pc[segment]+1, rlt[1], lab[1], 1);
                                   t[0]=t[0]|(vv[0]<<4);
                                   t[1]=vv[1];
                                   v=vv[2]-pc[segment]-3;
                                   if((v&0xff80) && ((v&0xff80)!=0xff80))
                                        er=E_OVERFLOW;
                                   else
                                        t[2]=v;
                              }
                         } else
                         if(am==15)
                         {
/*if(rlt[1]) printf("relocation 1 byte %04x at pc=$%04x, value now =$%04x\n",rlt[1],pc[segment]+1,*vv); */
			      if(rlt[1]) u_set(pc[segment]+1, rlt[1], lab[1], 1);
                              if(vv[0]&0xfff8 || vv[1]&0xff00)
                                   er=E_OVERFLOW;
                              else
                              {
                                   t[0]=t[0]|(vv[0]<<4);
                                   t[1]=vv[1];
                              }
                         } else
                         if(am==17 || am==18)
                         {
                                   t[1]=vv[0]&255;
                                   t[2]=(vv[0]>>8)&255;
                                   t[3]=(vv[0]>>16)&255;
			           if(rlt[0]) {
                                        rlt[0]|=A_LONG;
			                u_set(pc[segment]+1, rlt[0], lab[0], 3);
                                   }

                         } else
                              er=E_SYNTAX;
                    }
               }          
               
          } else
               er=E_SYNTAX;
     }

#ifdef DEBUG_AM
fprintf(stderr, "-- endof P2\n");
#endif
     pc[segment]+=bl;
     if(segment==SEG_TEXT) pc[SEG_ABS]+=bl;
     if(segment==SEG_ABS) pc[SEG_TEXT]+=bl;
     *al = bl;
     return(er);
}

/*********************************************************************************************/
/* helper function for the preprocessor, to compute an arithmetic value
 * (e.g. for #if or #print).
 * First tokenizes it, then calculates the value
 */
int b_term(char *s, int *v, int *l, int pc)
{
     static signed char t[MAXLINE];
     int er,i,afl, label;

     if(!(er=t_conv((signed char*)s,t,l,pc,&i,&i,&i,1,NULL)))
     {
          er=a_term(t,v,&i,pc,&afl,&label,0);
     
     }
     return(er);
}
     
/*********************************************************************************************/
/* translate a string into a first-pass sequence of tokens;
 * Take the text from *s (stopping at \0 or ';'), tokenize it
 * and write the result to *t, returning the length of the
 * token sequence in *l
 *
 * Input params:
 * 	s	source input line
 * 	t	output token sequence buffer
 * 	l	return length of output token sequence here
 * 	pc	the current PC to set address labels to that value
 * 	nk	return number of comma in the parameters
 * 	na1	asc text count returned
 * 	na2	total byte count in asc texts returned
 * 	af	arithmetic flag: 0=do label definitions, parse opcodes and params;
 * 		1=only tokenize parameters, for b_term() call from the preprocessor
 * 		for arithmetic conditions
 * 	bytep	???
 */
static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk,
             int *na1, int *na2, int af, int *bytep)  
{
     static int v,f;
     static int operand,o;
     int fl,afl;
     int p,q,ll,mk,er;
     int ud;	/* counts undefined labels */
     int n;	/* label number to be passed between l_def (definition) and l_set (set the value) */
     int byte;
     int uz;	/* unused at the moment */
     /*static unsigned char cast;*/

/* ich verstehe deutsch, aber verstehen andere leute nicht; so, werde ich
   diese bemerkungen uebersetzen ... cameron */
/* I understand German, but other folks don't, so I'll translate these
   comments ... Cameron */
/* note that I don't write so good tho' ;) */

     *nk=0;         /* comma count */
     *na1=0;        /* asc text count */
     *na2=0;        /* total bytecount in asc texts */
     ll=0;
     er=E_OK;		/* error state */
     p=0;
     q=0;
     ud = uz = byte =0;
     mk=0;          /* 0 = add'l commas ok */
     fl=0;          /* 1 = pass text thru */
     afl=0;         /* pointer flag for label */

     // skip leading whitespace
     while(isspace(s[p])) p++;

     n=T_END;
     /*cast='\0';*/

     if(!af)
     {
          while(s[p]!='\0' && s[p]!=';')
          {
		//printf("CONV: %s\n", s);

	       if (s[p] == ':') {
			// this is a ca65 unnamed label
			if ((er = l_def((char*)s+p, &ll, &n, &f)))
				break;
                    	l_set(n,pc,segment);        /* set as address value */
		    	t[q++]=T_DEFINE;
		    	t[q++]=n&255;
		    	t[q++]=(n>>8)&255;
                    	n=0;

			p+=ll;

               		while(isspace(s[p])) p++;

			// end of line
			if (s[p] == 0 || s[p] == ';') {
				break;
			}
	       }
			
		/* is keyword? */
               if(!(er=t_keyword(s+p,&ll,&n)))
                    break;

		/* valid syntax, but just not a real token? */
               if(er && er!=E_NOKEY)
                    break;

		// if so, try to understand as label 
		// it returns the label number in n
               if((er=l_def((char*)s+p,&ll,&n,&f)))
                    break;

               p+=ll;

               while(isspace(s[p])) p++;

               if(s[p]=='=')
               {
		    /*printf("Found = @%s\n",s+p);*/
                    t[q++]=T_OP;
                    t[q++]=n&255;
                    t[q++]=(n>>8)&255;
                    t[q++]='=';
                    p++;
                    ll=n=0;
                    break;
               } else
               if(s[p]==':' && s[p+1]=='=')		/* support := label assignments (ca65 compatibility) */
	       {
		    /*printf("Found := @%s\n", s+p);*/
		    t[q++]=T_OP;
		    t[q++]=n&255;
		    t[q++]=(n>>8)&255;
		    t[q++]='=';
		    p+=2;
		    ll=n=0;
		    break;
               } else
               if(f && s[p]!='\0' && s[p+1]=='=')
               {
                    t[q++]=T_OP;
                    t[q++]=n&255;
                    t[q++]=(n>>8)&255;
                    t[q++]=s[p];
                    p+=2;
                    ll=n=0;
                    break;
               } else
               if(s[p]==':')	/* to support label: ... syntax */
               {
                    p++;
                    while(s[p]==' ') p++;
                    l_set(n,pc,segment);        /* set as address value */
		    t[q++]=T_DEFINE;
		    t[q++]=n&255;
		    t[q++]=(n>>8)&255;
                    n=0;

               } else {		/* label ... syntax */
                    l_set(n,pc,segment);        /* set as address value */
      		    t[q++]=T_DEFINE;
		    t[q++]=n&255;
		    t[q++]=(n>>8)&255;
        	    n=0;
               }

          }

          if(n != Kmvn && n != Kmvp && ((n & 0xff) <=Lastbef)) {
               mk=1;     /* = only 1 comma ok for normal opcodes */
	  }
     }

     if(s[p]=='\0' || s[p]==';')
     {
          er=E_NOLINE;
          ll=0;
     } else
     if(!er)
     {

          p+=ll;
          if(ll) {
             t[q++]= n & 0xff;
/*
             if( (n&0xff) == Kmacro) {
                t[q++]= (n >> 8) & 0xff;
             }
*/
          }

          operand=1;

	  // skip whitespace
          while(isspace(s[p])) {
		p++;
	  }

          if(s[p]=='#')
          {
               mk=0;
               t[q++]=s[p++];

	       // skip following whitespace
               while(isspace(s[p])) {
		   p++;
	       }
          }

/*
 *
 * operand processing
 * byte = length of operand in bytes to be assembled
 *
 *
 */

          /* this addresses forced high/low/two byte addressing, but only
             for the first operand. Further processing is done in a_term()
          */

/* FIXIT2 */

          while(s[p]!='\0' && s[p]!=';' && !er)
          {
               if(fl)
               {
		    // pass through text (e.g. for ",y")
                    t[q++]=s[p++];

               } else
               {
                 if(operand)
                 {
			/* are we forcing the operand into a particular
			   addressing mode? !, @, ` operators 
			   Note these are not available in ca65, but we only
			   switch off "@" which are used for cheap local labels*/
                    if(s[p]=='!' || (s[p]=='@' && !ca65) || s[p]=='`')
                    {
#ifdef DEBUG_CAST
	printf("Setting cast to: %c\n", s[p]);
#endif
		       t[q++]=T_CAST;
		       t[q++]=s[p];
                       operand= -operand+1;
                       p++;
                    } else
                    if(s[p]=='(' || s[p]=='-' || s[p]=='>' ||
			s[p]=='<' || s[p]=='[')
                    {
                         t[q++]=s[p++];
                         operand= -operand+1; /* invert to become reinverted */
                    } else
                    if(s[p]=='*')
                    {
                         t[q++]=s[p++];
                    } else
		    /* maybe it's a label 
 			Note that for ca65 cheap local labels, we check for "@" */
                    if(isalpha(s[p]) || s[p]=='_' || ((s[p]==':' || s[p]=='@') && ca65))
                    {
                       
			int p2 = 0; 
			if (n == (Klistbytes & 0xff)) {
				// check for "unlimited"
				// Note: this could be done by a more general "constants" handling,
				// where in appropriate places (like the one here), constants are
				// replaced by a pointer to a predefined constants info, e.g. using 
				// a T_CONSTANT. Which would also fix the listing of this constant
				// (which is currently listed as "0")
				static char *unlimited = "unlimited";
				while (s[p+p2] != 0 && unlimited[p2] != 0 && s[p+p2] == unlimited[p2]) p2++;
			} 
			if (p2 == 9) {	// length of "unlimited"
				er = E_OK;
				// found constant
                       		wval(q, 0, 'd');
				p += p2;
			} else {
			 //m=n;
                         er=l_search((char*)s+p,&ll,&n,&v,&afl);

			 if (er == E_NODEF && undefok) {
				lg_toglobal(s+p);
			 }

                         if(!er)
                         {
                           if(afl) {
                             t[q++]=T_POINTER;
                             t[q++]=afl & 255;
                             t[q++]=v & 255;
                             t[q++]=(v>>8) & 255;
			     t[q++]=n & 255;		/* cheap fix for listing */
			     t[q++]=(n>>8) & 255;	/* why is the label already resolved in t_conv? */
                           } else {
                              t[q++]=T_LABEL;
                              t[q++]=n & 255;
                              t[q++]=(n>>8) & 255;
                             /*wval(q,v, 0);*/
                           }
                         } else
                         if(er==E_NODEF)
                         {
#ifdef DEBUG_AM
fprintf(stderr, "could not find %s\n", (char *)s+p);
#endif
                              t[q++]=T_LABEL;
                              t[q++]=n & 255;
                              t[q++]=(n>>8) & 255;
/*
                              if(afl==SEG_ZEROUNDEF) uz++;
*/
                              ud++;	// number of undefined labels
                              er=E_OK;
                         }
                         p+=ll;
			}
                    }
                    else
                    if(s[p]<='9' && (s[p]>'0' || (s[p] == '0' && !ctypes)))
                    {
                         tg_dez(s+p,&ll,&v);
                         p+=ll;
                         wval(q,v, 'd');
                    }
                    else
		    /* handle encodings: hex, binary, octal, quoted strings */
                    switch(s[p]) {
                    case '0':
			 // only gets here when "ctypes" is set, and starts with 0
			 // we here check for the C stype "0xHEX" and "0OCTAL" encodings
			 if ('x' == tolower(s[p+1])) {
				// c-style hex
				tg_hex(s+p+2, &ll, &v);
				p+=2+ll;
				wval(q, v, '$');
			 } else 
			 if (isdigit(s[p+1])) {
				// c-style octal if digit follows
                         	tg_oct(s+p+1,&ll,&v);
                         	p+=1+ll;
                         	wval(q,v, '&');
			 } else {
				// else use decimal (0)
                         	tg_dez(s+p,&ll,&v);
                         	p+=ll;
                         	wval(q,v, 'd');
			 }
			 break;
                    case '$':
                         tg_hex(s+p+1,&ll,&v);
                         p+=1+ll;
                         wval(q,v, '$');
                         break;
                    case '%':
                         tg_bin(s+p+1,&ll,&v);
                         p+=1+ll;
                         wval(q,v, '%');
                         break;
                    case '&':
                         tg_oct(s+p+1,&ll,&v);
                         p+=1+ll;
                         wval(q,v, '&');
                         break;
                    case '\'':
                    case '\"':
                         er=tg_asc(s+p,t+q,&q,&p,na1,na2,n);
                         break;
                    case ',':
                         if(mk)
                              while(s[p]!='\0' && s[p]!=';')
                              {
                                   while(s[p]==' ') p++;
                                   *nk+=(s[p]==',');
                                   t[q++]=s[p++];
                              }
                         else
                         {
                              *nk+=1;
                              t[q++]=s[p++];
                         }
                         break;
                    default :
                         er=E_SYNTAX;
                         break;
                    }
                    operand= -operand+1;

                 } else    /* operator    */
                 {
                    o=0;
                    if(s[p]==')' || s[p]==']')
                    {
                         t[q++]=s[p++];
                         operand =-operand+1;
                    } else
                    if(s[p]==',')
                    {
                         t[q++]=s[p++];
                         if(mk) {
			      // if only one comma, pass through all following text - esp. ",y" or ",x" etc
                              fl++;
			 }
                         *nk+=1;
                    } else
                    switch(s[p]) {
                    case '+':
                         o=1;
                         break;
                    case '-':
                         o=2;
                         break;
                    case '*':
                         o=3;
                         break;
                    case '/':
                         o=4;
                         break;
                    case '!':
                         if (s[p+1] == '=') o=12;
                         break;
                    case '<':
                         switch (s[p+1]) {
                         case '<':
                              o=6;
                              break;
                         case '>':
                              o=12;
                              break;
                         case '=':
                              o=10;
                              break;
                         default :
                              o=7;
                              break;
                         }
                         break;
                    case '>':
                         switch (s[p+1]) {
                         case '>':
                              o=5;
                              break;
                         case '<':
                              o=12;
                              break;
                         case '=':
                              o=11;
                              break;
                         default:
                              o=8;
                              break;
                         }
                         break;
                    case '=':
                         switch (s[p+1]) {
                         case '<':
                              o=10;
                              break;
                         case '>':
                              o=11;
                              break;
                         case '=':
                              o=9; p++; /* hack */
                              break;
                         default:
                              o=9;
                              break;
                         }
                         break;
                    case '&':
                         if (s[p+1]=='&')
                              o=16;
                         else
                              o=13;
                         break;
                    case '|':
                         if (s[p+1]=='|')
                              o=17;
                         else
                              o=15;
                         break;
                    case '^':
                         o=14;
                         break;
                    default:
                         er=E_SYNTAX;
                         break;
                    }
                    if(o)
                    {
                         t[q++]=o;
                         p+=lp[o];
                    }
                    operand= -operand+1;
                 }

                 while(s[p]==' ') p++;
               }
          }
     }
//printf("er=%d, ud=%d\n", er, ud);
     if(!er)
     {
/*
          if(uz==1 && ud==1 && byte!=2) {
               byte=1;
	  }
          if(byte == 1) {
               t[q++] = T_FBYTE;
          } else if(byte == 2) {
               t[q++] = T_FADDR;
          }
*/
	  byte = 0;
          if(ud > 0) {
               er=E_NODEF;
		byte = 1;
          }
     }
    
     if (s[p] == ';') {
	/* handle comments */
	/* first find out how long */
	int i;
	for (i = p+1; s[i] != '\0'; i++);
	i = i - p;	/* actual length of the comment, including zero-byte terminator */
	/*if (i >= 1) {*/
		/* there actually is a comment */
		t[q++] = T_COMMENT;
		t[q++] = i&255;
		t[q++] = (i>>8)&255;
		memcpy(t+q, s+p+1, i);	/* also copy zero terminator, used in listing */
		q += i;
	/*}*/
     } 
     t[q++]=T_END;
     /* FIXME: this is an unholy union of two "!" implementations :-( */
     /* FIXME FIXME FIXME ... 
     if (operand==1) {
         t[q++]='\0';
         t[q++]=cast;
     }
     */
     *l=q;
     if(bytep) *bytep=byte; 
     return(er);
}

/*********************************************************************************************
 * identifies a keyword in s, if it is found, starting with s[0]
 * A keyword is either a mnemonic, or a pseudo-opcode
 */
static int t_keyword(signed char *s, int *l, int *n)
{
     int i = 0;		// index into keywords
     int j = 0;
     int hash;

     // keywords either start with a character, a "." or "*"
     if(!isalpha(s[0]) && s[0]!='.' && s[0]!='*' )
          return(E_NOKEY);

     // if first char is a character, use it as hash...
     if(isalpha(s[0]))
          hash=tolower(s[0])-'a';
     else
          hash=26;
     

     // check for "*="
     if(s[0]=='*') {
 	j=1;
	while(s[j] && isspace(s[j])) j++;
	if(s[j]=='=') {
	  i=Kpcdef;
	  j++;
	}
     } 

     // no keyword yet found?
     if(!i) {    
       // get sub-table from hash code, and compare with table content
       // (temporarily) redefine i as start index in opcode table, and hash as end index
       i=ktp[hash];
       hash=ktp[hash+1];
       // check all entries in opcode table from start to end for that hash code
       while(i<hash)
       {
          j=0;
          while(kt[i][j]!='\0' && kt[i][j]==tolower(s[j]))
               j++;

          if((kt[i][j]=='\0') && ((i==Kpcdef) || ((s[j]!='_') && !isalnum(s[j]))))
               break;
          i++;
       }
     }    
     if(i==Kbyte) i=Kbyt;
     if(i==Kdupb) i=Kdsb;
     if(i==Kblkb) i=Kdsb;
     if(i==Kdb) i=Kbyt;
     if(i==Kdw) i=Kword;
     if(i==Kblock) i=Kopen;
     if(i==Kbend) i=Kclose;
     if(i==Kcode) i=Ktext;
     if(i==Kproc || i==Kscope) i=Kopen;
     if(i==Kendproc || i==Kendscope) i=Kclose;
     if(i==Kzeropage) i=Kzero;
     if(i==Korg) i=Kpcdef;
     if(i==Krelocx) i=Kpcdef;


     *l=j;
     *n=i;
     return( i==hash ? E_NOKEY : E_OK );
}

static void tg_dez(s,l,v)
signed char *s;
int *l,*v;
{
     int i=0,val=0;

     while(isdigit(s[i]))
          val=val*10+(s[i++]-'0');

     *l=i;
     *v=val;
}

static void tg_bin(signed char *s, int *l, int *v)
{
     int i=0,val=0;

     while(s[i]=='0' || s[i]=='1')
          val=val*2+(s[i++]-'0');

     *l=i;
     *v=val;
}

static void tg_oct(signed char *s, int *l, int *v)
{
     int i=0,val=0;

     while(s[i]<'8' && s[i]>='0')
          val=val*8+(s[i++]-'0');

     *l=i;
     *v=val;
}

static void tg_hex(signed char *s, int *l, int *v)
{
     int i=0,val=0;

     while((s[i]>='0' && s[i]<='9') || (tolower(s[i])<='f' && tolower(s[i])>='a'))
     {
          val=val*16+(s[i]<='9' ? s[i]-'0' : tolower(s[i])-'a'+10);
          i++;
     }
     *l=i;
     *v=val;
}

/* 
 * tokenize a string - handle two delimiter types, ' and " 
 */
static int tg_asc(signed char *s, signed char *t, int *q, int *p, int *na1, int *na2,int n)
{

     int er=E_OK,i=0,j=0,bs=0;

     signed char delimiter = s[i++];
     
#ifdef DEBUG_AM
fprintf(stderr, "tg_asc token = %i\n", n);
#endif

     t[j++]='"';	/* pass2 token for string */
     j++;		/* skip place for length */

     while(s[i]!='\0' && (bs || s[i]!=delimiter))
     {

	/* implement backslashed quotes for 2.4 */
          if(n != Kbin && s[i] == '\\' && !bs && !xa23) {
               bs=1; i++; continue;
          } else bs=0;
	/* do NOT convert for Kbin or Kaasc, or for initial parse */
	  if (!n || n == Kbin || n == Kaasc) {
		t[j++]=s[i];
/* XXX 2.4 implement option for ^ for backwards compatibility */
          } else if(ca65 || !xa23 || s[i]!='^') { 	/* no escape code "^" - TODO: does ca65 has an escape code */
               t[j++]=convert_char(s[i]);
          } else { 		/* escape code */
		  signed char payload = s[i+1];
	          switch(payload) {
	          case '\0':
	               er=E_SYNTAX;
	               break;
	          case '\"':
		       if (payload == delimiter) {
	                 t[j++]=convert_char(payload);
	                 i++;
		       } else {
	                 er=E_SYNTAX;
		       }
	               break;
	          case '\'':
		       if (payload == delimiter) {
	                 t[j++]=convert_char(payload);
	                 i++;
		       } else {
	                 er=E_SYNTAX;
		       }
	               break;
	          case '^':
	               t[j++]=convert_char('^');
	               i++;
	               break;
	          default:
	               t[j++]=convert_char(payload&0x1f);
	               i++;
	               break;
	          }
	  }
          i++;
     }
     if(j==3)	/* optimize single byte string to value */
     {
          t[0]=T_VALUE;
          t[1]=t[2];
          t[2]=0;
          t[3]=0;
	  t[4]=delimiter;
          j+=2;
     } else
     {		/* handle as string */
          t[1]=j-2;
          *na1 +=1;
          *na2 +=j-2;
     }
     if(s[i]==delimiter) {	/* in case of no error */
          i++;			/* skip ending delimiter */
     }
     *q +=j;
     *p +=i;
     return(er);
}


