1
0
mirror of https://github.com/fachat/xa65.git synced 2024-06-22 06:29:28 +00:00

break out listing code from xat.c into separate file

This commit is contained in:
fachat 2012-07-30 14:14:39 +02:00
parent f296538a90
commit 93d832b04a
9 changed files with 623 additions and 519 deletions

View File

@ -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

550
xa/src/xalisting.c Normal file
View File

@ -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 <stdio.h>
#include <string.h>
#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 <segment>':'<address>' ' */
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;
}

24
xa/src/xalisting.h Normal file
View File

@ -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__ */

View File

@ -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 <segment>':'<address>' ' */
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;
}

View File

@ -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__ */

View File

@ -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

View File

@ -0,0 +1,8 @@
.org $1000
#include "include1a.a65"
.include "include1a.a65"

View File

@ -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

View File

@ -0,0 +1,3 @@
lda #$00