/* 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 #include #include #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 (inp1) && (t[inp]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 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 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); // 5 byte t[i++]=','; tmp2= 0xea; wval(i,tmp2, 0); /* nop opcode, another 5 byte */ t[i++]=T_END; *ll=wval_len * 2 + 3; //13; //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=0) break; if(v=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) { 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;i0 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 error string. 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 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 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 if(tolower(t[inp])=='x') sy=5; else er=E_SYNTAX; } 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=0) break; if(v16 && !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) { #ifdef DEBUG_AM fprintf(stderr,"not 65816 n=%d, am=%d\n", n, am); #endif 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]==':' && collab) || ((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='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 && !mask) || 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); }