diff --git a/xa/src/Makefile b/xa/src/Makefile index 173d634..8e32165 100644 --- a/xa/src/Makefile +++ b/xa/src/Makefile @@ -1,4 +1,4 @@ -OBJ = xa.o xaa.o xal.o xap.o xat.o xar.o xar2.o xao.o xau.o xam.o xacharset.o +OBJ = xa.o xaa.o xal.o xap.o xat.o xar.o xar2.o xao.o xau.o xam.o xacharset.o xalisting.o #CFLAGS=-W -Wall -pedantic -ansi -g #CFLAGS=-W -Wall -ansi -O2 diff --git a/xa/src/xalisting.c b/xa/src/xalisting.c new file mode 100644 index 0000000..9bbb4a7 --- /dev/null +++ b/xa/src/xalisting.c @@ -0,0 +1,550 @@ +/* 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 */ +/* #define DEBUG_AM */ +#undef LISTING_DEBUG + +#include +#include + +#include "xah.h" +#include "xal.h" +#include "xat.h" + + +/*********************************************************************************************/ +/* this is the listing code + * + * Unfortunately this code has to go here (for now), as this file is the only one + * where we have access to the tables that allow to convert the tokens back to + * a listing + */ + +static FILE *listfp = NULL; +static int list_lineno = 1; /* current line number */ +static int list_last_lineno = 0; /* current line number */ +static char *list_filenamep = NULL; /* current file name pointer */ + +static int list_numbytes = 8; + +static int list_string(char *buf, char *string); +static int list_tokens(char *buf, signed char *input, int len); +static int list_value(char *buf, int val, signed char format); +static int list_nchar(char *buf, signed char c, int n); +static int list_char(char *buf, signed char c); +static int list_sp(char *buf); +static int list_word(char *buf, int outword); +static int list_word_f(char *buf, int outword, signed char format); +static int list_byte(char *buf, int outbyte); +static int list_byte_f(char *buf, int outbyte, signed char format); +static int list_nibble_f(char *buf, int outnib, signed char format); + +// set number of bytes per line displayed as hex +void list_setbytes(int number_of_bytes_per_line) { + list_numbytes = number_of_bytes_per_line; +} + +/* set line number for the coming listing output */ +void list_line(int l) { + list_lineno = l; +} + +/* set file name for the coming listing output */ +void list_filename(char *fname) { + if (list_filenamep == NULL || (fname != NULL && strcmp(fname, list_filenamep) != 0)) { + list_filenamep = fname; + list_lineno = 1; + list_last_lineno = 0; + + /* Hack */ + if (listfp != NULL) { + fprintf(listfp, "\n%s\n\n", fname); + } + } +} + +/** + * set the output file descriptor where to write the listing + */ +void list_setfile(FILE *fp) { + listfp = fp; +} + +char *list_preamble(char *buf, int lineno, int seg, int pc) { + /* line number in file */ + snprintf(buf, 10, "% 5d", lineno); + int i = strlen(buf); + buf += i; + buf += list_char(buf, ' '); + + char c = '?'; + /* preamble ':'
' ' */ + switch(seg) { + case SEG_ABS: c='A'; break; + case SEG_TEXT: c='T'; break; + case SEG_BSS: c='B'; break; + case SEG_DATA: c='D'; break; + case SEG_UNDEF: c='U'; break; + case SEG_ZERO: c='Z'; break; + } + buf = buf + list_char(buf, c); + buf = buf + list_char(buf, ':'); + buf = buf + list_word(buf, pc); + buf = buf + list_nchar(buf, ' ', 2); + + return buf; +} + + +/** + * listing/listing_len give the buffer address and length respectively that contains + * the token as they are produced by the tokenizer. + * bincode/bincode_len give the buffer address and length that contain the binary code + * that is produced from the token listing + * + * Note that both lengths may be zero + */ +void do_listing(signed char *listing, int listing_len, signed char *bincode, int bincode_len) { + + int i, n_hexb; + + char outline[MAXLINE]; + char *buf = outline; + + int lst_seg = listing[0]; + int lst_pc = (listing[2]<<8) | (listing[1] & 255); + + /* no output file (not even stdout) */ + if (listfp == NULL) return; + + /*printf("do_listing: listing=%p (%d), bincode=%p (%d)\n", listing, listing_len, bincode, bincode_len);*/ + + if (bincode_len < 0) bincode_len = -bincode_len; + + /* do we need a separation line? */ + if (list_lineno > list_last_lineno+1) { + /* yes */ + /*fprintf(listfp, "line=%d, last=%d\n", list_lineno, list_last_lineno);*/ + fprintf(listfp, "\n"); + } + list_last_lineno = list_lineno; + + buf = list_preamble(buf, list_lineno, lst_seg, lst_pc); + + // check if we have labels, so we can adjust the max printable number of + // bytes in the last line + int num_last_line = 11; + int tmp = listing[3] & 255; + if (tmp == (T_DEFINE & 255)) { + // we have label definition + num_last_line = 8; + } + int overflow = 0; + + /* binary output (up to 8 byte. If more than 8 byte, print 7 plus "..." */ + n_hexb = bincode_len; + if (list_numbytes != 0 && n_hexb >= list_numbytes) { + n_hexb = list_numbytes-1; + overflow = 1; + } + for (i = 0; i < n_hexb; i++) { + buf = buf + list_byte(buf, bincode[i]); + buf = buf + list_sp(buf); + if ( (i%16) == 15) { + // make a break + buf[0] = 0; + fprintf(listfp, "%s\n", outline); + buf = outline; + buf = list_preamble(buf, list_lineno, lst_seg, lst_pc + i + 1); + } + } + if (overflow) { + // are we at the last byte? + if (n_hexb + 1 == bincode_len) { + // just print the last byte + buf = buf + list_byte(buf, bincode[i]); + buf = buf + list_sp(buf); + } else { + // display "..." + buf = buf + list_nchar(buf, '.', 3); + } + n_hexb++; + } + i = n_hexb % 16; + if (i > num_last_line) { + // make a break (Note: with original PC, as now the assembler text follows + buf[0] = 0; + fprintf(listfp, "%s\n", outline); + buf = outline; + buf = list_preamble(buf, list_lineno, lst_seg, lst_pc); + i = 0; + } + i = num_last_line - i; + buf = buf + list_nchar(buf, ' ', i * 3); + + buf = buf + list_sp(buf); + + buf += list_tokens(buf, listing + 3, listing_len - 3); + +#ifdef LISTING_DEBUG + /* for now only do a hex dump so we see what actually happens */ + i = buf - outline; + if (i<80) buf += list_nchar(buf, ' ', 80-i); + + buf += list_string(buf, " >>"); + for (i = 3; i < listing_len; i++) { + buf = buf + list_byte(buf, listing[i]); + buf = buf + list_sp(buf); + } +#endif + buf[0] = 0; + + fprintf(listfp, "%s\n", outline); +} + +int list_tokens(char *buf, signed char *input, int len) { + int outp = 0; + int inp = 0; + int tmp; + char *name; + signed char c; + label_t is_cll; + int tabval; + signed char format; + + if (inp >= len) return 0; + + tmp = input[inp] & 255; + + tabval = 0; + if (tmp == (T_DEFINE & 255)) { + while (inp < len && tmp == (T_DEFINE & 255)) { + tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); +/*printf("define: len=%d, inp=%d, tmp=%d\n", len, inp, tmp);*/ + name=l_get_name(tmp, &is_cll); + if (is_cll == CHEAP) { + outp += list_char(buf+outp, '@'); + } else + if (is_cll == UNNAMED_DEF || is_cll == UNNAMED) { + outp += list_char(buf+outp, ':'); + } + if (is_cll != UNNAMED) { + tmp = list_string(buf+outp, name); + tabval += tmp + 1 + is_cll; + outp += tmp; + } + outp += list_char(buf+outp, ' '); + inp += 3; + tmp = input[inp] & 255; + } + if (tabval < 10) { + outp += list_nchar(buf+outp, ' ', 10-tabval); + } + } else { + if (tmp >= 0 && tmp < number_of_valid_tokens) { + outp += list_string(buf+outp, " "); + } + } + + if (tmp >= 0 && tmp < number_of_valid_tokens) { + /* assembler keyword */ + /*printf("tmp=%d, kt[tmp]=%p\n", tmp, kt[tmp]);*/ + if (kt[tmp] != NULL) { + outp += list_string(buf+outp, kt[tmp]); + } + outp += list_sp(buf + outp); + inp += 1; +#if 0 + if (tmp == Kinclude) { + /* just another exception from the rule... */ + /* next char is terminator (", ') then the length and then the file name */ + char term = input[inp]; + int len = input[inp+1] & 255; + outp += list_char(buf+outp, term); + for (tmp = 2; tmp < len+2; tmp++) { + outp += list_char(buf+outp, input[inp+tmp]); + } + outp += list_char(buf+outp, term); + inp += len + 2; + } +#endif + } + + while (inp < len) { + int operator = 0; + + switch(input[inp]) { + case T_CAST: + outp += list_char(buf+outp, input[inp+1]); + break; + case T_VALUE: + /*outp += list_char(buf+outp, 'V');*/ + /* 24 bit value */ + tmp = ((input[inp+3]&255)<<16) | ((input[inp+2]&255)<<8) | (input[inp+1]&255); + format = input[inp+4]; + outp += list_value(buf+outp, tmp, format); + inp += 5; + operator = 1; /* check if arithmetic operator follows */ + break; + case T_LABEL: + /*outp += list_char(buf+outp, 'L');*/ + /* 16 bit label number */ + tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); + name=l_get_name(tmp, &is_cll); + if (is_cll == CHEAP) { + outp += list_char(buf+outp, '@'); + } else + if (is_cll == UNNAMED || is_cll == UNNAMED_DEF) { + outp += list_char(buf+outp, ':'); + } + if (is_cll != UNNAMED) { + outp += list_string(buf+outp, name); + } + inp += 3; + operator = 1; /* check if arithmetic operator follows */ + break; + case T_OP: + /* label arithmetic operation; inp[3] is operation like '=' or '+' */ + tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); + name=l_get_name(tmp, &is_cll); + if (is_cll) outp += list_char(buf+outp, '@'); + outp += list_string(buf+outp, name); + outp += list_char(buf+outp, input[inp+3]); + inp += 4; + + break; + case T_END: + /* end of operation */ + /*outp += list_string(buf+outp, ";");*/ + inp += 1; + goto end; + break; + case T_COMMENT: + if (inp > 0 && inp < 20) { + outp += list_nchar(buf+outp, ' ', 20-inp); + } + tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); + outp += list_char(buf+outp, ';'); + outp += list_string(buf+outp, (char*)input+inp+3); + inp += tmp + 3; + break; + case T_LINE: + case T_FILE: + /* those two are meta-tokens, evaluated outside the t_p2 call, + * they result in calls to list_line(), list_filename() */ + break; + case T_POINTER: + /* what is this? It's actually resolved during token conversion */ + tmp = ((input[inp+5]&255)<<8) | (input[inp+4]&255); + name=l_get_name(tmp, &is_cll); + if (is_cll) outp += list_char(buf+outp, '@'); + outp += list_string(buf+outp, name); + /* + outp += list_byte(buf+outp, input[inp+1]); + outp += list_char(buf+outp, '#'); + tmp = ((input[inp+3]&255)<<8) | (input[inp+2]&255); + outp += list_value(buf+outp, tmp); + */ + inp += 6; + operator = 1; /* check if arithmetic operator follows */ + break; + case '"': + // string display + inp++; + outp += list_char(buf+outp, '"'); + int len = input[inp] & 0xff; + for (int i = 0; i < len; i++) { + inp++; + outp += list_char(buf+outp, input[inp]); + } + inp++; + outp += list_char(buf+outp, '"'); + break; + default: + c = input[inp]; + if (c > 31) { + outp += list_char(buf+outp, input[inp]); + } else { + outp += list_char(buf+outp, '\''); + outp += list_byte(buf+outp, input[inp]); + } + inp += 1; + break; + } + + if (operator && inp < len) { + signed char op = input[inp]; + if (op > 0 && op <= 17) { + outp += list_string(buf+outp, arith_ops[op]); + inp += 1; + } + operator = 0; + } + } +end: + return outp; +} + +int list_string(char *buf, char *string) { + int p = 0; + while (string[p] != 0) { + buf[p] = string[p]; + p++; + } + return p; +} + +int list_value(char *buf, int val, signed char format) { + int p = 0; + char valbuf[32]; + + switch (format) { + case '$': + p += list_char(buf + p, '$'); + if (val & (255<<16)) { + p += list_byte(buf+p, val>>16); + p += list_word(buf+p, val); + } else + if (val & (255<<8)) { + p += list_word(buf+p, val); + } else { + p += list_byte(buf+p, val); + } + break; + case '%': + p += list_char(buf + p, '%'); + if (val & (255<<16)) { + p += list_byte_f(buf+p, val>>16,'%'); + p += list_word_f(buf+p, val,'%'); + } else + if (val & (255<<8)) { + p += list_word_f(buf+p, val,'%'); + } else { + p += list_byte_f(buf+p, val,'%'); + } + break; + case '&': + snprintf(valbuf, 32, "%o",val); + p+= list_char(buf+p, '&'); + p+= list_string(buf+p, valbuf); + break; + case 'd': + snprintf(valbuf, 32, "%d",val); + p+= list_string(buf+p, valbuf); + break; + case '\'': + case '"': + p+= list_char(buf+p, format); + p+= list_char(buf+p, val); + p+= list_char(buf+p, format); + break; + default: + /* hex format as fallback */ + p += list_char(buf + p, '$'); + if (val & (255<<16)) { + p += list_byte(buf+p, val>>16); + p += list_word(buf+p, val); + } else + if (val & (255<<8)) { + p += list_word(buf+p, val); + } else { + p += list_byte(buf+p, val); + } + break; + } + return p; +} + +int list_nchar(char *buf, signed char c, int n) { + int i; + for (i = 0; i < n; i++) { + buf[i]=c; + } + return n; +} + +int list_char(char *buf, signed char c) { + buf[0] = c; + return 1; +} + +int list_sp(char *buf) { + buf[0] = ' '; + return 1; +} + +int list_word(char *buf, int outword) { + return list_word_f(buf, outword, '$'); +} + +int list_word_f(char *buf, int outword, signed char format) { + int p = 0; + p+= list_byte_f(buf+p, outword >> 8, format); + p+= list_byte_f(buf+p, outword, format); + return p; +} + +int list_byte(char *buf, int outbyte) { + return list_byte_f(buf, outbyte, '$'); +} + +int list_byte_f(char *buf, int outbyte, signed char format) { + int p = 0; + p+= list_nibble_f(buf+p, (outbyte >> 4), format); + p+= list_nibble_f(buf+p, outbyte, format); + return p; +} + +int list_nibble_f(char *buf, int outnib, signed char format) { + int p = 0; + outnib = outnib & 0xf; + switch(format) { + case '$': + if (outnib < 10) { + buf[p]='0'+outnib; + } else { + buf[p]='a'-10+outnib; + } + p++; + break; + case '%': + buf[p++] = (outnib&8)?'1':'0'; + buf[p++] = (outnib&4)?'1':'0'; + buf[p++] = (outnib&2)?'1':'0'; + buf[p++] = (outnib&1)?'1':'0'; + break; + default: + /* hex as default */ + if (outnib < 10) { + buf[p]='0'+outnib; + } else { + buf[p]='a'-10+outnib; + } + p++; + break; + } + return p; +} + + + diff --git a/xa/src/xalisting.h b/xa/src/xalisting.h new file mode 100644 index 0000000..91ce008 --- /dev/null +++ b/xa/src/xalisting.h @@ -0,0 +1,24 @@ +/* xa65 - 65xx/65816 cross-assembler and utility suite + * + * Copyright (C) 1989-1997 André Fachat (a.fachat@physik.tu-chemnitz.de) + * + * 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. + */ +#ifndef __XA65_XALISTING_H__ +#define __XA65_XALISTING_H__ + +void do_listing(signed char *listing, int listing_len, signed char *bincode, int bincode_len); + +#endif /* __XA65_XALISTING_H__ */ diff --git a/xa/src/xat.c b/xa/src/xat.c index dddf7f2..b208855 100644 --- a/xa/src/xat.c +++ b/xa/src/xat.c @@ -51,7 +51,7 @@ 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); +//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); @@ -67,7 +67,7 @@ void list_setbytes(int number_of_bytes_per_line); * .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. */ -static char *kt[] ={ +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", @@ -99,7 +99,7 @@ static char *kt[] ={ }; /* arithmetic operators (purely for listing, parsing is done programmatically */ -static char *arith_ops[] = { +char *arith_ops[] = { "", "+", "-", "*", "/", ">>", "<<", @@ -172,6 +172,8 @@ static int lp[]= { 0,1,1,1,1,2,2,1,1,1,2,2,2,1,1,1,2,2 }; #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, @@ -2525,518 +2527,4 @@ fprintf(stderr, "tg_asc token = %i\n", n); return(er); } -/*********************************************************************************************/ -/* this is the listing code - * - * Unfortunately this code has to go here (for now), as this file is the only one - * where we have access to the tables that allow to convert the tokens back to - * a listing - */ - -static FILE *listfp = NULL; -static int list_lineno = 1; /* current line number */ -static int list_last_lineno = 0; /* current line number */ -static char *list_filenamep = NULL; /* current file name pointer */ - -static int list_numbytes = 8; - -static int list_string(char *buf, char *string); -static int list_tokens(char *buf, signed char *input, int len); -static int list_value(char *buf, int val, signed char format); -static int list_nchar(char *buf, signed char c, int n); -static int list_char(char *buf, signed char c); -static int list_sp(char *buf); -static int list_word(char *buf, int outword); -static int list_word_f(char *buf, int outword, signed char format); -static int list_byte(char *buf, int outbyte); -static int list_byte_f(char *buf, int outbyte, signed char format); -static int list_nibble_f(char *buf, int outnib, signed char format); - -// set number of bytes per line displayed as hex -void list_setbytes(int number_of_bytes_per_line) { - list_numbytes = number_of_bytes_per_line; -} - -/* set line number for the coming listing output */ -void list_line(int l) { - list_lineno = l; -} - -/* set file name for the coming listing output */ -void list_filename(char *fname) { - if (list_filenamep == NULL || (fname != NULL && strcmp(fname, list_filenamep) != 0)) { - list_filenamep = fname; - list_lineno = 1; - list_last_lineno = 0; - - /* Hack */ - if (listfp != NULL) { - fprintf(listfp, "\n%s\n\n", fname); - } - } -} - -/** - * set the output file descriptor where to write the listing - */ -void list_setfile(FILE *fp) { - listfp = fp; -} - -char *list_preamble(char *buf, int lineno, int seg, int pc) { - /* line number in file */ - snprintf(buf, 10, "% 5d", lineno); - int i = strlen(buf); - buf += i; - buf += list_char(buf, ' '); - - char c = '?'; - /* preamble ':'
' ' */ - switch(seg) { - case SEG_ABS: c='A'; break; - case SEG_TEXT: c='T'; break; - case SEG_BSS: c='B'; break; - case SEG_DATA: c='D'; break; - case SEG_UNDEF: c='U'; break; - case SEG_ZERO: c='Z'; break; - } - buf = buf + list_char(buf, c); - buf = buf + list_char(buf, ':'); - buf = buf + list_word(buf, pc); - buf = buf + list_nchar(buf, ' ', 2); - - return buf; -} - - -/** - * listing/listing_len give the buffer address and length respectively that contains - * the token as they are produced by the tokenizer. - * bincode/bincode_len give the buffer address and length that contain the binary code - * that is produced from the token listing - * - * Note that both lengths may be zero - */ -void do_listing(signed char *listing, int listing_len, signed char *bincode, int bincode_len) { - - int i, n_hexb; - - char outline[MAXLINE]; - char *buf = outline; - - int lst_seg = listing[0]; - int lst_pc = (listing[2]<<8) | (listing[1] & 255); - - /* no output file (not even stdout) */ - if (listfp == NULL) return; - - /*printf("do_listing: listing=%p (%d), bincode=%p (%d)\n", listing, listing_len, bincode, bincode_len);*/ - - if (bincode_len < 0) bincode_len = -bincode_len; - - /* do we need a separation line? */ - if (list_lineno > list_last_lineno+1) { - /* yes */ - /*fprintf(listfp, "line=%d, last=%d\n", list_lineno, list_last_lineno);*/ - fprintf(listfp, "\n"); - } - list_last_lineno = list_lineno; - - buf = list_preamble(buf, list_lineno, lst_seg, lst_pc); - - // check if we have labels, so we can adjust the max printable number of - // bytes in the last line - int num_last_line = 11; - int tmp = listing[3] & 255; - if (tmp == (T_DEFINE & 255)) { - // we have label definition - num_last_line = 8; - } - int overflow = 0; - - /* binary output (up to 8 byte. If more than 8 byte, print 7 plus "..." */ - n_hexb = bincode_len; - if (list_numbytes != 0 && n_hexb >= list_numbytes) { - n_hexb = list_numbytes-1; - overflow = 1; - } - for (i = 0; i < n_hexb; i++) { - buf = buf + list_byte(buf, bincode[i]); - buf = buf + list_sp(buf); - if ( (i%16) == 15) { - // make a break - buf[0] = 0; - fprintf(listfp, "%s\n", outline); - buf = outline; - buf = list_preamble(buf, list_lineno, lst_seg, lst_pc + i + 1); - } - } - if (overflow) { - // are we at the last byte? - if (n_hexb + 1 == bincode_len) { - // just print the last byte - buf = buf + list_byte(buf, bincode[i]); - buf = buf + list_sp(buf); - } else { - // display "..." - buf = buf + list_nchar(buf, '.', 3); - } - n_hexb++; - } - i = n_hexb % 16; - if (i > num_last_line) { - // make a break (Note: with original PC, as now the assembler text follows - buf[0] = 0; - fprintf(listfp, "%s\n", outline); - buf = outline; - buf = list_preamble(buf, list_lineno, lst_seg, lst_pc); - i = 0; - } - i = num_last_line - i; - buf = buf + list_nchar(buf, ' ', i * 3); - - buf = buf + list_sp(buf); - - buf += list_tokens(buf, listing + 3, listing_len - 3); - -#ifdef LISTING_DEBUG - /* for now only do a hex dump so we see what actually happens */ - i = buf - outline; - if (i<80) buf += list_nchar(buf, ' ', 80-i); - - buf += list_string(buf, " >>"); - for (i = 3; i < listing_len; i++) { - buf = buf + list_byte(buf, listing[i]); - buf = buf + list_sp(buf); - } -#endif - buf[0] = 0; - - fprintf(listfp, "%s\n", outline); -} - -int list_tokens(char *buf, signed char *input, int len) { - int outp = 0; - int inp = 0; - int tmp; - char *name; - signed char c; - label_t is_cll; - int tabval; - signed char format; - - if (inp >= len) return 0; - - tmp = input[inp] & 255; - - tabval = 0; - if (tmp == (T_DEFINE & 255)) { - while (inp < len && tmp == (T_DEFINE & 255)) { - tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); -/*printf("define: len=%d, inp=%d, tmp=%d\n", len, inp, tmp);*/ - name=l_get_name(tmp, &is_cll); - if (is_cll == CHEAP) { - outp += list_char(buf+outp, '@'); - } else - if (is_cll == UNNAMED_DEF || is_cll == UNNAMED) { - outp += list_char(buf+outp, ':'); - } - if (is_cll != UNNAMED) { - tmp = list_string(buf+outp, name); - tabval += tmp + 1 + is_cll; - outp += tmp; - } - outp += list_char(buf+outp, ' '); - inp += 3; - tmp = input[inp] & 255; - } - if (tabval < 10) { - outp += list_nchar(buf+outp, ' ', 10-tabval); - } - } else { - if (tmp >= 0 && tmp < Anzkey) { - outp += list_string(buf+outp, " "); - } - } - - if (tmp >= 0 && tmp < Anzkey) { - /* assembler keyword */ - /*printf("tmp=%d, kt[tmp]=%p\n", tmp, kt[tmp]);*/ - if (kt[tmp] != NULL) { - outp += list_string(buf+outp, kt[tmp]); - } - outp += list_sp(buf + outp); - inp += 1; - - if (tmp == Kinclude) { - /* just another exception from the rule... */ - /* next char is terminator (", ') then the length and then the file name */ - char term = input[inp]; - int len = input[inp+1] & 255; - outp += list_char(buf+outp, term); - for (tmp = 2; tmp < len+2; tmp++) { - outp += list_char(buf+outp, input[inp+tmp]); - } - outp += list_char(buf+outp, term); - inp += len + 2; - } - } - - while (inp < len) { - int operator = 0; - - switch(input[inp]) { - case T_CAST: - outp += list_char(buf+outp, input[inp+1]); - break; - case T_VALUE: - /*outp += list_char(buf+outp, 'V');*/ - /* 24 bit value */ - tmp = ((input[inp+3]&255)<<16) | ((input[inp+2]&255)<<8) | (input[inp+1]&255); - format = input[inp+4]; - outp += list_value(buf+outp, tmp, format); - inp += 5; - operator = 1; /* check if arithmetic operator follows */ - break; - case T_LABEL: - /*outp += list_char(buf+outp, 'L');*/ - /* 16 bit label number */ - tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); - name=l_get_name(tmp, &is_cll); - if (is_cll == CHEAP) { - outp += list_char(buf+outp, '@'); - } else - if (is_cll == UNNAMED || is_cll == UNNAMED_DEF) { - outp += list_char(buf+outp, ':'); - } - if (is_cll != UNNAMED) { - outp += list_string(buf+outp, name); - } - inp += 3; - operator = 1; /* check if arithmetic operator follows */ - break; - case T_OP: - /* label arithmetic operation; inp[3] is operation like '=' or '+' */ - tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); - name=l_get_name(tmp, &is_cll); - if (is_cll) outp += list_char(buf+outp, '@'); - outp += list_string(buf+outp, name); - outp += list_char(buf+outp, input[inp+3]); - inp += 4; - - break; - case T_END: - /* end of operation */ - /*outp += list_string(buf+outp, ";");*/ - inp += 1; - goto end; - break; - case T_COMMENT: - if (inp > 0 && inp < 20) { - outp += list_nchar(buf+outp, ' ', 20-inp); - } - tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255); - outp += list_char(buf+outp, ';'); - outp += list_string(buf+outp, (char*)input+inp+3); - inp += tmp + 3; - break; - case T_LINE: - case T_FILE: - /* those two are meta-tokens, evaluated outside the t_p2 call, - * they result in calls to list_line(), list_filename() */ - break; - case T_POINTER: - /* what is this? It's actually resolved during token conversion */ - tmp = ((input[inp+5]&255)<<8) | (input[inp+4]&255); - name=l_get_name(tmp, &is_cll); - if (is_cll) outp += list_char(buf+outp, '@'); - outp += list_string(buf+outp, name); - /* - outp += list_byte(buf+outp, input[inp+1]); - outp += list_char(buf+outp, '#'); - tmp = ((input[inp+3]&255)<<8) | (input[inp+2]&255); - outp += list_value(buf+outp, tmp); - */ - inp += 6; - operator = 1; /* check if arithmetic operator follows */ - break; - case '"': - // string display - inp++; - outp += list_char(buf+outp, '"'); - int len = input[inp] & 0xff; - for (int i = 0; i < len; i++) { - inp++; - outp += list_char(buf+outp, input[inp]); - } - inp++; - outp += list_char(buf+outp, '"'); - break; - default: - c = input[inp]; - if (c > 31) { - outp += list_char(buf+outp, input[inp]); - } else { - outp += list_char(buf+outp, '\''); - outp += list_byte(buf+outp, input[inp]); - } - inp += 1; - break; - } - - if (operator && inp < len) { - signed char op = input[inp]; - if (op > 0 && op <= 17) { - outp += list_string(buf+outp, arith_ops[op]); - inp += 1; - } - operator = 0; - } - } -end: - return outp; -} - -int list_string(char *buf, char *string) { - int p = 0; - while (string[p] != 0) { - buf[p] = string[p]; - p++; - } - return p; -} - -int list_value(char *buf, int val, signed char format) { - int p = 0; - char valbuf[32]; - - switch (format) { - case '$': - p += list_char(buf + p, '$'); - if (val & (255<<16)) { - p += list_byte(buf+p, val>>16); - p += list_word(buf+p, val); - } else - if (val & (255<<8)) { - p += list_word(buf+p, val); - } else { - p += list_byte(buf+p, val); - } - break; - case '%': - p += list_char(buf + p, '%'); - if (val & (255<<16)) { - p += list_byte_f(buf+p, val>>16,'%'); - p += list_word_f(buf+p, val,'%'); - } else - if (val & (255<<8)) { - p += list_word_f(buf+p, val,'%'); - } else { - p += list_byte_f(buf+p, val,'%'); - } - break; - case '&': - snprintf(valbuf, 32, "%o",val); - p+= list_char(buf+p, '&'); - p+= list_string(buf+p, valbuf); - break; - case 'd': - snprintf(valbuf, 32, "%d",val); - p+= list_string(buf+p, valbuf); - break; - case '\'': - case '"': - p+= list_char(buf+p, format); - p+= list_char(buf+p, val); - p+= list_char(buf+p, format); - break; - default: - /* hex format as fallback */ - p += list_char(buf + p, '$'); - if (val & (255<<16)) { - p += list_byte(buf+p, val>>16); - p += list_word(buf+p, val); - } else - if (val & (255<<8)) { - p += list_word(buf+p, val); - } else { - p += list_byte(buf+p, val); - } - break; - } - return p; -} - -int list_nchar(char *buf, signed char c, int n) { - int i; - for (i = 0; i < n; i++) { - buf[i]=c; - } - return n; -} - -int list_char(char *buf, signed char c) { - buf[0] = c; - return 1; -} - -int list_sp(char *buf) { - buf[0] = ' '; - return 1; -} - -int list_word(char *buf, int outword) { - return list_word_f(buf, outword, '$'); -} - -int list_word_f(char *buf, int outword, signed char format) { - int p = 0; - p+= list_byte_f(buf+p, outword >> 8, format); - p+= list_byte_f(buf+p, outword, format); - return p; -} - -int list_byte(char *buf, int outbyte) { - return list_byte_f(buf, outbyte, '$'); -} - -int list_byte_f(char *buf, int outbyte, signed char format) { - int p = 0; - p+= list_nibble_f(buf+p, (outbyte >> 4), format); - p+= list_nibble_f(buf+p, outbyte, format); - return p; -} - -int list_nibble_f(char *buf, int outnib, signed char format) { - int p = 0; - outnib = outnib & 0xf; - switch(format) { - case '$': - if (outnib < 10) { - buf[p]='0'+outnib; - } else { - buf[p]='a'-10+outnib; - } - p++; - break; - case '%': - buf[p++] = (outnib&8)?'1':'0'; - buf[p++] = (outnib&4)?'1':'0'; - buf[p++] = (outnib&2)?'1':'0'; - buf[p++] = (outnib&1)?'1':'0'; - break; - default: - /* hex as default */ - if (outnib < 10) { - buf[p]='0'+outnib; - } else { - buf[p]='a'-10+outnib; - } - p++; - break; - } - return p; -} - - diff --git a/xa/src/xat.h b/xa/src/xat.h index cd684bc..13be740 100644 --- a/xa/src/xat.h +++ b/xa/src/xat.h @@ -29,4 +29,8 @@ int b_term(char *s, int *v, int *l, int pc); void list_line(int l); /* set line number for the coming listing output */ void list_filename(char *fname);/* set file name for the coming listing output */ +extern char *kt[]; // table of key words, needed for listing +extern char *arith_ops[]; // table of arithmetic operators, needed for listing +extern int number_of_valid_tokens; // as it says, in the "kt" table + #endif /* __XA65_XAT_H__ */ diff --git a/xa/tests/listing/Makefile b/xa/tests/listing/Makefile index f151618..a225637 100644 --- a/xa/tests/listing/Makefile +++ b/xa/tests/listing/Makefile @@ -4,9 +4,13 @@ XA=../../xa -tests: linebreak clean +tests: linebreak include1 clean +include1: include1.a65 + ${XA} -P- $< > a.out + cmp include1.out a.out + linebreak: linebreak.a65 ${XA} -P- $< > a.out cmp linebreak.out a.out diff --git a/xa/tests/listing/include1.a65 b/xa/tests/listing/include1.a65 new file mode 100644 index 0000000..070429e --- /dev/null +++ b/xa/tests/listing/include1.a65 @@ -0,0 +1,8 @@ + + .org $1000 + +#include "include1a.a65" + +.include "include1a.a65" + + diff --git a/xa/tests/listing/include1.out b/xa/tests/listing/include1.out new file mode 100644 index 0000000..4b6a923 --- /dev/null +++ b/xa/tests/listing/include1.out @@ -0,0 +1,23 @@ + +include1.a65 + + + 2 A:1000 *= $1000 + +include1a.a65 + + + 2 A:1000 a9 00 lda #$00 + +include1.a65 + + + 6 A:1002 .include "include1a.a65" + +include1a.a65 + + + 2 A:1002 a9 00 lda #$00 + +include1.a65 + diff --git a/xa/tests/listing/include1a.a65 b/xa/tests/listing/include1a.a65 new file mode 100644 index 0000000..554af8f --- /dev/null +++ b/xa/tests/listing/include1a.a65 @@ -0,0 +1,3 @@ + + lda #$00 +