Merge branch 'testsuite' into testmerge

Resolved Conflicts:
	xa/ChangeLog
	xa/src/xa.c
	xa/tests/adrm/Makefile
	xa/tests/binclude/Makefile
	xa/tests/charset/Makefile
	xa/tests/comcom/Makefile
	xa/tests/fordef/Makefile
	xa/tests/incerr/Makefile
This commit is contained in:
A. Fachat 2014-08-20 22:13:20 +02:00
commit bd65f3de18
117 changed files with 4246 additions and 562 deletions

5
README
View File

@ -13,3 +13,8 @@ These are the directories:
xa - contains the main source. The master branch is the stable version (currently 2.3.5)
These are the current branches:
master - stable branch, currently 2.3.5
listing - experimental branch that adds ca65 compatibility features and assembler listing

View File

@ -304,3 +304,24 @@ xa-2.3.6
* Fixed message offsets.
-- Cameron Kaiser <ckaiser@floodgap.com> 11 July 2014
xa-2.x.x
* Add -E commandline option to not stop after 20 errors, but show all
of them
* Introduce -X compatibility set commandline option, to distinguish
between MASM and CA65 compatibility options
* Implement CA65 "cheap local labels", ":=" label definitions,
and various pseudo opcodes (.include, .import, .importzp,
.zeropage, .proc (anonymous only), .endproc, .code, .org, .reloc)
* some bugfixes around error/warning logs
* some more comments
* Stuff is mostly untested...
-- André Fachat <afachat@gmx.de> 25 June, 2011
xa-2.x.x
* add test suite code
-- André Fachat <afachat@gmx.de> 20 August, 2014

10
xa/TODO
View File

@ -8,3 +8,13 @@ o inc a -> ina, dec a -> dea (right now uses bare inc and dec)
o VICE label file support
o Smarter -X that can cope with non-block-aligned segment sizes
o The listing feature is not bug-free yet:
- ca65 and other assembler compatibility pseudo-opcodes will be
listed as xa specific ones, not the original in the source
E.g. a CA65 ".scope" will appear as ".(" in the listing
- The assembler has no constant handling, so constants are
resolved at parse time. Thus they appear as their value
in the listing. Only situation now is ".listbytes unlimited",
which will show as ".listbytes 0" in the listing

View File

@ -40,8 +40,9 @@ respectively. Not valid for bss or zero.
.B \-X
Extract text and data segment together
from the file instead of writing back the whole
file. Relocating data segment to the end of the text segment
(ignoring the \-xd option) before extracting.
file. Relocating data segment to the end of the text segment and
bss segment to the end of the data segment
(\-xd and \-xb options override the derived address) before extracting.
.TP
.B \-\-help
Show summary of options.

View File

@ -19,6 +19,9 @@ further in this manual page.
.SH OPTIONS
.TP
.B \-E
Do not stop after 20 errors, but show all errors.
.TP
.B \-v
Verbose output.
.TP
@ -54,6 +57,15 @@ use the special filename
.BR \-
to output to standard output.
.TP
.B \-P filename
Set listing filename, default is none. use the special filename
.BR \-
to print the listing to standard output.
.TP
.B \-F html
Set listing format, default is plain. The only other currently supported format is
.BR html
.TP
.B \-e filename
Set errorlog filename, default is none.
.TP
@ -67,12 +79,27 @@ to reconstruct source.
Add cross-reference list to labellist (requires
.BR \-l ).
.TP
.B \-Xcompatset
Enables compatibility settings to become more (not fully!) compatible with other 6502 assemblers.
Currently supported are compatibility set "MASM" and "CA65".
"MASM" allows colons to appear in comments. This does not affect colon interpretation elsewhere.
"CA65" allows the ":=" label definition (instead of "="), It adds the "unnamed labels" and also the
"cheap local labels" using
the "@" character. This, however, disables the "@" 24-bit enforcement.
"C" enables the usage of "0xHEX" and "0OCTAL" C-style number encodings. Note that you can combine
compatibility sets e.g. with "-XCA65 -XC".
.TP
.B \-M
Allow colons to appear in comments; for MASM compatibility. This does
not affect colon interpretation elsewhere.
not affect colon interpretation elsewhere. This option is deprecated. Use
.BR -X
instead.
.TP
.B \-R
Start assembler in relocating mode.
Start assembler in relocating mode, i.e. use segments.
.TP
.B \-U
Do not allow undefined labels in relocating mode.
.TP
.B \-Llabel
Defines
@ -339,7 +366,7 @@ for those opcodes that support it (i.e., keep as 16 bit word)
.B @
render as 24-bit quantity for 65816 (must specify
.B \-w
command-line option).
command-line option, must not specify the CA65 compatibility).
.B This is required to specify any
.B 24-bit quantity!
.TP
@ -441,7 +468,7 @@ and
are synonymous, so you can mix things such as
.B .byt $43, 22, """a character string"""
and get the expected result. The string is subject to the current character
set, but the remaining bytes are inserted wtihout modification.
set, but the remaining bytes are inserted without modification.
.TP
.B .aasc """text1""","text2",...
Specifies a character string that is
@ -491,10 +518,21 @@ a block, precede the label with
or precede it with
.B &
to declare it within the previous level only (or globally if you are only
one level deep). Sixteen levels of scoping are permitted.
one level deep). Sixteen levels of scoping are permitted.
.B \&.)
is equivalent to
.B .block
or
.B .proc
. The latter is similar to the ca65 pseudo-opcode, but only anonymous blocks
are supported.
.TP
.B \&.)
Closes a block.
Closes a block. This is equivalent to
.B .bend
or
.B .endproc
.
.TP
.B \.as \.al \.xs \.xl
Only relevant in 65816 mode (with the
@ -521,6 +559,11 @@ and
generate errors if
.B \-w
is not specified.
.TP
.B .include "filename"
Includes another file in place of the pseudo opcode. Same as the preprocessor
.B #include
.LP
The following pseudo-ops apply primarily to relocatable .o65 objects.
A full discussion of the relocatable format is beyond the
@ -538,6 +581,11 @@ space for allocation and .zero being uninitialized zero page space for
allocation. In .bss and .zero, only labels are evaluated. These pseudo-ops
are valid in relative and absolute modes.
.TP
.B .code
For CA65 compatibility this is currently mapped to ".text".
.B .zeropage
For CA65 compatibility this is currently mapped to ".zero".
.TP
.B .align value
Aligns the current segment to a byte boundary (2, 4 or 256) as specified by
.B
@ -555,6 +603,17 @@ is used to specify the file option being referenced. A table of these options
is in the relocatable o65 file format description. The remainder of the options
are interpreted as values to insert. Any number of values may be specified,
and may also be strings.
.TP
.B .import label1, label2, label3, ...
Defines the given labels as global labels which are imported and resolved during
the link stage. Similar to the
.B -L
command line parameter
.TP
.B .importzp label1, label2, label3, ...
Similar to
.B .import
only it imports zeropage labels (i.e. byte values)
.SH PREPROCESSOR
@ -830,7 +889,7 @@ This manual page was written by David Weinehall <tao@acc.umu.se>,
Andre Fachat <fachat@web.de>
and Cameron Kaiser <ckaiser@floodgap.com>.
Original xa package (C)1989-1997 Andre Fachat. Additional changes
(C)1989-2009 Andre Fachat, Jolse Maginnis, David Weinehall,
(C)1989-2011 Andre Fachat, Jolse Maginnis, David Weinehall,
Cameron Kaiser. The official maintainer is Cameron Kaiser.
.SH WEBSITE

View File

@ -74,6 +74,7 @@ void usage(FILE *fp)
" -X extracts the file such that text and data\n"
" segments are chained, i.e. possibly relocating\n"
" the data segment to the end of the text segment\n"
" -v verbose output\n"
" --version output version information and exit\n"
" --help display this help and exit\n");
}
@ -86,6 +87,7 @@ int main(int argc, char *argv[]) {
int tbase = 0, dbase = 0, bbase = 0, zbase = 0;
char *outfile = "a.o65";
int extract = 0;
int verbose = 0;
if (argc <= 1) {
usage(stderr);
@ -106,6 +108,9 @@ int main(int argc, char *argv[]) {
if(argv[i][0]=='-') {
/* process options */
switch(argv[i][1]) {
case 'v':
verbose = 1;
break;
case 'o':
if(argv[i][2]) outfile=argv[i]+2;
else outfile=argv[++i];
@ -188,25 +193,53 @@ int main(int argc, char *argv[]) {
file.tbase = file.buf[ 9]*256+file.buf[ 8];
file.tlen = file.buf[11]*256+file.buf[10];
file.tdiff = tflag? tbase - file.tbase : 0;
file.tdiff = tflag ? tbase - file.tbase : 0;
file.dbase = file.buf[13]*256+file.buf[12];
file.dlen = file.buf[15]*256+file.buf[14];
file.ddiff = dflag ? dbase - file.dbase : 0;
if (extract == 3) {
if (dflag) {
fprintf(stderr,"reloc65: %s: Warning: data segment address ignored for -X option\n", argv[i]);
}
dbase = file.tbase + file.tdiff + file.tlen;
file.ddiff = dbase - file.dbase;
} else {
file.ddiff = dflag? dbase - file.dbase : 0;
fprintf(stderr,"reloc65: %s: Warning: data segment address overrides -X option\n", argv[i]);
} else {
dbase = file.tbase + file.tdiff + file.tlen;
file.ddiff = dbase - file.dbase;
}
}
file.bbase = file.buf[17]*256+file.buf[16];
file.blen = file.buf[19]*256+file.buf[18];
file.bdiff = bflag? bbase - file.bbase : 0;
file.zbase = file.buf[21]*256+file.buf[20];
file.zlen = file.buf[23]*256+file.buf[21];
file.zdiff = zflag? zbase - file.zbase : 0;
file.bdiff = bflag ? bbase - file.bbase : 0;
if (extract == 3) {
if (bflag) {
fprintf(stderr,"reloc65: %s: Warning: bss segment address overrides -X option\n", argv[i]);
} else {
bbase = file.dbase + file.ddiff + file.dlen;
file.bdiff = bbase - file.bbase;
}
}
file.zbase = file.buf[21]*256+file.buf[20];
file.zlen = file.buf[23]*256+file.buf[22];
file.zdiff = zflag ? zbase - file.zbase : 0;
if (verbose) {
printf("Relocating segments to:\n");
printf("text segment @ $%04x - $%04x, %5d ($%04x) bytes, diff is %5d ($%04x)\n",
file.tbase + file.tdiff, file.tbase + file.tdiff + file.tlen,
file.tlen, file.tlen, file.tdiff, file.tdiff & 0xffff);
printf("data segment @ $%04x - $%04x, %5d ($%04x) bytes, diff is %5d ($%04x)\n",
file.dbase + file.ddiff, file.dbase + file.ddiff + file.dlen,
file.dlen, file.dlen, file.ddiff, file.ddiff & 0xffff);
printf("bss segment @ $%04x - $%04x, %5d ($%04x) bytes, diff is %5d ($%04x)\n",
file.bbase + file.bdiff, file.bbase + file.bdiff + file.blen,
file.blen, file.blen, file.bdiff, file.bdiff & 0xffff);
printf("zero segment @ $%04x - $%04x, %5d ($%04x) bytes, diff is %5d ($%04x)\n",
file.zbase + file.zdiff, file.zbase + file.zdiff + file.zlen,
file.zlen, file.zlen, file.zdiff, file.zdiff & 0xffff);
}
/* pointer of position in file */
file.segt = file.buf + hlen;
file.segd = file.segt + file.tlen;
file.utab = file.segd + file.dlen;

2
xa/src/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*.o

View File

@ -1,7 +1,8 @@
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 -pedantic -ansi -g
#CFLAGS=-W -Wall -ansi -O2
CFLAGS=-g -std=c99
#LD = ${CC}
#LDFLAGS = "-lc"

View File

@ -45,6 +45,7 @@
#include "xar.h"
#include "xat.h"
#include "xacharset.h"
#include "xalisting.h"
#include "version.h"
@ -55,26 +56,33 @@
#define ANZWARN 13
#define programname "xa"
#define progversion "v2.3.6"
#define progversion "v2.3.6+af"
#define authors "Written by Andre Fachat, Jolse Maginnis, David Weinehall and Cameron Kaiser"
#define copyright "Copyright (C) 1989-2014 Andre Fachat, Jolse Maginnis, David Weinehall\nand Cameron Kaiser."
/* exported globals */
int ncmos, cmosfl, w65816, n65816;
int masm = 0;
/* compatibility flags */
int masm = 0; /* MASM */
int ca65 = 0; /* CA65 */
int ctypes = 0; /* C compatibility, like "0xab" types */
int nolink = 0;
int romable = 0;
int romaddr = 0;
int noglob = 0;
int showblk = 0;
int crossref = 0;
int noundef = 0; // overrides -R acceptance of undefined labels
char altppchar;
/* local variables */
static char out[MAXLINE];
static time_t tim1, tim2;
static FILE *fpout, *fperr, *fplab;
static FILE *fpout, *fperr, *fplab, *fplist;
static int ner = 0;
static int ner_max = 20;
static int align = 1;
@ -85,12 +93,14 @@ static int x_init(void);
static int pass1(void);
static int pass2(void);
static int puttmp(int);
static int puttmpw(int);
static int puttmps(signed char *, int);
static void chrput(int);
static int xa_getline(char *);
static void lineout(void);
static long ga_p1(void);
static long gm_p1(void);
static int set_compat(char *compat_name);
/* text */
int memode,xmode;
@ -110,6 +120,8 @@ int main(int argc,char *argv[])
signed char *s=NULL;
char *tmpp;
char *listformat = NULL;
int mifiles = 5;
int nifiles = 0;
int verbose = 0;
@ -117,9 +129,10 @@ int main(int argc,char *argv[])
int no_link = 0;
char **ifiles;
char *ofile;
char *efile;
char *lfile;
char *printfile; /* print listing to this file */
char *ofile; /* output file */
char *efile; /* error listing goes there */
char *lfile; /* labels go here */
char *ifile;
char old_e[MAXLINE];
@ -173,6 +186,7 @@ int main(int argc,char *argv[])
ofile="a.o65";
efile=NULL;
lfile=NULL;
printfile=NULL;
if(pp_init()) {
logout("fatal: pp: no memory!");
@ -191,6 +205,9 @@ int main(int argc,char *argv[])
while(i<argc) {
if(argv[i][0]=='-') {
switch(argv[i][1]) {
case 'E':
ner_max = 0;
break;
case 'p':
/* intentionally not allowing an argument to follow with a
space to avoid - being seen as the alternate
@ -210,6 +227,19 @@ int main(int argc,char *argv[])
case 'M':
masm = 1; /* MASM compatibility mode */
break;
case 'X': /* compatibility across assemblers... */
{
char *name = NULL;
if (argv[i][2] == 0) {
name = argv[++i];
} else {
name = argv[i]+2;
}
if (set_compat(name) < 0) {
fprintf(stderr, "Compatibility set '%s' unknown - ignoring! (check case?)\n", name);
}
}
break;
case 'O': /* output charset */
{
char *name = NULL;
@ -241,6 +271,9 @@ int main(int argc,char *argv[])
case 'R':
relmode = 1;
break;
case 'U':
noundef = 1;
break;
case 'D':
s = (signed char*)strstr(argv[i]+2,"=");
if(s) *s = ' ';
@ -276,6 +309,20 @@ int main(int argc,char *argv[])
reg_include(argv[i]+2);
}
break;
case 'P':
if(argv[i][2]==0) {
printfile=argv[++i];
} else {
printfile=argv[i]+2;
}
break;
case 'F':
if (argv[i][2]==0) {
listformat = argv[++i];
} else {
listformat = argv[i]+2;
}
break;
case 'o':
if(argv[i][2]==0) {
ofile=argv[++i];
@ -356,6 +403,12 @@ int main(int argc,char *argv[])
if(setfext(old_l,".lab")==0) lfile = old_l;
}
if (printfile!=NULL && !strcmp(printfile, "-")) {
printfile=NULL;
fplist = stdout;
} else {
fplist= printfile ? xfopen(printfile,"w") : NULL;
}
fplab= lfile ? xfopen(lfile,"w") : NULL;
fperr= efile ? xfopen(efile,"w") : NULL;
if(!strcmp(ofile,"-")) {
@ -371,6 +424,7 @@ int main(int argc,char *argv[])
if(verbose) fprintf(stderr, "%s\n",copyright);
if(1 /*!m_init()*/)
{
if(1 /*!b_init()*/)
@ -384,6 +438,8 @@ int main(int argc,char *argv[])
if(fperr) fprintf(fperr,"%s\n",copyright);
if(verbose) logout(ctime(&tim1));
list_setfile(fplist);
/* Pass 1 */
pc[SEG_ABS]= 0; /* abs addressing */
@ -406,7 +462,7 @@ int main(int argc,char *argv[])
if(verbose) logout(out);
er=pp_open(ifile);
puttmp(0);
puttmpw(0);
puttmp(T_FILE);
puttmp(0);
puttmp(0);
@ -459,6 +515,8 @@ int main(int argc,char *argv[])
{
if(verbose) logout("xAss65: Pass 2:\n");
list_start(listformat);
seg_pass2();
if(!relmode) {
@ -468,6 +526,8 @@ int main(int argc,char *argv[])
segment = SEG_TEXT;
}
er=pass2();
list_end();
}
if(fplab) printllist(fplab);
@ -476,9 +536,10 @@ int main(int argc,char *argv[])
if((!er) && relmode) seg_end(fpout); /* write reloc/label info */
if(fplist && fplist!=stdout) fclose(fplist);
if(fperr) fclose(fperr);
if(fplab) fclose(fplab);
if(fpout) fclose(fpout);
if(fpout && fpout!=stdout) fclose(fpout);
} else {
logout("fatal: x: no memory!\n");
@ -500,7 +561,12 @@ int main(int argc,char *argv[])
if(ner || er)
{
if (ner_max > 0) {
fprintf(stderr, "Break after %d error%c\n",ner,ner?'s':0);
} else {
/* ner_max==0, i.e. show all errors */
fprintf(stderr, "End after %d error%c\n",ner,ner?'s':0);
}
/*unlink();*/
if(ofile) {
unlink(ofile);
@ -615,39 +681,41 @@ static int pass2(void)
filep=&datei;
afile->mn.tmpe=0L;
while(ner<20 && afile->mn.tmpe<afile->mn.tmpz)
while((ner_max==0 || ner<ner_max) && afile->mn.tmpe<afile->mn.tmpz)
{
l=afile->mn.tmp[afile->mn.tmpe++];
// get the length of the entry (now two byte - need to handle the sign)
l = 255 & afile->mn.tmp[afile->mn.tmpe++];
l |= afile->mn.tmp[afile->mn.tmpe++] << 8;
ll=l;
//printf("%p: l=%d first=%02x\n", afile->mn.tmp+afile->mn.tmpe-1, l, 0xff & afile->mn.tmp[afile->mn.tmpe]);
if(!l)
{
if(afile->mn.tmp[afile->mn.tmpe]==T_LINE)
{
datei.fline=(afile->mn.tmp[afile->mn.tmpe+1]&255)+(afile->mn.tmp[afile->mn.tmpe+2]<<8);
afile->mn.tmpe+=3;
list_line(datei.fline); /* set line number of next listing output */
} else
if(afile->mn.tmp[afile->mn.tmpe]==T_FILE)
{
// copy the current line number from the current file descriptor
datei.fline=(afile->mn.tmp[afile->mn.tmpe+1]&255)+(afile->mn.tmp[afile->mn.tmpe+2]<<8);
// copy the pointer to the file name in the current file descriptor
// Note: the filename in the current file descriptor is separately malloc'd and
// thus save to store the pointer
memcpy(&datei.fname, afile->mn.tmp+afile->mn.tmpe+3, sizeof(datei.fname));
afile->mn.tmpe+=3+sizeof(datei.fname);
/*
datei.fname = malloc(strlen((char*) afile->mn.tmp+afile->mn.tmpe+3)+1);
if(!datei.fname) {
fprintf(stderr,"Oops, no more memory\n");
exit(1);
}
strcpy(datei.fname,(char*) afile->mn.tmp+afile->mn.tmpe+3);
afile->mn.tmpe+=3+strlen(datei.fname);
*/
list_filename(datei.fname); /* set file name of next listing output */
}
} else
{
/* do not attempt address mode optimization on pass 2 */
er=t_p2(afile->mn.tmp+afile->mn.tmpe,&ll,1,&al);
/* t_p2_l() includes the listing call to do_listing() */
er=t_p2_l(afile->mn.tmp+afile->mn.tmpe,&ll,&al);
if(er==E_NOLINE)
{
} else
@ -752,16 +820,14 @@ fprintf(stderr, "offset = %i length = %i fstart = %i flen = %i charo = %c\n",
static int pass1(void)
{
signed char o[MAXLINE];
int l,er,temp_er,al;
signed char o[2*MAXLINE]; /* doubled for token listing */
int l,er,al;
memode=0;
xmode=0;
tlen=0;
ner=0;
temp_er = 0;
/*FIXIT*/
while(!(er=xa_getline(s)))
{
@ -774,7 +840,7 @@ static int pass1(void)
case SEG_ZERO: zlen += al; break;
}
/*printf(": er= %d, l=%d, tmpz=%d\n",er,l,tmpz); */
//printf(": er= %d, l=%d\n",er,l);
if(l)
{
@ -782,14 +848,14 @@ static int pass1(void)
{
if(er==E_OKDEF)
{
if(!(er=puttmp(l)))
if(!(er=puttmpw(l)))
er=puttmps(o,l);
} else
if(er==E_NOLINE)
er=E_OK;
} else
{
if(!(er=puttmp(-l)))
if(!(er=puttmpw(-l)))
er=puttmps(o,l);
}
}
@ -827,6 +893,7 @@ static void usage(int default816, FILE *fp)
programname);
fprintf(fp,
" -v verbose output\n"
" -E do not break after 20 errors, but show all\n"
" -x old filename behaviour (overrides `-o', `-e', `-l')\n"
" This is deprecated and may disappear in future versions!\n"
" -C no CMOS-opcodes\n"
@ -842,11 +909,18 @@ static void usage(int default816, FILE *fp)
fprintf(fp,
" -e filename sets errorlog filename, default is none\n"
" -l filename sets labellist filename, default is none\n"
" -P filename sets filename for listing, default is none, '-' is stdout\n"
" -F format sets format for listing, default is plain, 'html' is current only other\n"
" supported format\n"
" -r adds crossreference list to labellist (if `-l' given)\n"
" -M allow ``:'' to appear in comments for MASM compatibility\n"
" -R start assembler in relocating mode\n");
" -Xcompatset set compatibility flags for other assemblers, known values are:\n"
" MASM, CA65\n"
" -R start assembler in relocating mode\n"
" -U do not allow undefined labels in relocating mode\n");
fprintf(fp,
" -Llabel defines `label' as absolute, undefined label even when linking\n"
" -p<c> replace preprocessor char '#' with custom, e.g. '-p!' replaces it with '!'\n"
" -b? addr set segment base address to integer value addr\n"
" `?' stands for t(ext), d(ata), b(ss) and z(ero) segment\n"
" (address can be given more than once, last one is used)\n");
@ -900,7 +974,7 @@ static char *ertxt[] = {
"NewFile",
"CMOS instruction used with -C",
"pp:Wrong parameter count",
"Illegal pointer arithmetic",
"Illegal pointer arithmetic (-26)",
"Illegal segment",
"File header option too long",
"File option not at file start (when ROM-able)",
@ -939,11 +1013,10 @@ static char *ertxt[] = {
"",
"",
"",
"",
/* warnings */
"Cutting word relocation in byte value",
"Byte relocation in word value",
"Illegal pointer arithmetic",
"Illegal pointer arithmetic (-66)",
"Address access to low or high byte pointer",
"High byte access to low byte pointer",
"Low byte access to high byte pointer",
@ -977,7 +1050,9 @@ static int x_init(void)
static int puttmp(int c)
{
int er=E_NOMEM;
/*printf("puttmp: afile=%p, tmp=%p, tmpz=%d\n",afile, afile?afile->mn.tmp:0, afile?afile->mn.tmpz:0);*/
//printf("puttmp: %02x -> %p \n",0xff & c, afile->mn.tmp+afile->mn.tmpz);
if(afile->mn.tmpz<TMPMEM)
{
afile->mn.tmp[afile->mn.tmpz++]=c;
@ -986,17 +1061,37 @@ static int puttmp(int c)
return(er);
}
static int puttmpw(int c)
{
int er=E_NOMEM;
//printf("puttmp: %02x -> %p \n",0xff & c, afile->mn.tmp+afile->mn.tmpz);
if(afile->mn.tmpz<TMPMEM-1)
{
afile->mn.tmp[afile->mn.tmpz++]= c & 0xff;
afile->mn.tmp[afile->mn.tmpz++]= (c >> 8) & 0xff;
er=E_OK;
}
return(er);
}
static int puttmps(signed char *s, int l)
{
int i=0,er=E_NOMEM;
// printf("puttmps %d bytes from %p to %p:", l, s, afile->mn.tmp+afile->mn.tmpz);
if(afile->mn.tmpz+l<TMPMEM)
{
while(i<l)
afile->mn.tmp[afile->mn.tmpz++]=s[i++];
while(i<l) {
//printf(" %02x", 0xff & s[i]);
afile->mn.tmp[afile->mn.tmpz++]=s[i++];
}
er=E_OK;
}
// printf("\n");
return(er);
}
@ -1026,25 +1121,19 @@ static int xa_getline(char *s)
if(ec==E_NEWLINE)
{
puttmp(0);
puttmpw(0);
puttmp(T_LINE);
puttmp((filep->fline)&255);
puttmp(((filep->fline)>>8)&255);
ec=E_OK;
puttmpw(filep->fline);
ec=E_OK;
}
else
if(ec==E_NEWFILE)
{
puttmp(0);
puttmpw(0);
puttmp(T_FILE);
puttmp((filep->fline)&255);
puttmp(((filep->fline)>>8)&255);
puttmpw(filep->fline);
puttmps((signed char*)&(filep->fname), sizeof(filep->fname));
/*
puttmps((signed char*)filep->fname,
1+(int)strlen(filep->fname));
*/
ec=E_OK;
}
} while(!ec && l[i]=='\0');
@ -1053,26 +1142,50 @@ static int xa_getline(char *s)
gl=0;
if(!ec || ec==E_EOF)
{
int startofline = 1;
do {
c=s[j]=l[i++];
if (c=='\"')
if (c=='\"') {
hkfl^=1;
if (c==';' && !hkfl)
}
if (c==';' && !hkfl) {
// start of comment
comcom = 1;
if (c=='\0')
break; /* hkfl = comcom = 0 */
if (c==':' && !hkfl && (!comcom || !masm)) {
gl=1;
break;
}
}
if (c=='\0') {
// end of line
break; /* hkfl = comcom = 0 */
}
if (c==':' && !hkfl) {
/* if the next char is a "=" - so that we have a ":=" - and we
we have ca65 compatibility, we ignore the colon */
// also check for ":+" and ":-"
if (((!startofline) && l[i]!='=' && l[i]!='+' && l[i]!='-') || !ca65 || comcom) {
/* but otherwise we check if it is in a comment and we have
MASM or CA65 compatibility, then we ignore the colon as well */
if(!comcom || !(masm || ca65)) {
/* we found a colon, so we keep the current line in memory
but return the part before the colon, and next time the part
after the colon, so we can parse C64 BASIC text assembler... */
gl=1;
break;
}
}
}
if (!isspace(c)) {
startofline = 0;
}
j++;
} while (c!='\0' && j<MAXLINE-1 && i<MAXLINE-1);
s[j]='\0';
} else
s[0]='\0';
#if 0
printf("got line: %s\n", s);
#endif
return(ec);
}
@ -1092,8 +1205,8 @@ static void lineout(void)
void errout(int er)
{
if (er<-ANZERR || er>-1) {
if(er>=-(ANZERR+ANZWARN) && er < -ANZERR) {
if (er<=-ANZERR || er>-1) {
if(er>=-(ANZERR+ANZWARN) && er <= -ANZERR) {
sprintf(out,"%s:line %d: %04x: Warning - %s\n",
filep->fname, filep->fline, pc[segment], ertxt[(-er)-1]);
} else {
@ -1129,3 +1242,31 @@ void logout(char *s)
fprintf(fperr,"%s",s);
}
/*****************************************************************/
typedef struct {
char *name;
int *flag;
} compat_set;
static compat_set compat_sets[] = {
{ "MASM", &masm },
{ "CA65", &ca65 },
{ "C", &ctypes },
{ NULL, NULL }
};
int set_compat(char *compat_name) {
int i = 0;
while (compat_sets[i].name != NULL) {
if (strcmp(compat_sets[i].name, compat_name) == 0) {
/* set appropriate compatibility flag */
(*compat_sets[i].flag) = 1;
return 0;
}
i++;
}
return -1;
}

View File

@ -22,11 +22,12 @@
#include "xah.h" /* For SEG_MAX */
extern int ncmos, cmosfl, w65816, n65816;
extern int masm, nolink;
extern int masm, ca65, nolink,noundef;
extern int noglob;
extern int showblk;
extern int relmode;
extern int crossref;
extern int ctypes;
extern char altppchar;
extern int tlen, tbase;

View File

@ -119,13 +119,15 @@ static int ag_term(signed char *s, int p, int *v, int *nafl, int *label)
if(s[pp]==T_LABEL)
{
er=l_get(cval(s+pp+1),v, &afl);
/* printf("label: er=%d, seg=%d, afl=%d, nolink=%d, fundef=%d\n",
er, segment, afl, nolink, fundef); */
//printf("label: er=%d, seg=%d, afl=%d, nolink=%d, fundef=%d\n",
// er, segment, afl, nolink, fundef);
if(er==E_NODEF && segment != SEG_ABS && fundef ) {
if( nolink || (afl==SEG_UNDEF)) {
if( (nolink && !noundef) || ((afl==SEG_UNDEF) || (afl==SEG_UNDEFZP))) {
er = E_OK;
*v = 0;
afl = SEG_UNDEF;
if(afl!=SEG_UNDEFZP) {
afl = SEG_UNDEF;
}
*label = cval(s+pp+1);
}
}
@ -135,7 +137,7 @@ static int ag_term(signed char *s, int p, int *v, int *nafl, int *label)
if(s[pp]==T_VALUE)
{
*v=lval(s+pp+1);
pp+=4;
pp+=5;
/* printf("value: v=%04x\n",*v); */
}
else
@ -143,7 +145,7 @@ static int ag_term(signed char *s, int p, int *v, int *nafl, int *label)
{
afl = s[pp+1];
*v=cval(s+pp+2);
pp+=4;
pp+=6;
/* printf("pointer: v=%04x, afl=%04x\n",*v,afl); */
}
else
@ -159,7 +161,7 @@ static int ag_term(signed char *s, int p, int *v, int *nafl, int *label)
*v *= mf;
while(!er && s[pp]!=')' && s[pp]!=']' && s[pp]!=',' && s[pp]!=T_END)
while(!er && s[pp]!=')' && s[pp]!=']' && s[pp]!=',' && s[pp]!=T_END && s[pp]!=T_COMMENT)
{
er=get_op(s,&o);
@ -169,7 +171,7 @@ static int ag_term(signed char *s, int p, int *v, int *nafl, int *label)
if(!(er=ag_term(s,pr[o],&w, nafl, label)))
{
if(afl || *nafl) { /* check pointer arithmetic */
if((afl == *nafl) && (afl!=SEG_UNDEF) && o==2) {
if((afl == *nafl) && (afl!=SEG_UNDEFZP) && (afl!=SEG_UNDEF) && o==2) {
afl = 0; /* substract two pointers */
} else
if(((afl && !*nafl) || (*nafl && !afl)) && o==1) {
@ -180,6 +182,8 @@ static int ag_term(signed char *s, int p, int *v, int *nafl, int *label)
} else {
if(segment!=SEG_ABS) {
if(!dsb_len) {
/*printf("ILLPOINTER=dsb_len=%d,segment=%d\n",dsb_len, segment);*/
/* e.g. adding two pointers, adding two undefined values */
er=E_ILLPOINTER;
}
}
@ -202,10 +206,18 @@ static int get_op(signed char *s, int *o)
*o=s[pp];
if(*o<1 || *o>17)
if(*o<1 || *o>17) {
/*
printf("*o=%d, pp=%d, s=%s\n", *o, pp, s);
for (int i=0; i< 10; i++) {
printf(" %02x", s[i]);
}
printf("\n");
*/
er=E_SYNTAX;
else
} else {
er=E_OK;
}
return(er);
}

View File

@ -31,11 +31,12 @@
#define cval(s) 256 * ((s)[1] & 255) + ((s)[0]&255)
#define lval(s) 65536 * ((s)[2] & 255) + 256 * ((s)[1] & 255) + ((s)[0] & 255)
#define wval(i, v) do { \
#define wval(i, v, f) do { \
t[i++] = T_VALUE; \
t[i++] = v & 255; \
t[i++] = (v >> 8) & 255; \
t[i++] = (v >> 16) & 255; \
t[i++] = f & 255; \
} while (0)
#endif /* __XA65_XAD_H__ */

View File

@ -20,15 +20,29 @@
#ifndef __XA65_XAH_H__
#define __XA65_XAH_H__
#define ANZLAB 5000 /* mal 14 -> Byte */
/*
* Note: the computations to get the number of bytes necessary to allocate are
* a historic remnant of the Atari ST (the original platform) not being able to efficiently allocate small chunks
* of memory so I had to allocate a large chunk myself and manage the tables myself.
* This has changed and some parts of xa65 are modified to just do a malloc() now.
* These fixed numbers should actually go away. AF 20110623
*/
#define ANZLAB 5000 /* multiplied by sizeof(Labtab) -> Byte */
#define LABMEM 40000L
#define MAXLAB 32
#define MAXBLK 16
#define MAXFILE 7
#define MAXLINE 2048
#define MAXPP 40000L
#define ANZDEF 2340 /* mal 14 -> Byte, ANZDEF * 14 < 32768 */
#define TMPMEM 200000L /* Zwischenspeicher von Pass1 nach Pass 2 */
#define ANZDEF 2340 /* multiplied by sizeof(List) -> Byte, ANZDEF * 20 < 32768 */
#define TMPMEM 2000000L /* temporary memory buffer from Pass1 to Pass 2 (includes all source, thus enlarged) */
typedef enum {
STD = 0,
CHEAP = 1,
UNNAMED = 2,
UNNAMED_DEF = 3
} label_t;
typedef struct LabOcc {
struct LabOcc *next;
@ -36,17 +50,27 @@ typedef struct LabOcc {
char *fname;
} LabOcc;
/**
* struct that defines a label, after it has been parsed
*/
typedef struct {
int blk;
int val;
int len;
int fl; /* 0 = label value not valid/known,
* 1 = label value known
* 2 = label value not known, external global label (imported on link)
*/
int afl; /* 0 = no address (no relocation), 1 = address label */
int nextindex;
label_t is_cll; /* 0 is normal label, 1 is cheap local label (used for listing) */
char *n;
struct LabOcc *occlist;
// within a block, make a linked list for the unnamed label counting
// use indexes, as the label table can be re-alloced (so pointers change)
// -1 is the "undef'd" end of list
int blknext;
int blkprev;
} Labtab;
typedef struct {
@ -71,20 +95,20 @@ typedef struct {
#define BUFSIZE 4096 /* File-Puffegroesse (wg Festplatte) */
#define E_OK 0 /* Fehlernummern */
#define E_SYNTAX -1 /* Syntax Fehler */
#define E_LABDEF -2 /* Label definiert */
#define E_NODEF -3 /* Label nicht definiert */
#define E_LABFULL -4 /* Labeltabelle voll */
#define E_LABEXP -5 /* Label erwartet */
#define E_NOMEM -6 /* kein Speicher mehr */
#define E_ILLCODE -7 /* Illegaler Opcode */
#define E_ADRESS -8 /* Illegale Adressierung */
#define E_OK 0 /* No error */
#define E_SYNTAX -1 /* Syntax error */
#define E_LABDEF -2 /* Label already defined (duplicate label definition) */
#define E_NODEF -3 /* Label not defined */
#define E_LABFULL -4 /* Label table full */
#define E_LABEXP -5 /* Label expected but not found */
#define E_NOMEM -6 /* out of memory */
#define E_ILLCODE -7 /* Illegal Opcode */
#define E_ADRESS -8 /* Illegal Addressing mode */
#define E_RANGE -9 /* Branch out of range */
#define E_OVERFLOW -10 /* Ueberlauf */
#define E_DIV -11 /* Division durch Null */
#define E_PSOEXP -12 /* Pseudo-Opcode erwartet */
#define E_BLKOVR -13 /* Block-Stack Uebergelaufen */
#define E_OVERFLOW -10 /* overflow */
#define E_DIV -11 /* Division by zero */
#define E_PSOEXP -12 /* Pseudo-Opcode expected but not found */
#define E_BLKOVR -13 /* Block-Stack overflow */
#define E_FNF -14 /* File not found (pp) */
#define E_EOF -15 /* End of File */
#define E_BLOCK -16 /* Block inkonsistent */
@ -126,18 +150,25 @@ typedef struct {
#define W_OVER16M -74 /* included binary over 16M in 65816 mode */
/* warnings 75-77 are placeholders */
#define T_VALUE -1
#define T_LABEL -2
#define T_OP -3
#define T_END -4
#define T_LINE -5
#define T_FILE -6
#define T_POINTER -7
/* Meta-values for the token list. Note must not overlap with the
* K* definitions in xat.c, which have outgrown the positive numbers
* and are now growing up from -128 ... */
#define T_VALUE -1 /* following is a 24 bit value in the token list */
#define T_LABEL -2 /* referring to a label, following the token is the 16bit label number */
#define T_OP -3 /* label oriented operation; following is the label number (16bit), plus the operation char (e.g. '+') */
#define T_END -4 /* end of line marker */
#define T_LINE -5 /* new line indicator; following is the 16 bit line number */
#define T_FILE -6 /* new file indicator; following is the 16 bit line number, then the file name (zero-term) */
#define T_POINTER -7 /* ??? */
#define T_COMMENT -8 /* unused */
#define T_DEFINE -9 /* define a label; inserted at conversion and discarded in pass1, only used in listing output */
#define T_LISTING -10 /* meta token, inserted after conversion before pass1, used after pass2 to create listing */
#define T_CAST -11 /* token inserted for a cast */
#define P_START 0 /* Prioritaeten fuer Arithmetik */
#define P_LOR 1 /* Von zwei Operationen wird immer */
#define P_LAND 2 /* die mit der hoeheren Prioritaet */
#define P_OR 3 /* zuerst ausgefuehrt */
#define P_START 0 /* arithmetic operation priorities */
#define P_LOR 1 /* of any two operations, the one with */
#define P_LAND 2 /* the higher priority will be done first */
#define P_OR 3
#define P_XOR 4
#define P_AND 5
#define P_EQU 6
@ -168,6 +199,8 @@ typedef struct {
#define SEG_ZERO 5
#define SEG_MAX 6
#define SEG_UNDEFZP 7 /* is being mapped to UNDEF */
typedef struct Fopt {
signed char *text; /* text after pass1 */
int len;
@ -188,8 +221,11 @@ typedef struct File {
int base[SEG_MAX];
int len[SEG_MAX];
struct {
// temporary memory between pass1 and pass2
signed char *tmp;
// write pointer
unsigned long tmpz;
// read pointer
unsigned long tmpe;
} mn;
struct {

View File

@ -48,7 +48,21 @@ static int b_fget(int*,int);
static int b_ltest(int,int);
static int b_get(int*);
static int b_test(int);
static int ll_def(char *s, int *n, int b);
static int ll_def(char *s, int *n, int b, label_t ltype);
static int b_link(int);
static int b_new(void);
static void cll_init();
static int cll_get();
static void cll_clear();
static int cll_getcur();
/*
static void unn_init();
static int unn_get();
static void unn_clear();
*/
/* local variables */
@ -69,6 +83,8 @@ static Labtab *ltp;
int l_init(void)
{
cll_init();
//unn_init();
return 0;
#if 0
int er;
@ -139,69 +155,168 @@ FILE *fp;
}
}
/**********************************************************************************
* cheap local labels
*/
static int cll_current = 0; /* the current cheap local labels block */
/**
* init the cheap local labels
*/
void cll_init() {
cll_current = 0;
}
/**
* get the block number for a new cheap local label block
*/
int cll_get() {
if (cll_current == 0) {
cll_current = b_new();
}
return cll_current;
}
/**
* clear the local labels
*/
void cll_clear() {
cll_current = 0;
}
int cll_getcur() {
return cll_current;
}
/**********************************************************************************/
/**
* define a global label (from the "-L" command line parameter)
*/
int lg_set(char *s ) {
int n, er;
er = ll_search(s,&n);
er = ll_search(s,&n, STD);
if(er==E_OK) {
fprintf(stderr,"Warning: global label doubly defined!\n");
} else {
if(!(er=ll_def(s,&n,0))) {
ltp=afile->la.lt+n;
ltp->fl=2;
ltp->afl=SEG_UNDEF;
}
if(!(er=ll_def(s,&n,0, STD))) {
return lg_import(n);
}
}
return er;
}
/**
* define a global label (from the .import pseudo opcode))
* "s" is a pointer to the first label character, end is at \0
* or at non-alphanumeric/_ char
*/
int lg_import(int n) {
int er=E_OK;
ltp=afile->la.lt+n;
ltp->fl=2;
ltp->afl=SEG_UNDEF;
return er;
}
/**
* define a global zeropage label (from the .importzp pseudo opcode))
* "s" is a pointer to the first label character, end is at \0
* or at non-alphanumeric/_ char
*/
int lg_importzp(int n) {
int er=E_OK;
ltp=afile->la.lt+n;
ltp->fl=2;
ltp->afl=SEG_UNDEFZP;
return er;
}
/**********************************************************************************/
int l_def(char *s, int *l, int *x, int *f)
{
int n,er,b,i=0;
label_t cll_fl;
*f=0;
b=0;
n=0;
*f=0; /* flag (given as param) that the label is to be re-defined and the
"label defined error" is to be skipped */
b=0; /* block level on block stack, resp. block number */
n=0; /* flag, when set, b is absolute block number and not being translated */
cll_fl=STD; /* when 0, clear the cheap local label block */
if(s[0]==':') {
// ca65 unnamed label
i++;
//n++; /* block number b is absolute */
//b=unn_get(); /* current (possibly newly allocated) unnamed label block */
cll_fl = UNNAMED; // keep the cheap local label block
} else
if(s[0]=='-')
{
*f+=1;
*f+=1; /* label is being redefined */
i++;
} else
if(s[0]=='@')
{
i++;
n++; /* block number b is absolute */
b=cll_get(); /* current (possibly newly allocated) cheap label block */
cll_fl=CHEAP; /* do not clear the cll block again... */
} else
if(s[0]=='+')
{
i++;
n++;
b=0;
n++; /* block number b is absolute */
b=0; /* global block number */
}
while(s[i]=='&')
{
n=0;
if (n) b=0; /* reset block number */
n=0; /* block number is relative */
i++;
b++;
b++; /* one (more) level up the block stack */
}
if(!n)
if(!n) {
/* translate from block stack level to absolute block number */
b_fget(&b,b);
}
if(cll_fl == STD) {
/* clear cheap local labels */
cll_clear();
}
if(!isalpha(s[i]) && s[i]!='_')
if((!isalpha(s[i])) && (s[i]!='_') && !(ca65 && ((cll_fl == UNNAMED) || isdigit(s[i])) ) ) {
//printf("SYNTAX cll_fl=%d, i=%d, s[i]=%02x (%c)\n", cll_fl, i, s[i], s[i]);
er=E_SYNTAX;
else
} else
{
er=ll_search(s+i,&n);
er = E_NODEF;
if (cll_fl != UNNAMED) {
er=ll_search(s+i,&n, cll_fl);
}
if(er==E_OK)
{
/* we actually found an existing label in the same scope */
ltp=afile->la.lt+n;
if(*f)
{
/* redefinition of label */
*l=ltp->len+i;
} else
if(ltp->fl==0)
{
/* label has not been defined yet, (e.g. pass1 forward ref), so we try to set it. */
*l=ltp->len+i;
if(b_ltest(ltp->blk,b))
er=E_LABDEF;
@ -213,11 +328,13 @@ int l_def(char *s, int *l, int *x, int *f)
} else
if(er==E_NODEF)
{
if(!(er=ll_def(s+i,&n,b))) /* ll_def(...,*f) */
if(!(er=ll_def(s+i,&n,b, cll_fl) )) /* store the label in the table of labels */
{
ltp=afile->la.lt+n;
*l=ltp->len+i;
ltp->fl=0;
ltp->is_cll=cll_fl;
}
}
@ -229,15 +346,31 @@ int l_def(char *s, int *l, int *x, int *f)
int l_search(char *s, int *l, int *x, int *v, int *afl)
{
int n,er,b;
label_t cll_fl;
*afl=0;
er=ll_search(s,&n);
/*printf("l_search: lab=%s(l=%d), afl=%d, er=%d, n=%d\n",s,*l, *afl,er,n);*/
/* check cheap local label */
cll_fl=STD;
if (s[0]=='@') {
cll_fl=CHEAP;
s++;
} else
if (s[0]==':') {
cll_fl = UNNAMED_DEF;
s++;
}
er = E_NODEF;
if (cll_fl != UNNAMED_DEF) {
er=ll_search(s,&n, cll_fl);
}
//printf("l_search: lab=%s(afl=%d, er=%d, cll_fl=%d, cll_cur=%d)\n",s,*afl,er, cll_fl, cll_getcur());
if(er==E_OK)
{
ltp=afile->la.lt+n;
*l=ltp->len;
*l=ltp->len + ((cll_fl == STD) ? 0 : 1);
if(ltp->fl == 1)
{
l_get(n,v,afl);/* *v=lt[n].val;*/
@ -251,12 +384,22 @@ int l_search(char *s, int *l, int *x, int *v, int *afl)
}
else
{
b_get(&b);
er=ll_def(s,x,b); /* ll_def(...,*v); */
if(cll_fl == CHEAP) {
b=cll_get();
} else
if(cll_fl == UNNAMED_DEF) {
b_get(&b); // b=unn_get();
} else {
b_get(&b);
}
er=ll_def(s,x,b, cll_fl); /* ll_def(...,*v); */
ltp=afile->la.lt+(*x);
*l=ltp->len;
ltp->is_cll = cll_fl;
*l=ltp->len + ((cll_fl == STD) ? 0 : 1);
//*l=ltp->len + cll_fl;
if(!er)
{
@ -303,11 +446,87 @@ void l_addocc(int n, int *v, int *afl) {
}
}
/* for the list functionality */
char *l_get_name(int n, label_t *is_cll) {
if (n > afile->la.ltm) {
fprintf(stderr, "Corrupted structures! n=%d, but max=%d\n", n, afile->la.ltm);
exit(1);
}
ltp=afile->la.lt+n;
*is_cll = ltp->is_cll;
return ltp->n;
}
// works on the static(!) ltp "label table pointer"
// also returns the actual index in the table of the current ltp
static int resolve_unnamed() {
// need to count up/down in the linkd label list for the block
char *namep = ltp->n;
int nextp = -1;
//printf("::: unnamed_def: %s, n=%d\n", namep, n);
while ((*namep == '+') || (*namep == '-')) {
char c = *namep;
nextp = -1;
if (c == '+') {
nextp = ltp->blknext;
} else
if (c == '-') {
nextp = ltp->blkprev;
}
//printf("::: nextp=%d\n", nextp);
if (nextp == -1) {
return -1; // E_NODEF
}
ltp = afile->la.lt+nextp;
//printf("::: leads to: %s, nextp=%d\n", ltp->n, nextp);
if (ltp->is_cll == UNNAMED) {
namep++;
}
}
return nextp;
}
/* for the listing, esp. html links; returns a pointer to a static buffer, available till next call */
char *l_get_unique_name(int n) {
static char buf[MAXLINE];
ltp=afile->la.lt+n;
if (ltp->is_cll == CHEAP || ltp->is_cll == STD) {
sprintf(buf, "%d%c%s", ltp->blk,
(ltp->is_cll == CHEAP) ? 'C' : '_',
ltp->n);
} else
if (ltp->is_cll == UNNAMED) {
// definition of unnamed label - name is NULL
// so use the actual index
sprintf(buf, "%dU%d", ltp->blk, n);
} else
if (ltp->is_cll == UNNAMED_DEF) {
// we actually need to find the correct label from the "+" and "-"
// in the name
int tmp = resolve_unnamed();
if (tmp >= 0) {
sprintf(buf, "%dU%d", ltp->blk, tmp);
} else {
sprintf(buf, "__%d", tmp);
}
} else {
buf[0] = 0; // no value
}
return buf;
}
int l_get(int n, int *v, int *afl)
{
if(crossref) l_addocc(n,v,afl);
ltp=afile->la.lt+n;
ltp = afile->la.lt+n;
if (ltp->is_cll == UNNAMED_DEF) {
int tmp = resolve_unnamed();
if (tmp == -1) return E_NODEF;
// now ltp is set to the actual label
}
(*v)=ltp->val;
lz=ltp->n;
*afl = ltp->afl;
@ -335,19 +554,23 @@ static void ll_exblk(int a, int b)
}
}
static int ll_def(char *s, int *n, int b) /* definiert naechstes Label nr->n */
/* defines next label, returns new label number in out param n */
static int ll_def(char *s, int *n, int b, label_t ltype)
{
int j=0,er=E_NOMEM,hash;
char *s2;
char *s2 = NULL;
/*printf("ll_def: s=%s\n",s); */
//printf("ll_def: s=%s, ltype=%d, no_name=%d\n",s, ltype, no_name);
// label table for the file ...
if(!afile->la.lt) {
// ... does not exist yet, so malloc it
afile->la.lti = 0;
afile->la.ltm = 1000;
afile->la.lt = malloc(afile->la.ltm * sizeof(Labtab));
}
if(afile->la.lti>=afile->la.ltm) {
// ... or is at its capacity limit, so realloc it
afile->la.ltm *= 1.5;
afile->la.lt = realloc(afile->la.lt, afile->la.ltm * sizeof(Labtab));
}
@ -355,54 +578,66 @@ static int ll_def(char *s, int *n, int b) /* definiert naechstes Label
fprintf(stderr, "Oops: no memory!\n");
exit(1);
}
#if 0
if((lti<ANZLAB) /*&&(lni<(long)(LABMEM-MAXLAB))*/)
{
#endif
ltp=afile->la.lt+afile->la.lti;
/*
s2=ltp->n=ln+lni;
while((j<MAXLAB-1) && (s[j]!='\0') && (isalnum(s[j]) || s[j]=='_'))
{
s2[j]=s[j];
j++;
}
*/
while((s[j]!='\0') && (isalnum(s[j]) || (s[j]=='_'))) j++;
s2 = malloc(j+1);
if(!s2) {
// current pointer in label table
ltp = afile->la.lt + afile->la.lti;
if (ltype != UNNAMED) {
// alloc space and copy over name
if (ltype == UNNAMED_DEF) {
// unnamed lables are like ":--" or ":+" with variable length
while((s[j]!='\0') && (s[j]=='+' || s[j]=='-')) j++;
} else {
// standard (and cheap) labels are normal text
while((s[j]!='\0') && (isalnum(s[j]) || (s[j]=='_'))) j++;
}
s2 = malloc(j+1);
if(!s2) {
fprintf(stderr,"Oops: no memory!\n");
exit(1);
}
strncpy(s2,s,j);
s2[j]=0;
}
strncpy(s2,s,j);
s2[j]=0;
/*
if(j<MAXLAB)
{
*/
// init new entry in label table
er=E_OK;
ltp->len=j;
ltp->n = s2;
ltp->blk=b;
ltp->len=j; // length of label
ltp->n = s2; // name of label (char*)
ltp->blk=b; // block number
ltp->fl=0;
ltp->afl=0;
ltp->occlist=NULL;
hash=hashcode(s,j);
ltp->nextindex=afile->la.hashindex[hash];
afile->la.hashindex[hash]=afile->la.lti;
*n=afile->la.lti;
afile->la.lti++;
/* lni+=j+1;*/
/* }
}
*/
/*printf("ll_def return: %d\n",er);*/
ltp->is_cll=ltype; // STD, CHEAP, or UNNAMED label
ltp->occlist=NULL;
hash=hashcode(s,j); // compute hashcode
ltp->nextindex=afile->la.hashindex[hash]; // and link in before last entry with same hashcode
afile->la.hashindex[hash]=afile->la.lti; // set as start of list for that hashcode
// TODO: does not work across files!
ltp->blknext = -1; // no next block
ltp->blkprev = b_link( afile->la.lti ); // previous block, linked within block
if (ltp->blkprev != -1) {
ltp = afile->la.lt + ltp->blkprev;
ltp->blknext = afile->la.lti;
}
*n=afile->la.lti; // return the list index for that file in the out parameter n
afile->la.lti++; // increase last index in lable table
return(er);
}
int ll_search(char *s, int *n) /* search Label in Tabelle ,nr->n */
/**
* search a label name in the label table. Return the label number
* in "n". Finds only labels that are in a block that is in the current
* set of blocks (in the block stack)
*
* If cll_fl is set, the label is also searched in the local cheap label scope
*
* Do not define the label (as is done in l_search()!)
*/
int ll_search(char *s, int *n, label_t cll_fl) /* search Label in Tabelle ,nr->n */
{
int i,j=0,k,er=E_NODEF,hash;
@ -411,7 +646,6 @@ int ll_search(char *s, int *n) /* search Label in Tabelle ,nr->n */
hash=hashcode(s,j);
i=afile->la.hashindex[hash];
/*printf("search?\n");*/
if(i>=afile->la.ltm) return E_NODEF;
do
@ -422,11 +656,24 @@ int ll_search(char *s, int *n) /* search Label in Tabelle ,nr->n */
{
for (k=0;(k<j)&&(ltp->n[k]==s[k]);k++);
if((j==k)&&(!b_test(ltp->blk)))
{
er=E_OK;
break;
}
if (cll_fl == CHEAP) {
if (ltp->blk == cll_getcur()) {
er=E_OK;
break;
}
} else
if (cll_fl == UNNAMED) {
// TODO
} else {
/* check if the found label is in any of the blocks in the
current block stack */
if((j==k)&&(!b_test(ltp->blk)))
{
/* ok, label found and it is reachable (its block nr is in the current block stack */
er=E_OK;
break;
}
}
}
if(!i)
@ -451,7 +698,7 @@ int ll_pdef(char *t)
{
int n;
if(ll_search(t,&n)==E_OK)
if(ll_search(t,&n, STD)==E_OK)
{
ltp=afile->la.lt+n;
if(ltp->fl)
@ -496,19 +743,39 @@ int l_write(FILE *fp)
return 0;
}
static int bt[MAXBLK];
static int blk;
static int bi;
/*******************************************************************************************
* block management code. Here the ".(" and ".)" blocks are maintained.
*
* Blocks are numbered uniquely, every time a new block is opened, the "blk" variable
* is increased and its number used as block number.
*
* The currently open blocks are maintained in a stack (bt[]). The lowest entry is the outermost
* block number, adding block numbers as blocks are opened. When a block is closed,
* the block stack is shortened again (bi has the length of the block stack)
*
* Methods exist to open new blocks, close a block, and do some checks, e.g. whether
* a specific block number is contained in the current block stack.
*/
static int bt[MAXBLK]; /* block stack */
static int labind; /* last allocated label, -1 none yet alloc'd - used for linking to find unnamed labels */
static int bi; /* length of the block stack (minus 1, i.e. bi[bi] has the innermost block) */
static int blk; /* current block number for allocation */
int b_init(void)
{
blk =0;
bi =0;
bt[bi]=blk;
labind=-1;
return(E_OK);
}
int b_new(void)
{
return ++blk;
}
int b_depth(void)
{
return bi;
@ -519,19 +786,26 @@ int ga_blk(void)
return(blk);
}
/**
* open a new block scope
*/
int b_open(void)
{
int er=E_BLKOVR;
if(bi<MAXBLK-1)
{
bt[++bi]=++blk;
bi++;
bt[bi]=b_new();
er=E_OK;
}
return(er);
}
/**
* close a block scope
*/
int b_close(void)
{
@ -542,10 +816,14 @@ int b_close(void)
} else {
return E_BLOCK;
}
cll_clear();
//unn_clear();
return(E_OK);
}
/**
* get the block number of the current innermost block
*/
static int b_get(int *n)
{
*n=bt[bi];
@ -553,6 +831,9 @@ static int b_get(int *n)
return(E_OK);
}
/**
* returns the block number of the block "i" levels up in the current block stack
*/
static int b_fget(int *n, int i)
{
if((bi-i)>=0)
@ -562,6 +843,10 @@ static int b_fget(int *n, int i)
return(E_OK);
}
/**
* tests whether the given block number n is in the current stack of
* current block numbers bt[]
*/
static int b_test(int n)
{
int i=bi;
@ -572,6 +857,9 @@ static int b_test(int n)
return( i+1 ? E_OK : E_NOBLK );
}
/**
* tests whether the given block number "a" is in the
*/
static int b_ltest(int a, int b) /* testet ob bt^-1(b) in intervall [0,bt^-1(a)] */
{
int i=0,er=E_OK;
@ -593,3 +881,10 @@ static int b_ltest(int a, int b) /* testet ob bt^-1(b) in intervall [0,bt^-1(
return(er);
}
int b_link(int newlab) {
int tmp = labind;
//printf("b_link: old was %d, set to %d\n", tmp, newlab);
labind = newlab;
return tmp;
}

View File

@ -21,8 +21,13 @@
#include <stdio.h> /* for FILE */
/* nasty stuff - "lz" is exported from xal.c so xa.c can print the name
* of the label that was last searched for in the error message that the
* label was not found...
*/
extern char *lz;
int l_init(void);
int ga_lab(void);
int gm_lab(void);
@ -30,6 +35,8 @@ long gm_labm(void);
long ga_labm(void);
int lg_set(char *);
int lg_import(int);
int lg_importzp(int);
int b_init(void);
int b_depth(void);
@ -40,9 +47,11 @@ int ga_blk(void);
int l_def(char *s, int* l, int *x, int *f);
int l_search(char *s, int *l, int *x, int *v, int *afl);
void l_set(int n, int v, int afl);
char* l_get_name(int n, label_t *is_cll);
char* l_get_unique_name(int n);
int l_get(int n, int *v, int *afl);
int l_vget(int n, int *v, char **s);
int ll_search(char *s, int *n);
int ll_search(char *s, int *n, label_t labeltype);
int ll_pdef(char *t);
int b_open(void);

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

@ -0,0 +1,730 @@
/* xa65 - 65xx/65816 cross-assembler and utility suite
*
* Copyright (C) 1989-1997 André Fachat (a.fachat@physik.tu-chemnitz.de)
* maintained by Cameron Kaiser
*
* Assembler listing
*
* 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);
/*********************************************************************************************/
// formatter
typedef struct {
void (*start_listing)(char *name);
void (*start_line)();
int (*set_anchor)(char *buf, char *name); // returns number of bytes added to buf
int (*start_label)(char *buf, char *name); // returns number of bytes added to buf
int (*end_label)(char *buf);
void (*end_line)();
void (*end_listing)();
char* (*escape)(char *toescape); // returns pointer to static buffer, valid until next call
char* (*escape_char)(char toescape); // returns pointer to static buffer, valid until next call
} formatter_t;
static char *def_escape(char *toescape) {
return toescape;
}
static char *def_escape_char(char toescape) {
static char buf[2];
buf[0] = toescape;
buf[1] = 0;
return buf;
}
static formatter_t def_format = {
NULL, NULL, NULL, NULL,
NULL, NULL, NULL,
def_escape, def_escape_char
};
static void html_start_listing(char *name) {
// really short version for now
fprintf(listfp, "<html><head><title>%s</title></head><body><pre>\n",
(name == NULL) ? "(null)" : name);
}
static int html_set_anchor(char *buf, char *name) {
sprintf(buf, "<a name=\"%s\"> </a>", name);
return strlen(buf);
}
static int html_start_label(char *buf, char *name) {
sprintf(buf, "<a href=\"#%s\">", name);
return strlen(buf);
}
static int html_end_label(char *buf) {
sprintf(buf, "</a>");
return strlen(buf);
}
static void html_end_listing() {
fprintf(listfp, "</pre></body></html>\n");
}
static char *html_escape(char *toescape) {
static char buf[MAXLINE];
char *p = toescape;
char *q = buf;
while (*p != 0) {
if (*p == '<') {
strcpy(q, "&lt;");
q+=4;
p++;
} else
if (*p == '&') {
strcpy(q, "&amp;");
q+=5;
p++;
} else {
*q = *p;
q++;
p++;
}
}
*q = 0; // string terminator
return buf;
}
static char *html_escape_char(char toescape) {
static char buf[2];
buf[0] = toescape;
buf[1] = 0;
return html_escape(buf);
}
static formatter_t html_format = {
html_start_listing,
NULL,
html_set_anchor,
html_start_label,
html_end_label,
NULL,
html_end_listing,
html_escape, html_escape_char
};
static formatter_t *formatp = &def_format;
/*********************************************************************************************/
void list_flush() {
if (listfp != NULL) {
fflush(listfp);
}
}
void list_start(const char *formatname) {
formatp = &def_format;
if (formatname != NULL && strcmp("html", formatname) == 0) {
formatp = &html_format;
}
if (listfp != NULL) {
if (formatp->start_listing != NULL) formatp->start_listing(list_filenamep);
}
}
void list_end() {
if (listfp != NULL) {
if (formatp->end_listing != NULL) formatp->end_listing();
}
}
// 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;
// could be extended to include the preamble...
if (formatp->start_line != NULL) formatp->start_line();
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);
if (formatp->end_line != NULL) formatp->end_line();
if (formatp->start_line != NULL) formatp->start_line();
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);
if (formatp->end_line != NULL) formatp->end_line();
if (formatp->start_line != NULL) formatp->start_line();
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 */
{
char valbuf[32];
i = buf - outline;
if (i<80) buf += list_nchar(buf, ' ', 80-i);
buf += list_string(buf, " >>");
sprintf(valbuf, "%p", listing+3);
buf += list_string(buf, valbuf);
buf += list_sp(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);
if (formatp->end_line != NULL) formatp->end_line();
}
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);
// duplicate anchor names?
if (formatp->set_anchor != NULL) {
outp += formatp->set_anchor(buf+outp, l_get_unique_name(tmp));
}
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_string(buf+outp, formatp->escape_char(input[inp+1]));
inp+=2;
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);
// duplicate label name
if (formatp->start_label != NULL) {
outp += formatp->start_label(buf+outp, l_get_unique_name(tmp));
}
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 == NULL ? "<null>" : name);
}
if (formatp->end_label != NULL) outp += formatp->end_label(buf+outp);
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 (input[inp+3] == '=') {
// label definition
if (formatp->set_anchor != NULL) {
outp += formatp->set_anchor(buf+outp, l_get_unique_name(tmp));
}
}
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 (formatp->start_label != NULL) {
outp += formatp->start_label(buf+outp, l_get_unique_name(tmp));
}
if (is_cll) outp += list_char(buf+outp, '@');
outp += list_string(buf+outp, name);
if (formatp->end_label != NULL) outp += formatp->end_label(buf+outp);
/*
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_string(buf+outp, formatp->escape_char(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, formatp->escape(arith_ops[op]));
inp += 1;
}
operator = 0;
}
}
end:
return outp;
}
int list_string(char *buf, char *string) {
if (buf == NULL || string == NULL) {
fprintf(stderr, "NULL pointer: buf=%p, string=%p\n", buf, string);
fflush(stderr);
//exit(1);
return 0;
}
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;
}

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

@ -0,0 +1,34 @@
/* 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 list_start(char *formatname); //either NULL or "html"
void list_end();
void list_flush(); // debug helper
void list_setfile(FILE *fp);
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 */
// list a single line/token set
void do_listing(signed char *listing, int listing_len, signed char *bincode, int bincode_len);
#endif /* __XA65_XALISTING_H__ */

View File

@ -53,10 +53,13 @@ FILE *xfopen(const char *fn,const char *mode)
return NULL;
}
// copy to xname by replacing windows backslashes with the proper DIRCHAR
for(i=0;i<l+1;i++) {
xname[i]=((fn[i]=='\\')?DIRCHAR:fn[i]);
}
//printf("name=%s, xname=%s, mode=%s\n",fn,xname, mode);
if(mode[0]=='r')
{
if((file=fopen(fn,mode))==NULL
@ -68,7 +71,6 @@ FILE *xfopen(const char *fn,const char *mode)
strcpy(n2,n);
strcat(n2,xname);
strcat(n,fn);
/* printf("name=%s,n2=%s,mode=%s\n",n,n2,mode); */
file=fopen(n,mode);
if(!file) file=fopen(n2,mode);
}
@ -87,7 +89,6 @@ FILE *xfopen(const char *fn,const char *mode)
strcpy(n2,n);
strcat(n2,xname);
strcat(n,fn);
/* printf("name=%s,n2=%s,mode=%s\n",n,n2,mode); */
file=fopen(n,mode);
if(!file) file=fopen(n2,mode);
}

View File

@ -66,7 +66,7 @@ void o_write(FILE *fp) {
l=afile->fo.olist[i].len;
t=afile->fo.olist[i].text;
/* do not optimize */
t_p2(t, &l, 1, &afl);
t_p2_l(t, &l, &afl);
if(l>254) {
errout(E_OPTLEN);

View File

@ -40,7 +40,8 @@
#include "xap.h"
/* define this for recursive evaluation output */
/* #define DEBUG_RECMAC */
#undef DEBUG_RECMAC
#undef DEBUG_REPLACE
char s[MAXLINE];
Datei *filep;
@ -50,7 +51,8 @@ static int pp_replace(char*,char*,int,int);
static int searchdef(char*);
static int fgetline(char*,int len, int *rlen, FILE*);
static int icl_open(char*),pp_ifdef(char*),pp_ifndef(char*);
/*static int icl_open(char*);*/
static int pp_ifdef(char*),pp_ifndef(char*);
static int pp_else(char*),pp_endif(char*);
static int pp_echo(char*),pp_if(char*),pp_print(char*),pp_prdef(char*);
static int pp_ifldef(char*),pp_iflused(char*);
@ -130,7 +132,7 @@ int pp_ifldef(char *t)
int pp_iflused(char *t)
{
int n;
loopfl=(loopfl<<1)+( ll_search(t,&n) ? 1 : 0 );
loopfl=(loopfl<<1)+( ll_search(t,&n,STD) ? 1 : 0 );
return(0);
}
@ -353,7 +355,10 @@ int pp_define(char *k)
{
i++;
liste[rl].p_anz++;
for(j=0; t[i+j]!=')' && t[i+j]!=',' && t[i+j]!='\0';j++);
// skip whitespace before parameter name
while(isspace(t[i])) i++;
// find length
for(j=0; (!isspace(t[i+j])) && t[i+j]!=')' && t[i+j]!=',' && t[i+j]!='\0';j++);
if(j<memfre)
{
strncpy(mem,t+i,j);
@ -362,6 +367,8 @@ int pp_define(char *k)
memfre-=j+1;
}
i+=j;
// skip trailing whitespace after parameter name
while(isspace(t[i])) i++;
}
if(t[i]==')')
i++;
@ -370,7 +377,7 @@ int pp_define(char *k)
i++;
t+=i;
pp_replace(h,t,-1,0);
pp_replace(h,t,-1,rlist);
t=h;
@ -433,78 +440,92 @@ int tcompare(char s[],char *v[], int n)
return((i==n)? -1 : i);
}
int pp_replace(char *to, char *ti, int a,int b)
static int check_name(char *t, int n) {
int i=0;
{
char *x=liste[n].search;
while(t[i]==*x++ && t[i] && (isalnum(t[i]) || t[i]=='_'))
i++;
}
#ifdef DEBUG_RECMAC
printf("check name with n=%d, name='%s' ->i=%d, len=%d\n", n, liste[n].search,i, liste[n].s_len);
#endif
return i == liste[n].s_len;
}
/**
* this is a break out of the original pp_replace code, as this code
* was basically duplicated for initial and recursive calls.
*/
static int pp_replace_part(char *to, char *t, int n, int sl, int recursive, int *l, int blist)
{
char *t=to,c,*x,*y,*mx,*rs;
int i,l,n,sl,d,ld,er=E_OK,hkfl,klfl;
char fti[MAXLINE],fto[MAXLINE];
/*
int flag=!strncmp(ti,"TOUT",4);
if(flag) printf("flag=%d\n",flag);
*/
(void)strcpy(t,ti);
int er = E_OK;
if(rlist)
{
while(t[0]!='\0')
{
while(!isalpha(t[0]) && t[0]!='_')
if(t[0]=='\0')
break; /*return(E_OK);*/
else
{
t++;
ti++;
}
for(l=0;isalnum(t[l])||t[l]=='_';l++);
ld=l;
/*
if(flag) printf("l=%d,a=%d,t=%s\n",l,a,t);
*/
if(a<0)
{
n=hashindex[hashcode(t,l)];
do
{
sl=liste[n].s_len;
if(sl && (sl==l))
{
i=0;
x=liste[n].search;
while(t[i]==*x++ && t[i])
i++;
// save mem, to restore it when we don't need the pseudo replacements anymore
// Note: in a real version, that should probably be a parameter, and not fiddling
// with global variables...
char *saved_mem = mem;
if(i==sl)
{
rs=liste[n].replace;
#ifdef DEBUG_RECMAC
printf("replace part: n=%d, sl=%d, rec=%d, %s\n", n, sl, recursive, t);
#endif
// yes, mark replacement string
char *rs=liste[n].replace;
// does it have parameters?
if(liste[n].p_anz)
{
// yes, we have parameters, so we need to pp_replace them
// as well.
char fti[MAXLINE],fto[MAXLINE];
// copy replacement into temp buffer
(void)strcpy(fti,liste[n].replace);
if(rlist+liste[n].p_anz>=ANZDEF || memfre<MAXLINE*2)
// boundary checks ...
if(blist+liste[n].p_anz>=ANZDEF || memfre<MAXLINE*2)
er=E_NOMEM;
else
{
y=t+sl;
x=liste[n].search+sl+1;
if(*y!='(')
// ... passed
// y points to the char behind the input name (i.e. the '(')
char *y=t+sl;
// x points into the pp definition, with the parameter definition names
// following the definition name, separated by \0. Starts here behind the
// name - i.e. now points to the name of the first parameter
char *x=liste[n].search+sl+1;
// does the input actually have a '(' as parameter marker?
if(*y!='(') {
// no. Should probably get an own error (E_PARAMETER_EXPECTED)
er=E_SYNTAX;
}
else
{
mx=mem-1;
for(i=0;i<liste[n].p_anz;i++)
// mx now points to next free memory (mem current pointer in text table)
char *mx=mem-1;
// walk through the pp parameters
// by creating "fake" preprocessor definitions at the end
// of the current definition list, i.e. in liste[] after index
// rlist.
for(int i=0;i<liste[n].p_anz;i++)
{
liste[rlist+i].search=x;
liste[rlist+i].s_len=(int)strlen(x);
// create new replacement entry
liste[blist+i].search=x;
liste[blist+i].s_len=(int)strlen(x);
liste[blist+i].p_anz=0;
liste[blist+i].replace=mx+1;
// move x over to the next parameter name
x+=strlen(x)+1;
liste[rlist+i].p_anz=0;
liste[rlist+i].replace=mx+1;
c=*(++mx)=*(++y);
hkfl=klfl=0;
// points to first char of the parameter name in the input
// copy over first char into text memory (note that the position
// is already stored in liste[].replace above)
char c=*(++mx)=*(++y);
int hkfl=0; // quote flag
int klfl=0; // brackets counter
// copy over the other characters
while(c!='\0'
&& ((hkfl!=0
|| klfl!=0)
@ -523,65 +544,129 @@ int pp_replace(char *to, char *ti, int a,int b)
klfl--;
}
c=*(++mx)=*(++y);
}
}
// zero-terminate stored string
*mx='\0';
// if i is for the last parameter, then check if the
// last copied char was ')', otherwise it should be ','
// as separator for the next parameter
if(c!=((i==liste[n].p_anz-1) ? ')' : ','))
{
er=E_ANZPAR;
// note: this break only exits the innermost loop!
break;
}
}
}
// at this point we have "augmented" the pp definitions
// with a list of new definitions for the macro parameters
// so that when pp_replace'ing them recursively the macro parameters
// will automatically be replaced.
// if we ran into an error, report so
if (er != E_OK) {
return (er);
}
// let mx point to first free (and not last non-free) byte
mx++;
// before we use the parameter replacements, we need to
// recursively evaluate and replace them as well.
#ifdef DEBUG_RECMAC
printf("replace:\n");
printf("replace (er=%d):\n", er);
printf("%s=%s\n",liste[n].search,liste[n].replace);
#endif
for(i=0;i<liste[n].p_anz;i++) {
// loop over all arguments
for(int i=0;i<liste[n].p_anz;i++) {
/* recursively evaluate arguments */
char nfto[MAXLINE];
char nfwas[MAXLINE];
int j = 0;
int k;
//int j = 0;
//int k = 0;
(void)strcpy(nfwas, liste[rlist+i].replace);
if (!er)
er=pp_replace(nfto,nfwas,-1,rlist);
// copy over the replacement string into a buffer nfwas
(void)strcpy(nfwas, liste[blist+i].replace);
if (!er) {
// replace the tokens in the parameter, adding possible pseudo params
// on top of the liste[] into nfto
er=pp_replace(nfto,nfwas,-1,blist+liste[n].p_anz);
}
#ifdef DEBUG_RECMAC
printf("-%s=%s\n",liste[rlist+i].search,liste[rlist+i].replace);
printf("SUBB: -%s=%s\n", nfwas, nfto);
#endif
#if 0
// as long as the strings don't match, loop...
while ((k = strcmp(nfto, nfwas))) {
// copy original from nfwas back to nfto
(void)strcpy(nfto, nfwas);
if (!er)
if (!er) {
// save-guard our replacement strings in global memory for the
// recursive pp_replace call. Note: is cleaned up after return,
// so need to restore mem only at the end of this function.
mem = mx;
// replace tokens
er=pp_replace(nfto,nfwas,-1,rlist);
}
// and copy result into input buffer
(void)strcpy(nfwas, nfto);
#ifdef DEBUG_RECMAC
printf("SUBB2 (%i): -%s=%s\n", k, liste[rlist+i].replace, nfto);
#endif
if (++j>10)
if (++j>10) {
// we ran into 10 recursions deep - that does not look sound, bail out
errout(E_ORECMAC);
}
}
(void)strcpy(liste[rlist+i].replace, nfto);
#endif
// copy over the replacement string into free memory (using mx as pointer)
(void)strcpy(mx, nfto);
// replace the pointer to the (now obsolete) old replacement with the one we just created
// Note that due to the nature of the (more or less static) memory allocation, this is not
// being freed. Oh well...
liste[blist+i].replace = mx;
mx += strlen(mx)+1;
#ifdef DEBUG_RECMAC
printf("FINAL: -%s=%s\n",liste[rlist+i].search,liste[rlist+i].replace);
#endif
}
if(!er)
er=pp_replace(fto,fti,rlist,rlist+i);
if(!er) {
// safe-guard our memory allocations
mem = mx;
// only change (of two) from recursive: rlist is 0 there
#ifdef DEBUG_RECMAC
printf("replace macro: recursive=%d, blist=%d, -> b=%d\n", recursive, blist, blist+liste[n].p_anz);
printf(" from: %s\n", fti);
#endif
er=pp_replace(fto,fti,recursive ? 0 : blist,blist+liste[n].p_anz);
#ifdef DEBUG_RECMAC
printf(" to: %s\n", fto);
#endif
}
/* if(flag) printf("sl=%d,",sl);*/
sl=(int)((long)y+1L-(long)t);
/* if(flag) printf("sl=%d\n",sl);*/
rs=fto;
/* printf("->%s\n",fto);*/
#ifdef DEBUG_RECMAC
printf("->%s\n",fto);
#endif
}
}
if(er)
if(er) {
mem = saved_mem;
return(er);
}
}
} // end if(liste[n].p_anz), i.e. if it has parameters
d=(int)strlen(rs)-sl;
int d=(int)strlen(rs)-sl;
if(strlen(to)+d>=MAXLINE)
if(strlen(to)+d>=MAXLINE) {
mem = saved_mem;
return(E_NOMEM);
}
/*
if(d<0)
@ -596,129 +681,153 @@ int pp_replace(char *to, char *ti, int a,int b)
t[ll+d]=t[ll];
}
*/
if(d)
(void)strcpy(t+sl+d,ti+sl);
if(d) {
// d can be positive or negative, so strcpy cannot be used, use memmove instead
(void)memmove(t+sl+d,t+sl, strlen(t) - sl + 1);
}
i=0;
while((c=rs[i]))
int i=0;
char c;
while((c=rs[i])) {
t[i++]=c;
l=sl+d;/*=0;*/
break;
}
}
// other change from recursive. there sl is missing from add
//*l=(recursive ? 0 : sl) + d;/*=0;*/
*l=sl + d;/*=0;*/
mem = saved_mem;
return (er);
}
/**
* copy the input string pointed to by ti into
* an output string buffer pointed to by to, replacing all
* preprocessor definitions in the process.
*
* Note: this method is called recursively, with "a" being -1
* when called from the "outside" respectively in a new context
* (like macro parameters)
*
* The "b" parameter denotes the index in the list from which on
* pseudo replacement entries are being created for replacement
* parameters
*
*/
int pp_replace(char *to, char *ti, int a,int b)
{
char *t=to;
int l,n,sl,er=E_OK;
int ld; // length of name/token to analyse
/*
int flag=!strncmp(ti,"TOUT",4);
if(flag) printf("flag=%d\n",flag);
*/
// t points to to, so copy input to output 1:1
// then below work on the copy in-place
(void)strcpy(t,ti);
// if there are replacements in the list of replacements
if(rlist)
{
// loop over the whole input
while(t[0]!='\0' && t[0] != ';')
{
// skip over the whitespace
// comment handling is NASTY NASTY NASTY
// but I currently don't see another way, as comments and colons
// can (and do) appear in preprocessor replacements
char quotefl = 0;
char commentfl = 0;
while((t[0] != 0) && (commentfl || ((!isalpha(t[0]) && t[0]!='_')))) {
if (t[0]=='\0') {
break; /*return(E_OK);*/
} else
{
if (t[0] == ';' && !quotefl) {
commentfl = 1;
}
if (t[0] == ':' && !quotefl && !ca65 && !masm) {
// note that both ca65 and masm allow colons in comments
// so in these cases we cannot reset the comment handling here
commentfl = 0;
}
if (quotefl) {
// ignore other quotes within a quote
if (t[0] == quotefl) {
quotefl = 0;
}
} else
if (t[0] == '"' || t[0] == '\'') {
quotefl = t[0];
}
t++;
ti++;
}
}
// determine the length of the name
for(l=0;isalnum(t[l])||t[l]=='_';l++);
// store in ld
ld=l;
#ifdef DEBUG_RECMAC
printf("l=%d,a=%d,b=%d, t=%s\n",l,a, b ,t);
#endif
// the following if() is executed when being called from an
// 'external' context, i.e. not from a recursion
if(a<0)
{
// when called from an external context, not by recursion
// compute hashcode for the name for the search index entry (liste[n])
n=hashindex[hashcode(t,l)];
// loop over all entries in linked list for hash code (think: hash collisions)
do // while(1);
{
// length of name of pp definition
sl=liste[n].s_len;
// does pp definition match what we have found?
if(sl && (sl==l) && check_name(t, n))
{
er = pp_replace_part(to, t, n, sl, 0, &l, b);
if (er != E_OK) {
return er;
}
break;
}
if(!n)
break;
// next index in linked list for given hash code
n=liste[n].nextindex;
} while(1);
} else
{
// called when in recursive call
// loop over all the replacement entries from the given b down to 0
// that allows to replace the parameters first (as they were added at
// the end of the list)
for(n=b-1;n>=a;n--)
{
sl=liste[n].s_len;
if(sl && (sl==l))
if(sl && (sl==l) && check_name(t, n))
{
i=0;
x=liste[n].search;
while(t[i]==*x++ && t[i])
i++;
if(i==sl)
{
rs=liste[n].replace;
if(liste[n].p_anz)
{
(void)strcpy(fti,liste[n].replace);
if(rlist+liste[n].p_anz>=ANZDEF || memfre<MAXLINE*2)
er=E_NOMEM;
else
{
y=t+sl;
x=liste[n].search+sl+1;
if(*y!='(')
er=E_SYNTAX;
else
{
mx=mem-1;
for(i=0;i<liste[n].p_anz;i++)
{
liste[rlist+i].search=x;
liste[rlist+i].s_len=strlen(x);
x+=strlen(x)+1;
liste[rlist+i].p_anz=0;
liste[rlist+i].replace=mx+1;
c=*(++mx)=*(++y);
hkfl=klfl=0;
while(c!='\0'
&& ((hkfl!=0
|| klfl!=0)
|| (c!=','
&& c!=')')
)
)
{
if(c=='\"')
hkfl=hkfl^1;
if(!hkfl)
{
if(c=='(')
klfl++;
if(c==')')
klfl--;
}
c=*(++mx)=*(++y);
}
*mx='\0';
if(c!=((i==liste[n].p_anz-1) ? ')' : ','))
{
er=E_ANZPAR;
break;
}
}
if(!er)
er=pp_replace(fto,fti,0,rlist+i);
sl=(int)((long)y+1L-(long)t);
rs=fto;
}
}
if(er)
return(er);
}
d=(int)strlen(rs)-sl;
if(strlen(to)+d>=MAXLINE)
return(E_NOMEM);
/*
if(d<0)
{
y=t+sl+d;
x=t+sl;
while(*y++=*x++);
}
if(d>0)
{
for(ll=strlen(t);ll>=sl;ll--)
t[ll+d]=t[ll];
}
*/
if(d)
(void)strcpy(t+sl+d,ti+sl);
i=0;
while((c=rs[i]))
t[i++]=c;
l+=d;/*0;*/
break;
}
er = pp_replace_part(to, t, n, sl, 1, &l, b);
break;
}
}
}
// advance input by length of name
ti+=ld;
// advance output by l
t+=l;
}
}
} /* end while(t[0] != 0) */
} /* end if(rlist) */
return(E_OK);
}
@ -752,14 +861,16 @@ int pp_open(char *name)
fp=xfopen(name,"r");
int l = strlen(name);
/* we have to alloc it dynamically to make the name survive another
pp_open - it's used in the cross-reference list */
flist[0].fname = malloc(strlen(name)+1);
flist[0].fname = malloc(l+1);
if(!flist[0].fname) {
fprintf(stderr,"Oops, no more memory!\n");
exit(1);
}
(void)strcpy(flist[0].fname,name);
(void)strncpy(flist[0].fname,name,l+1);
flist[0].fline=0;
flist[0].bdepth=b_depth();
flist[0].filep=fp;
@ -826,14 +937,17 @@ int icl_open(char *tt)
fsp++;
char *namep = s+i;
int len = strlen(namep);
/* we have to alloc it dynamically to make the name survive another
pp_open - it's used in the cross-reference list */
flist[fsp].fname = malloc(strlen(s+i)+1);
flist[fsp].fname = malloc(len+1);
if(!flist[fsp].fname) {
fprintf(stderr,"Oops, no more memory!\n");
exit(1);
}
strcpy(flist[fsp].fname,s+i);
strncpy(flist[fsp].fname,namep, len+1);
flist[fsp].fline=0;
flist[fsp].bdepth=b_depth();
flist[fsp].flinep=NULL;
@ -843,6 +957,51 @@ int icl_open(char *tt)
return(0);
}
/*
* parses the current line for double-slash comments,
* handling single- and double-quotes appropriately
* shortens the line if a comment is found, returns
* the new line length.
*/
int double_slash_comments(char *line) {
int p = 0;
int qfl = 0; // if set, contains the current quote char (others are then ignored)
char c;
while (line[p] != 0) {
c = line[p];
if (c == qfl) {
// always in quote, c==0 not possible due to loop condition
// found matching quote char, so end of quote
qfl = 0;
} else
if ((c == '\'' || c == '"') && !qfl) {
// not in quote, but finding quote char
qfl = c;
}
if (c == '^' && qfl) {
// xa65 escape character in strings (quoted)
if (line[p+1] != 0) {
// skip the next char in test
p++;
}
}
if (c == '/' && !qfl) {
// found '/' outside quote
if (line[p+1] == '/') {
// gotcha
//printf("shorten at %d: %s\n", p, line);
// shorten line
line[p] = 0;
// return new length
return p;
}
}
p++;
}
return p;
}
int pgetline(char *t)
{
int c,er=E_OK;
@ -854,15 +1013,25 @@ int pgetline(char *t)
filep =flist+fsp;
do {
c=fgetline(in_line, MAXLINE, &rlen, flist[fsp].filep);
/* continuation lines */
tlen = rlen;
while(c=='\n' && tlen && in_line[tlen-1]=='\\') {
c=fgetline(in_line + tlen-1, MAXLINE-tlen, &rlen, flist[fsp].filep);
tlen += rlen-1;
int is_continuation = 0;
tlen = 0; // start of current line in in_line[]
do {
c=fgetline(in_line + tlen, MAXLINE, &rlen, flist[fsp].filep);
/* check for continuation lines */
is_continuation = ((c == '\n') && (rlen > 0) && (in_line[tlen + rlen - 1]=='\\'));
if (is_continuation) {
// cut off the continuation character
rlen--;
in_line[tlen + rlen] = 0;
}
if(in_line[0]=='#' || in_line[0] == altppchar)
{
rlen = double_slash_comments(in_line + tlen);
tlen += rlen;
} while (is_continuation);
if(in_line[0]=='#' || in_line[0] == altppchar)
{
if (in_line[1]==' ') { /* cpp comment -- pp_comand doesn't
handle this right */
er=pp_cpp(in_line+1);
@ -876,10 +1045,10 @@ int pgetline(char *t)
}
}
}
} else
} else
er=1;
if(c==EOF) {
if(c==EOF) {
if (loopfl && fsp) {
char bletch[MAXLINE];
sprintf(bletch,
@ -896,22 +1065,21 @@ int pgetline(char *t)
errout(E_OPENPP);
}
/* handle the double-slash comment (like in C++) */
p = strchr(in_line, '/');
if (p != NULL) {
if (p[1] == '/') {
*p = 0; /* terminate string */
}
}
if(!er || loopfl) {
in_line[0]='\0';
}
er= (er==1) ? E_OK : er ;
if(!er)
if(!er) {
#ifdef DEBUG_REPLACE
// printf("<<<: %s\n", in_line);
#endif
er=pp_replace(t,in_line,-1,rlist);
#ifdef DEBUG_REPLACE
printf(">>>: %s\n", t);
#endif
}
if(!er && nff)
er=E_NEWFILE;
@ -929,7 +1097,7 @@ int pgetline(char *t)
/*************************************************************************/
/* this is the most disgusting code I have ever written, but Andre drove me
to it because I can't think of any other F$%Y#*U(%&Y##^#KING way to fix the
to it because I can't think of any other way to fix the
last line bug ... a very irritated Cameron */
/* however, it also solved the problem of open #ifdefs not bugging out */
@ -996,6 +1164,11 @@ int rgetc(FILE *fp)
return(c-'\t'?c:' ');
}
/**
* Note that the line returned is always zero-terminated,
* the rlen out parameter is just convenience, so that
* a further strlen() can be saved
*/
int fgetline(char *t, int len, int *rlen, FILE *fp)
{
static int c,i;

View File

@ -30,6 +30,9 @@ void pp_end(void);
int pgetline(char *t);
Datei *pp_getidat(void);
/* needed for .include pseudo opcode */
int icl_open(char*);
int ga_pp(void);
int gm_pp(void);
long gm_ppm(void);

View File

@ -34,18 +34,22 @@ File *afile = NULL;
int rmode = RMODE_RELOC;
/*
int r_set(int pc, int afl, int l) {
/*printf("set relocation @$%04x, l=%d, afl=%04x, segment=%d\n",pc, l, afl,segment);*/
if(segment==SEG_TEXT) return rt_set(pc,afl,l,0);
if(segment==SEG_DATA) return rd_set(pc,afl,l,0);
return 0;
}
*/
int u_set(int pc, int afl, int label, int l) {
/*printf("set relocation @$%04x, l=%d, afl=%04x, segment=%d, label=%d\n",
pc, l, afl,segment, label);*/
if((afl & A_FMASK) == (SEG_UNDEF<<8))
if(((afl & A_FMASK) == (SEG_UNDEF<<8))
|| ((afl & A_FMASK) == (SEG_UNDEFZP<<8))
) {
label = u_label(label); /* set label as undefined */
}
if(segment==SEG_TEXT) return rt_set(pc,afl,l,label);
if(segment==SEG_DATA) return rd_set(pc,afl,l,label);
return 0;
@ -77,7 +81,9 @@ int rt_set(int pc, int afl, int l, int lab) {
/*printf("Warning: byte relocation in word value at PC=$%04x!\n",pc);*/
}
if(l==1 && ((afl&A_MASK)==A_ADR)) {
if((afl & A_FMASK) != (SEG_ZERO<<8)) {
if(((afl & A_FMASK) != (SEG_ZERO<<8))
&& ((afl & A_FMASK) != (SEG_UNDEFZP<<8))
) {
/*printf("afl=%04x\n",afl);*/
errout(W_ADRRELOC);
}
@ -147,10 +153,16 @@ int rt_write(FILE *fp, int pc) {
}
fputc(pc2-pc, fp);
pc=pc2;
fputc((afl>>8)&255, fp);
if((afile->rt.rlist[p].afl&A_FMASK)==(SEG_UNDEF<<8)) {
if((afile->rt.rlist[p].afl&A_FMASK)==(SEG_UNDEFZP<<8)) {
fputc( (((afl & ~A_FMASK)>>8)&255)|SEG_UNDEF, fp);
fputc(afile->rt.rlist[p].lab & 255, fp);
fputc((afile->rt.rlist[p].lab>>8) & 255, fp);
} else {
fputc( (afl>>8)&255, fp);
if((afile->rt.rlist[p].afl&A_FMASK)==(SEG_UNDEF<<8)) {
fputc(afile->rt.rlist[p].lab & 255, fp);
fputc((afile->rt.rlist[p].lab>>8) & 255, fp);
}
}
if((afl&A_MASK)==A_HIGH) fputc(afl&255,fp);
}

View File

@ -25,7 +25,7 @@
extern File *alloc_file(void);
/* jumps to r[td]_set, depending on segment */
int r_set(int pc, int reloc, int len);
/*int r_set(int pc, int reloc, int len);*/
int u_set(int pc, int reloc, int label, int len);
int rt_set(int pc, int reloc, int len, int label);

View File

@ -111,11 +111,17 @@ int rd_write(FILE *fp, int pc) {
}
fputc(pc2-pc, fp);
pc=pc2;
fputc((afl>>8)&255, fp);
if((afile->rd.rlist[p].afl&A_FMASK)==(SEG_UNDEF<<8)) {
if((afile->rd.rlist[p].afl&A_FMASK)==(SEG_UNDEFZP<<8)) {
fputc((((afl & ~A_FMASK)>>8)&255)|SEG_UNDEF, fp);
fputc(afile->rd.rlist[p].lab & 255, fp);
fputc((afile->rd.rlist[p].lab>>8) & 255, fp);
} else {
fputc((afl>>8)&255, fp);
if(((afile->rd.rlist[p].afl&A_FMASK)==(SEG_UNDEF<<8))) {
fputc(afile->rd.rlist[p].lab & 255, fp);
fputc((afile->rd.rlist[p].lab>>8) & 255, fp);
}
}
}
if((afl&A_MASK)==A_HIGH) fputc(afl&255,fp);
}
p=afile->rd.rlist[p].next;

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,11 @@
extern int dsb_len;
int t_p1(signed char *s, signed char *t, int *ll, int *al);
int t_p2(signed char *t, int *ll, int fl, int *al);
int t_p2_l(signed char *t, int *ll, int *al);
int b_term(char *s, int *v, int *l, int pc);
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__ */

7
xa/tests/Makefile Normal file
View File

@ -0,0 +1,7 @@
TESTS=adrm binclude chardelimiter charset comcom fordef incerr
tests:
for i in $(TESTS); do (cd $$i; make tests); done

View File

@ -27,6 +27,8 @@ incerr/ 1) .xl/.al should error without -w 2) error should be in
binclude/ Binary include code with some weird casing
chppch/ Changing preprocessor characters (-p)
charset/ Tests of when charsets should be honoured and when not
cc65/ Compatibility tests for ca65 compatibility
relmode/ tests concerning switches between segments and absolute mode
Cameron Kaiser, André Fachat

View File

@ -1,3 +1,4 @@
default:
# xa should not allow this to happen. if it does, this test is no good.
../../xa 816.asm || exit 0 && exit 1
@ -18,3 +19,7 @@ default:
clean:
rm -f *.o
tests:
./runtest.sh -q -C

BIN
xa/tests/adrm/a.out-02 Normal file

Binary file not shown.

BIN
xa/tests/adrm/a.out-c02 Normal file

Binary file not shown.

BIN
xa/tests/adrm/a.out-zab Normal file

Binary file not shown.

BIN
xa/tests/adrm/a.out-zab2 Normal file

Binary file not shown.

BIN
xa/tests/adrm/a.out-zpa Normal file

Binary file not shown.

BIN
xa/tests/adrm/a.out-zpa2 Normal file

Binary file not shown.

28
xa/tests/adrm/bip2.inc Normal file
View File

@ -0,0 +1,28 @@
/*
- tbasic.0.asm: if you make vecwri absolute with !, then the branch gets
generated as if it were NOT absolute. works okay without it (and
gets a warning)
*/
test lda !$0095
bne test
ldx #13
lup0 lda !vecwri,x
sta $2005,x
dex
bne lup0
lda #$00
sta $0020
lda #$02
sta $0021
lda #$ff
sta $0022
lda #$13
sta $0023
jmp $2003
vectors .byt $4c, $5a, $1e, $4c, $a0, $1e, $4c, $00, $01
vecwri = vectors - 1

35
xa/tests/adrm/runtest.sh Executable file
View File

@ -0,0 +1,35 @@
#!/bin/bash
# run a test script
#THISDIR=`dirname $0`
THISDIR=`pwd`
#echo "0=$0"
#echo "THISDIR=$THISDIR"
declare -A opts
#opts=([816.asm]="-w")
opts[02.asm]="-C"
opts[816.asm]="-w"
opts[zab.asm]="-w"
opts[zpa.asm]="-w"
#ASMFLAGS=-v
ASMFLAGS=
# exclude filter from *.asm if no explicit file is given
EXCLUDE=
# test files used
TESTFILES="bip.inc bip2.inc"
# files to compare afterwards, against <file>-<script>
COMPAREFILES=a.out
XA=$THISDIR/../../xa
##########################
# actual code
. ../func.sh

4
xa/tests/adrm/zab2.asm Normal file
View File

@ -0,0 +1,4 @@
.word $4000
* = $4000
#include "bip2.inc"

4
xa/tests/adrm/zpa2.asm Normal file
View File

@ -0,0 +1,4 @@
.word $0000
* = $0000
#include "bip2.inc"

View File

@ -1,3 +1,4 @@
default:
../../xa test.asm -o test.o
../hextool -cmp=test.ok < test.o
@ -10,3 +11,5 @@ default:
clean:
rm -f *.o

34
xa/tests/ca65/Makefile Normal file
View File

@ -0,0 +1,34 @@
#
# Makefile for tests
#
XA=../../xa
CA65=ca65
LD65=ld65
tests: unnamed1 unnamed2 escape1 escape2 clean
unnamed1: unnamed1.a65
#${CA65} $<; ${LD65} -t none -o unnamed1.ca65 unnamed1.o; rm unnamed1.o
${XA} -XCA65 $<
cmp unnamed1.ca65 a.o65
unnamed2: unnamed2.a65
#${CA65} $<; ${LD65} -t none -o unnamed2.ca65 unnamed2.o; rm unnamed2.o
${XA} -XCA65 $< 2>a.err || true
cmp unnamed2.ca65 a.o65
escape1: escape1.a65
${XA} $<
cmp escape1.out a.o65
escape2: escape2.a65
#${CA65} $<; ${LD65} -t none -o escape2.ca65 escape2.o; rm escape2.o
${XA} -XCA65 $< 2>a.err || true
cmp escape2.ca65 a.o65
clean:
rm -f a.err a.o65

View File

@ -0,0 +1,6 @@
*=$1000
lda #"^^"

View File

@ -0,0 +1 @@
ゥ^

View File

@ -0,0 +1,6 @@
.org $1000
lda #'^'

View File

@ -0,0 +1 @@
ゥ^

View File

@ -0,0 +1,15 @@
; test of unnamed labels
start: .org $4000
lda #$00
: iny ; first
bne :- ; go to first
beq :++ ; go to third
: ; second
jmp :- ; go to second
jmp :++
: ldy #1 ; third
: nop

BIN
xa/tests/ca65/unnamed1.ca65 Normal file

Binary file not shown.

View File

@ -0,0 +1,17 @@
; test of unnamed labels
start: .org $4000
lda #$00
: iny ; first
bne :- ; go to first
beq :++ ; go to third
.scope
: ; second
jmp :- ; go to second
jmp :++
: ldy #1 ; third
.endscope
: nop

BIN
xa/tests/ca65/unnamed2.ca65 Normal file

Binary file not shown.

View File

@ -0,0 +1,3 @@
unnamed2.a65:line 9: 4007:Label '(null)' not defined
unnamed2.a65:line 13: 400e:Label '(null)' not defined
Break after 2 errors

View File

@ -0,0 +1,5 @@
tests:
./runtest.sh -q -C

View File

@ -0,0 +1,32 @@
#!/bin/bash
# run a test script
#THISDIR=`dirname $0`
THISDIR=`pwd`
#echo "0=$0"
#echo "THISDIR=$THISDIR"
#declare -A opts
#opts=([816.asm]="-w")
#opts[02.asm]="-C"
#ASMFLAGS=-v
ASMFLAGS=
# exclude filter from *.asm if no explicit file is given
EXCLUDE=
# test files used
TESTFILES=""
# files to compare afterwards, against <file>-<script>
COMPAREFILES=a.out
XA=$THISDIR/../../xa
##########################
# actual code
. ../func.sh

View File

@ -1,3 +1,4 @@
default:
../../xa test.s
../hextool -cmp=no-charset.o < a.o65
@ -10,3 +11,7 @@ default:
clean:
rm -rf a.o65
tests:
./runtest.sh -q -C

BIN
xa/tests/charset/a.out-test Normal file

Binary file not shown.

32
xa/tests/charset/runtest.sh Executable file
View File

@ -0,0 +1,32 @@
#!/bin/bash
# run a test script
#THISDIR=`dirname $0`
THISDIR=`pwd`
#echo "0=$0"
#echo "THISDIR=$THISDIR"
declare -A opts
#opts=([816.asm]="-w")
opts[testpet.asm]="-OPETSCII"
#ASMFLAGS=-v
ASMFLAGS=
# exclude filter from *.asm if no explicit file is given
EXCLUDE=
# test files used
TESTFILES="README.1st test2.s"
# files to compare afterwards, against <file>-<script>
COMPAREFILES=a.out
XA=$THISDIR/../../xa
##########################
# actual code
. ../func.sh

View File

@ -0,0 +1,16 @@
.word $9000
* = $9000
w = 10
.bin 0,10+w,"README.1st"
.bin 0,10,"README.1st"
#include "test2.s"
.byt "FooBar"
.aasc "FooBar"
.asc "FooBar",65,97,10
.aasc "FooBar"
.bin 0,10,"README.1st"
.aasc "Barfoo",65,97,10
lda #'A'
lda #"A"

View File

@ -1,3 +1,4 @@
default:
# this should fail.
../../xa scomcom.asm || exit 0 && exit 1
@ -12,3 +13,7 @@ default:
clean:
rm -f a.o65
tests:
./runtest.sh -q -C

Binary file not shown.

View File

@ -0,0 +1 @@
<EFBFBD><01>

1
xa/tests/comcom/comcom2.asm Symbolic link
View File

@ -0,0 +1 @@
comcom.asm

33
xa/tests/comcom/runtest.sh Executable file
View File

@ -0,0 +1,33 @@
#!/bin/bash
# run a test script
#THISDIR=`dirname $0`
THISDIR=`pwd`
#echo "0=$0"
#echo "THISDIR=$THISDIR"
declare -A opts
#opts=([816.asm]="-w")
opts[comcom2.asm]="-M"
opts[scomcom.asm]="-M"
#ASMFLAGS=-v
ASMFLAGS=
# exclude filter from *.asm if no explicit file is given
EXCLUDE=
# test files used
TESTFILES=""
# files to compare afterwards, against <file>-<script>
COMPAREFILES=a.out
XA=$THISDIR/../../xa
##########################
# actual code
. ../func.sh

View File

@ -1,3 +1,4 @@
default:
# this must not pass.
../../xa -DFAIL test3.asm || exit 0 && exit 1
@ -12,3 +13,6 @@ default:
clean:
rm -f a.o65 test.out
tests:
./runtest.sh -q -C

Binary file not shown.

34
xa/tests/fordef/runtest.sh Executable file
View File

@ -0,0 +1,34 @@
#!/bin/bash
# run a test script
#THISDIR=`dirname $0`
THISDIR=`pwd`
#echo "0=$0"
#echo "THISDIR=$THISDIR"
declare -A opts
#opts=([816.asm]="-w")
#opts[02.asm]="-C"
declare -A errs
errs[test4.asm]=1
#ASMFLAGS=-v
ASMFLAGS=
# exclude filter from *.asm if no explicit file is given
EXCLUDE=
# test files used
TESTFILES="test2.s"
# files to compare afterwards, against <file>-<script>
COMPAREFILES="a.out test.asm.err test4.asm.err"
XA=$THISDIR/../../xa
##########################
# actual code
. ../func.sh

View File

@ -16,5 +16,5 @@ t1 lda `forward1
sta `forward2
rts
#include "test2.asm"
#include "test2.s"

View File

@ -0,0 +1,4 @@
Copyright (C) 1989-2009 Andre Fachat, Jolse Maginnis, David Weinehall
and Cameron Kaiser.
test.asm:line 6: 0400: Warning - Can't optimize forward-defined label; using absolute addressing
test.asm:line 7: 0403: Warning - Can't optimize forward-defined label; using absolute addressing

View File

@ -18,4 +18,4 @@
lda (forward1),y
jmp forward3
#include "test2.asm"
#include "test2.s"

18
xa/tests/fordef/test4.asm Normal file
View File

@ -0,0 +1,18 @@
.word $0400
*=$0400
/* define this if you want to crash and burn */
jmp `forward3
bne `forward3
lda (`forward1),y
lda (`forward3),y
sta `forward3
/* this looks like it should fail, but won't because there is no ambiguity */
lda (forward1),y
jmp forward3
#include "test2.s"

View File

@ -0,0 +1,7 @@
Copyright (C) 1989-2009 Andre Fachat, Jolse Maginnis, David Weinehall
and Cameron Kaiser.
test4.asm:line 6: 0400:Wrong addressing mode error
test4.asm:line 7: 0402:Wrong addressing mode error
test4.asm:line 8: 0401:Wrong addressing mode error
test4.asm:line 9: 0400:Wrong addressing mode error
test4.asm:line 9: 0409:Overflow error

319
xa/tests/func.sh Executable file
View File

@ -0,0 +1,319 @@
#!/bin/bash
declare -A errs
declare -A opts
function usage() {
echo "Assemble *.asm or *.a65 test files"
echo " $0 [options] [frs_scripts]"
echo "Options:"
echo " -v verbose log"
echo " -o server log on console"
echo " -d <breakpoint> run xa with gdb and set given breakpoint. Can be "
echo " used multiple times"
echo " -k keep all files, even non-log and non-data files in run directory"
echo " -c clean up only non-log and non-data files from run directory,"
echo " keep rest (default)"
echo " -C always clean up complete run directory"
echo " -R <run directory> use given run directory instead of tmp folder (note:"
echo " will not be rmdir'd on -C"
echo " -q will suppress any output except whether test was successful"
echo " -h show this help"
}
function contains() {
local j
for j in "${@:2}"; do test "$j" == "$1" && return 0; done;
return 1;
}
function hexdiff() {
diffres=0
if ! cmp -b "$1" "$2"; then
tmp1=`mktemp`
tmp2=`mktemp`
hexdump -C "$1" > $tmp1
hexdump -C "$2" > $tmp2
diff -u $tmp1 $tmp2
diffres=$?
rm $tmp1 $tmp2
fi;
return $diffres
}
VERBOSE=""
DEBUG=""
CLEAN=1
QUIET=0
LOGFILE=""
TMPDIR=`mktemp -d`
OWNDIR=1
while test $# -gt 0; do
case $1 in
-h)
usage
exit 0;
;;
-o)
LOGFILE="-"
shift;
;;
-v)
VERBOSE="-v"
shift;
;;
-d)
if test $# -lt 2; then
echo "Option -d needs the break point name for gdb as parameter"
exit -1;
fi;
DEBUG="$DEBUG $2"
shift 2;
;;
-k)
CLEAN=0
shift;
;;
-c)
CLEAN=1
shift;
;;
-C)
CLEAN=2
shift;
;;
-q)
QUIET=1
shift;
;;
-R)
if test $# -lt 2; then
echo "Option -R needs the directory path as parameter"
exit -1;
fi;
TMPDIR="$2"
OWNDIR=0
shift 2;
;;
-?)
echo "Unknown option $1"
usage
exit 1;
;;
*)
break;
;;
esac;
done;
#######################
# test for executables
ERR=0
if test ! -e $XA; then
echo "$XA does not exist! Maybe forgot to compile?"
ERR=1
fi
if [ $ERR -ge 1 ]; then
echo "Aborting!"
exit 1;
fi
# scripts to run
if [ "x$*" = "x" ]; then
shopt -s extglob
SCRIPTS=$THISDIR/*${FILTER}*.a[s6][m5]
SCRIPTS=`basename -a $SCRIPTS`;
TESTSCRIPTS=""
if test "x$EXCLUDE" != "x"; then
exarr=( $EXCLUDE )
scrarr=( $SCRIPTS )
for scr in "${scrarr[@]}"; do
if ! contains "${scr}" "${exarr[@]}"; then
TESTSCRIPTS="$TESTSCRIPTS $scr";
fi
done;
else
TESTSCRIPTS="$SCRIPTS"
fi;
else
TESTSCRIPTS="";
for i in "$@"; do
if test -f "$i".asm ; then
TESTSCRIPTS="$TESTSCRIPTS $i.asm";
else
if test -f "$i".a65 ; then
TESTSCRIPTS="$TESTSCRIPTS $i.a65";
else
TESTSCRIPTS="$TESTSCRIPTS $i";
fi
fi
done;
fi;
#echo "TESTSCRIPTS=$TESTSCRIPTS"
########################
# tmp names
#
DEBUGFILE="$TMPDIR"/gdb.ex
########################
# stdout
# remember stdout for summary output
exec 5>&1
exec 6>&2
# redirect log when quiet
if test $QUIET -ge 1 ; then
exec 1>$TMPDIR/stdout.log
exec 2>$TMPDIR/stderr.log
fi
########################
# prepare files
#
for i in $TESTSCRIPTS; do
cp "$THISDIR/$i" "$TMPDIR"
done;
########################
# run scripts
#
for script in $TESTSCRIPTS; do
echo "Run script $script"
AFLAGS="${ASMFLAGS} ${opts[$script]}"
ALOG=
if test "x$LOGFILE" = "x"; then
ALOG="-P $script.log"
else
ALOG="-P $LOGFILE"
fi
ALOG="$ALOG -e $script.err"
# overwrite test files in each iteration, just in case
for i in $TESTFILES; do
if [ -f ${THISDIR}/${i}.gz ]; then
gunzip -c ${THISDIR}/${i}.gz > ${TMPDIR}/${i}
else
cp ${THISDIR}/${i} ${TMPDIR}/${i}
fi;
done;
if test "x$DEBUG" = "x"; then
############################################
# simply do assemble
echo "Run assembler:" $XA $AFLAGS $script
(cd $TMPDIR; $XA -o a.out $ALOG $AFLAGS $script)
RESULT=$?
# check if we actually expected an error
#echo "errs=${errs[$script]}"
if [ "x${errs[$script]}" != "x" ]; then
if [ "$RESULT" = ${errs[$script]} ]; then
echo "override error because was expected"
RESULT=0
fi
fi
if test $RESULT -eq 0; then
echo "$script: Ok" >&5
else
echo "$script: errors: $RESULT" >&5
fi
else
echo > $DEBUGFILE;
for i in $DEBUG; do
echo "break $i" >> $DEBUGFILE
done;
gdb -x $DEBUGFILE -ex "run -o $TMPDIR/a.out $ALOG $AFLAGS $script" $XA
fi;
#echo "Killing server (pid $SERVERPID)"
#kill -TERM $SERVERPID
if [ -f "${THISDIR}/$script.err" ]; then
echo "Comparing file ${script}.err"
hexdiff ${THISDIR}/$script.err ${TMPDIR}/$script.err
fi
if test "x$COMPAREFILES" != "x"; then
testname=`basename $script .asm`
if [ "$script" = "$testname" ]; then
testname=`basename $script .a65`
fi
for i in $COMPAREFILES; do
NAME="${THISDIR}/${i}-${testname}"
if test -f ${NAME}; then
echo "Comparing file ${i} with ${NAME}"
hexdiff ${NAME} $TMPDIR/${i}
if test $? -ne 0; then
echo "$script: File ${i} differs!" >&5
fi;
fi
if test -f ${NAME}.gz; then
echo "Comparing file ${i} with ${NAME}.gz"
gunzip -c ${NAME}.gz > ${TMPDIR}/shouldbe_${i}
hexdiff ${TMPDIR}/shouldbe_${i} ${TMPDIR}/${i}
if test $? -ne 0; then
echo "$script: File ${i} differs!" >&5
fi;
rm -f ${TMPDIR}/shouldbe_${i}
fi
done;
fi
if test $CLEAN -ge 1; then
rm -f $DEBUGFILE;
rm -f $TMPDIR/$script;
rm -f $TMPDIR/a.out;
fi
done;
if test $CLEAN -ge 2; then
echo "Cleaning up directory $TMPDIR"
for script in $TESTSCRIPTS; do
rm -f $TMPDIR/$script.log
rm -f $TMPDIR/$script.err
done;
# gzipped test files are unzipped
for i in $TESTFILES; do
rm -f $TMPDIR/$i;
done;
rm -f $TMPDIR/stdout.log
rm -f $TMPDIR/stderr.log
# only remove work dir if we own it (see option -R)
if test $OWNDIR -ge 1; then
rmdir $TMPDIR
fi;
else
echo "Find debug info in $TMPDIR" >&5
fi;

View File

@ -1,8 +1,13 @@
default:
# in 6502 mode, it will fail.
../../xa test.s || exit 0 && exit 1
../../xa test.a65 || exit 0 && exit 1
# in 65816 mode, it will pass.
../../xa -w test.s
../../xa -w test.a65
clean:
rm -f a.o65
tests:
./runtest.sh -q -C

31
xa/tests/incerr/runtest.sh Executable file
View File

@ -0,0 +1,31 @@
#!/bin/bash
# run a test script
#THISDIR=`dirname $0`
THISDIR=`pwd`
#echo "0=$0"
#echo "THISDIR=$THISDIR"
declare -A opts
opts=([test.a65]="-w")
#ASMFLAGS=-v
ASMFLAGS=
# exclude filter from *.asm if no explicit file is given
EXCLUDE=
# test files used
TESTFILES="test.6502"
# files to compare afterwards, against <file>-<script>
COMPAREFILES=
XA=$THISDIR/../../xa
##########################
# actual code
. ../func.sh

6
xa/tests/line/Makefile Normal file
View File

@ -0,0 +1,6 @@
all: test1
%:%.a65
../../xa $<

20
xa/tests/line/test1.a65 Normal file
View File

@ -0,0 +1,20 @@
/*
* tests the internal line presentation getting over 128
*/
#define MAX_ENDPOINTS 4
*=$c000
txmax .dsb MAX_ENDPOINTS, 0 ; max transfer length per endpoint
txpos .dsb MAX_ENDPOINTS, 0 ; endpoint buffer position per endpoint, calculated at usbd_start
txlen .dsb MAX_ENDPOINTS, 0 ; endpoint buffer length, set per transaction
/*
* tests the internal line presentation getting over 256
*/
txpos2 .byt MAX_ENDPOINTS, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ; endpoint buffer position per endpoint, calculated at usbd_start and even more comments, but the many values alone use 5 byte per value internally...

39
xa/tests/listing/Makefile Normal file
View File

@ -0,0 +1,39 @@
#
# Makefile for tests
#
XA=../../xa
CA65=ca65
LD65=ld65
tests: linebreak include1 listblocks listca65 listca65_2 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
listblocks: listblocks.a65
${XA} -P- -Fhtml listblocks.a65 > a.out
cmp listblocks.html a.out
listca65: listca65.a65
${XA} -XCA65 -P- -Fhtml listca65.a65 > a.out
#${CA65} $<; ${LD65} -t none -o listca65.ca65 listca65.o; rm listca65.o
cmp listca65.html a.out
cmp listca65.ca65 a.o65
listca65_2: listca65_2.a65
${XA} -XCA65 -P- -Fhtml listca65_2.a65 > a.out
${CA65} $<; ${LD65} -t none -o listca65_2.ca65 listca65_2.o; rm listca65_2.o
cmp listca65_2.html a.out
cmp listca65_2.ca65 a.o65
clean:
rm -f a.err a.o65 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

View File

@ -0,0 +1,160 @@
*=$1000
// default listbytes is 8
lda #$0
// first without labels
.(
// less than 8 bytes
.byt 0,1,2,3,4,5 ; 6
// seven bytes
.byt 0,1,2,3,4,5,6 ; 7
// eight bytes
.byt 0,1,2,3,4,5,6,7 ; 8
// nine bytes
.byt 0,1,2,3,4,5,6,7,8 ; 9
// ten bytes
.byt 0,1,2,3,4,5,6,7,8,9 ; 10
// eleven bytes
.byt 0,1,2,3,4,5,6,7,8,9,10 ; 11
// fifteen bytes
.asc "012345678901234" ; 15, asc test as well
// sixteen bytes
.asc "0123456789012345" ; 16
// seventeen bytes
.asc "01234567890123456"; 17
// thirtythree
.asc "012345678901234567890123456789012"; 32
// now with labels
// less than 8 bytes
l6 .byt 0,1,2,3,4,5 ; 6
// seven bytes
l7 .byt 0,1,2,3,4,5,6 ; 7
// eight bytes
l8 .byt 0,1,2,3,4,5,6,7 ; 8
// nine bytes
l9 .byt 0,1,2,3,4,5,6,7,8 ; 9
// ten bytes
l10 .byt 0,1,2,3,4,5,6,7,8,9 ; 10
// eleven bytes
l11 .byt 0,1,2,3,4,5,6,7,8,9,10 ; 11
// fifteen bytes
l15 .asc "012345678901234" ; 15, asc test as well
// sixteen bytes
l16 .asc "0123456789012345" ; 16
// seventeen bytes
l17 .asc "01234567890123456"; 17
// thirtythree
l32 .asc "012345678901234567890123456789012"; 32
.)
// now set number of bytes per listing line to 10
.listbytes 10
.(
// less than 8 bytes
.byt 0,1,2,3,4,5 ; 6
// seven bytes
.byt 0,1,2,3,4,5,6 ; 7
// eight bytes
.byt 0,1,2,3,4,5,6,7 ; 8
// nine bytes
.byt 0,1,2,3,4,5,6,7,8 ; 9
// ten bytes
.byt 0,1,2,3,4,5,6,7,8,9 ; 10
// eleven bytes
.byt 0,1,2,3,4,5,6,7,8,9,10 ; 11
// fifteen bytes
.asc "012345678901234" ; 15, asc test as well
// sixteen bytes
.asc "0123456789012345" ; 16
// seventeen bytes
.asc "01234567890123456"; 17
// thirtythree
.asc "012345678901234567890123456789012"; 32
// now with labels
// less than 8 bytes
l6 .byt 0,1,2,3,4,5 ; 6
// seven bytes
l7 .byt 0,1,2,3,4,5,6 ; 7
// eight bytes
l8 .byt 0,1,2,3,4,5,6,7 ; 8
// nine bytes
l9 .byt 01,2,3,4,5,6,7,8 ; 9
// ten bytes
l10 .byt 01,2,3,4,5,6,7,8,9 ; 10
// eleven bytes
l11 .byt 01,2,3,4,5,6,7,8,9,10 ; 11
// fifteen bytes
l15 .asc "012345678901234" ; 15, asc test as well
// sixteen bytes
l16 .asc "0123456789012345" ; 16
// seventeen bytes
l17 .asc "01234567890123456"; 17
// thirtythree
l32 .asc "012345678901234567890123456789012"; 32
.)
// set number of listing bytes to unlimited
.listbytes unlimited
.(
// less than 8 bytes
.byt 0,1,2,3,4,5 ; 6
// seven bytes
.byt 0,1,2,3,4,5,6 ; 7
// eight bytes
.byt 0,1,2,3,4,5,6,7 ; 8
// nine bytes
.byt 0,1,2,3,4,5,6,7,8 ; 9
// ten bytes
.byt 0,1,2,3,4,5,6,7,8,9 ; 10
// eleven bytes
.byt 0,1,2,3,4,5,6,7,8,9,10 ; 11
// fifteen bytes
.asc "012345678901234" ; 15, asc test as well
// sixteen bytes
.asc "0123456789012345" ; 16
// seventeen bytes
.asc "01234567890123456"; 17
// thirtythree
.asc "012345678901234567890123456789012"; 32
// now with labels
// less than 8 bytes
l6 .byt 0,1,2,3,4,5 ; 6
// seven bytes
l7 .byt 0,1,2,3,4,5,6 ; 7
// eight bytes
l8 .byt 0,1,2,3,4,5,6,7 ; 8
// nine byte
l9 .byt 0,1,2,3,4,5,6,7,8 ; 9
// ten bytes
l10 .byt 0,1,2,3,4,5,6,7,8,9 ; 10
// eleven bytes
l11 .byt 0,1,2,3,4,5,6,7,8,9,10 ; 11
// fifteen bytes
l15 .asc "012345678901234" ; 15, test as well
// sixteen bytes
l16 .asc "0123456789012345" ; 16
// seventeen bytes
l17 .asc "01234567890123456"; 17
// thirtythree
l32 .asc "012345678901234567890123456789012"; 32
.)

View File

@ -0,0 +1,162 @@
linebreak.a65
2 A:1000 *= $1000
6 A:1000 a9 00 lda #$00
10 A:1002 .(
12 A:1002 00 01 02 03 04 05 .byt 0,1,2,3,4,5; 6
14 A:1008 00 01 02 03 04 05 06 .byt 0,1,2,3,4,5,6; 7
16 A:100f 00 01 02 03 04 05 06 07 .byt 0,1,2,3,4,5,6,7; 8
18 A:1017 00 01 02 03 04 05 06 ... .byt 0,1,2,3,4,5,6,7,8; 9
20 A:1020 00 01 02 03 04 05 06 ... .byt 0,1,2,3,4,5,6,7,8,9; 10
22 A:102a 00 01 02 03 04 05 06 ... .byt 0,1,2,3,4,5,6,7,8,9,10; 11
24 A:1035 30 31 32 33 34 35 36 ... .asc "012345678901234" ; 15, asc test as well
26 A:1044 30 31 32 33 34 35 36 ... .asc "0123456789012345" ; 16
28 A:1054 30 31 32 33 34 35 36 ... .asc "01234567890123456"; 17
30 A:1065 30 31 32 33 34 35 36 ... .asc "012345678901234567890123456789012"; 32
35 A:1086 00 01 02 03 04 05 l6 .byt 0,1,2,3,4,5; 6
37 A:108c 00 01 02 03 04 05 06 l7 .byt 0,1,2,3,4,5,6; 7
39 A:1093 00 01 02 03 04 05 06 07 l8 .byt 0,1,2,3,4,5,6,7; 8
41 A:109b 00 01 02 03 04 05 06 ... l9 .byt 0,1,2,3,4,5,6,7,8; 9
43 A:10a4 00 01 02 03 04 05 06 ... l10 .byt 0,1,2,3,4,5,6,7,8,9; 10
45 A:10ae 00 01 02 03 04 05 06 ... l11 .byt 0,1,2,3,4,5,6,7,8,9,10; 11
47 A:10b9 30 31 32 33 34 35 36 ... l15 .asc "012345678901234"; 15, asc test as well
49 A:10c8 30 31 32 33 34 35 36 ... l16 .asc "0123456789012345"; 16
51 A:10d8 30 31 32 33 34 35 36 ... l17 .asc "01234567890123456"; 17
53 A:10e9 30 31 32 33 34 35 36 ... l32 .asc "012345678901234567890123456789012"; 32
55 A:110a .)
59 A:110a .listbytes 10
61 A:110a .(
63 A:110a 00 01 02 03 04 05 .byt 0,1,2,3,4,5; 6
65 A:1110 00 01 02 03 04 05 06 .byt 0,1,2,3,4,5,6; 7
67 A:1117 00 01 02 03 04 05 06 07 .byt 0,1,2,3,4,5,6,7; 8
69 A:111f 00 01 02 03 04 05 06 07 08 .byt 0,1,2,3,4,5,6,7,8; 9
71 A:1128 00 01 02 03 04 05 06 07 08 09 .byt 0,1,2,3,4,5,6,7,8,9; 10
73 A:1132 00 01 02 03 04 05 06 07 08 ... .byt 0,1,2,3,4,5,6,7,8,9,10; 11
75 A:113d 30 31 32 33 34 35 36 37 38 ... .asc "012345678901234" ; 15, asc test as well
77 A:114c 30 31 32 33 34 35 36 37 38 ... .asc "0123456789012345" ; 16
79 A:115c 30 31 32 33 34 35 36 37 38 ... .asc "01234567890123456"; 17
81 A:116d 30 31 32 33 34 35 36 37 38 ... .asc "012345678901234567890123456789012"; 32
87 A:118e 00 01 02 03 04 05 l6 .byt 0,1,2,3,4,5; 6
89 A:1194 00 01 02 03 04 05 06 l7 .byt 0,1,2,3,4,5,6; 7
91 A:119b 00 01 02 03 04 05 06 07 l8 .byt 0,1,2,3,4,5,6,7; 8
93 A:11a3 01 02 03 04 05 06 07 08 l9 .byt 1,2,3,4,5,6,7,8; 9
95 A:11ab 01 02 03 04 05 06 07 08 09
95 A:11ab l10 .byt 1,2,3,4,5,6,7,8,9; 10
97 A:11b4 01 02 03 04 05 06 07 08 09 0a
97 A:11b4 l11 .byt 1,2,3,4,5,6,7,8,9,10; 11
99 A:11be 30 31 32 33 34 35 36 37 38 ...
99 A:11be l15 .asc "012345678901234"; 15, asc test as well
101 A:11cd 30 31 32 33 34 35 36 37 38 ...
101 A:11cd l16 .asc "0123456789012345"; 16
103 A:11dd 30 31 32 33 34 35 36 37 38 ...
103 A:11dd l17 .asc "01234567890123456"; 17
105 A:11ee 30 31 32 33 34 35 36 37 38 ...
105 A:11ee l32 .asc "012345678901234567890123456789012"; 32
107 A:120f .)
110 A:120f .listbytes 0
112 A:120f .(
114 A:120f 00 01 02 03 04 05 .byt 0,1,2,3,4,5; 6
116 A:1215 00 01 02 03 04 05 06 .byt 0,1,2,3,4,5,6; 7
118 A:121c 00 01 02 03 04 05 06 07 .byt 0,1,2,3,4,5,6,7; 8
120 A:1224 00 01 02 03 04 05 06 07 08 .byt 0,1,2,3,4,5,6,7,8; 9
122 A:122d 00 01 02 03 04 05 06 07 08 09 .byt 0,1,2,3,4,5,6,7,8,9; 10
124 A:1237 00 01 02 03 04 05 06 07 08 09 0a .byt 0,1,2,3,4,5,6,7,8,9,10; 11
126 A:1242 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34
126 A:1242 .asc "012345678901234" ; 15, asc test as well
128 A:1251 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35
128 A:1261 .asc "0123456789012345" ; 16
130 A:1261 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35
130 A:1271 36 .asc "01234567890123456"; 17
132 A:1272 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35
132 A:1282 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31
132 A:1292 32 .asc "012345678901234567890123456789012"; 32
138 A:1293 00 01 02 03 04 05 l6 .byt 0,1,2,3,4,5; 6
140 A:1299 00 01 02 03 04 05 06 l7 .byt 0,1,2,3,4,5,6; 7
142 A:12a0 00 01 02 03 04 05 06 07 l8 .byt 0,1,2,3,4,5,6,7; 8
144 A:12a8 00 01 02 03 04 05 06 07 08
144 A:12a8 l9 .byt 0,1,2,3,4,5,6,7,8; 9
146 A:12b1 00 01 02 03 04 05 06 07 08 09
146 A:12b1 l10 .byt 0,1,2,3,4,5,6,7,8,9; 10
148 A:12bb 00 01 02 03 04 05 06 07 08 09 0a
148 A:12bb l11 .byt 0,1,2,3,4,5,6,7,8,9,10; 11
150 A:12c6 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34
150 A:12c6 l15 .asc "012345678901234"; 15, test as well
152 A:12d5 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35
152 A:12e5 l16 .asc "0123456789012345"; 16
154 A:12e5 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35
154 A:12f5 36 l17 .asc "01234567890123456"; 17
156 A:12f6 30 31 32 33 34 35 36 37 38 39 30 31 32 33 34 35
156 A:1306 36 37 38 39 30 31 32 33 34 35 36 37 38 39 30 31
156 A:1316 32 l32 .asc "012345678901234567890123456789012"; 32
158 A:1317 .)

View File

@ -0,0 +1,23 @@
// tests the html listing feature with blocks that
// contain the same label names, but in different scopes
*=$1000
label1 lda #$00
.(
label2 sta $02
bne label2
.)
.(
label2 lda $02 ; again!
bne label2
.)
label2 iny
beq label2
jmp label1

View File

@ -0,0 +1,24 @@
<html><head><title>(null)</title></head><body><pre>
listblocks.a65
5 A:1000 *= $1000
7 A:1000 a9 00 <a name="0_label1"> </a>label1 lda #$00
9 A:1002 .(
10 A:1002 85 02 <a name="1_label2"> </a>label2 sta $02
11 A:1004 d0 fc bne <a href="#1_label2">label2</a>
12 A:1006 .)
14 A:1006 .(
15 A:1006 a5 02 <a name="2_label2"> </a>label2 lda $02 ; again!
16 A:1008 d0 fc bne <a href="#2_label2">label2</a>
17 A:100a .)
19 A:100a c8 <a name="0_label2"> </a>label2 iny
20 A:100b f0 fd beq <a href="#0_label2">label2</a>
22 A:100d 4c 00 10 jmp <a href="#0_label1">label1</a>
</pre></body></html>

View File

@ -0,0 +1,24 @@
; tests the html listing feature with blocks that
; contain the same label names, but in different scopes
.org $1000
: lda #$00
.scope
: sta $02
: bne :-
.endscope
.scope
@label2: lda $02 ; again!
bne @label2
.endscope
label2: iny
beq label2
beq :---
jmp :--

Binary file not shown.

View File

@ -0,0 +1,30 @@
<html><head><title>(null)</title></head><body><pre>
listca65.a65
2 A:1000 ; tests the html listing feature with blocks that
3 A:1000 ; contain the same label names, but in different scopes
5 A:1000 *= $1000
7 A:1000 a9 00 <a name="0U0"> </a>: lda #$00
9 A:1002 .(
10 A:1002 85 02 <a name="1U1"> </a>: sta $02
11 A:1004 d0 fe <a name="1U2"> </a>: bne <a href="#1U2">:-</a>
12 A:1006 .)
14 A:1006 .(
15 A:1006 <a name="3Clabel2"> </a>@label2
15 A:1006 a5 02 lda $02 ; again!
16 A:1008 d0 fc bne <a href="#3Clabel2">@label2</a>
17 A:100a .)
19 A:100a <a name="0_label2"> </a>label2
19 A:100a c8 iny
20 A:100b f0 fd beq <a href="#0_label2">label2</a>
22 A:100d f0 f1 beq <a href="#0U0">:---</a>
23 A:100f 4c 02 10 jmp <a href="#1U1">:--</a>
</pre></body></html>

BIN
xa/tests/listing/listca65.o Normal file

Binary file not shown.

View File

@ -0,0 +1,15 @@
; tests the html listing feature with blocks that
; contain the same label names, but in different scopes
.org $1000
: lda #$00
.include "listca65_2b.a65"
label2: iny
beq label2
jmp :-

Binary file not shown.

View File

@ -0,0 +1,32 @@
<html><head><title>(null)</title></head><body><pre>
listca65_2.a65
2 A:1000 ; tests the html listing feature with blocks that
3 A:1000 ; contain the same label names, but in different scopes
5 A:1000 *= $1000
7 A:1000 a9 00 <a name="0U0"> </a>: lda #$00
9 A:1002 .include "listca65_2b.a65"
listca65_2b.a65
2 A:1002 ; to be included in listca65_2.a65
3 A:1002 ; to check HTML linkage of unnamed labels across files
5 A:1002 c8 <a name="0U1"> </a>: iny
6 A:1003 d0 fd bne <a href="#0U1">:-</a>
listca65_2.a65
11 A:1005 <a name="0_label2"> </a>label2
11 A:1005 c8 iny
12 A:1006 f0 fd beq <a href="#0_label2">label2</a>
14 A:1008 4c 02 10 jmp <a href="#0U1">:-</a>
</pre></body></html>

View File

@ -0,0 +1,7 @@
; to be included in listca65_2.a65
; to check HTML linkage of unnamed labels across files
: iny
bne :-

View File

@ -0,0 +1,13 @@
XA=../../xa
all: test1 test2 test3 test4 test5 test6 test6a test6b test7 clean
clean:
rm a.o65
%:%.a65
${XA} -XC $<
cmp a.o65 $@.o65

View File

@ -0,0 +1,32 @@
#define macro1() \
lda #0
#define macro2(a) \
lda #(a)
#define macro3(a,b) \
lda #(a): \
ldy #(b)
#define const1 $40
#define func1(a) (a) | $20
*=$c000
macro1()
macro2(2)
macro3(2,3)
lda #(2) | $20
lda #func1(2)
macro2(func1(3))
macro3(const1, func1(5))
macro3(func1(const1), func1(func1(const1)))

Binary file not shown.

View File

@ -0,0 +1,33 @@
/*
* tests the definition of macro parameters with spaces
* between the name and the brackers / comma
*/
#define wreg(reg, val) \
lda #(reg) | 0x02 :\
lda #(val)
#define wreg2( reg , val , val2 ) \
lda #(reg) | 0x02 :\
lda #(val) :\
ldx #(val2)
#define wreg3(reg, val, val2) \
.byt reg, val, val2
#define P1 1
#define P2 2
#define P3 3
*=$c000
wreg(P1, P2)
wreg2(P1, P2, P3)
wreg3( P1 , P2 , P3 )

Some files were not shown because too many files have changed in this diff Show More