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

Compare commits

...

3 Commits

Author SHA1 Message Date
Andre Fachat
1691f5fb46 added first listing feature! 2011-12-16 23:35:53 +01:00
Andre Fachat
eae097c73a added more ca65 compatibility fixes, like
Implement CA65 "cheap local labels", ":=" label definitions,
    and various pseudo opcodes (.include, .import, .importzp,
    .zeropage, .proc (anonymous only), .endproc, .code, .org, .reloc)
2011-12-16 23:30:15 +01:00
Andre Fachat
f28af4a917 added ca65 compatibiltiy patch 2011-12-16 23:22:32 +01:00
17 changed files with 1044 additions and 125 deletions

View File

@ -295,3 +295,19 @@ xa-2.3.5
* Documentation updated.
-- Cameron Kaiser <ckaiser@floodgap.com> 7 February, 2009
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

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,11 @@ 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 \-e filename
Set errorlog filename, default is none.
.TP
@ -67,9 +75,18 @@ 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 "="), and also the "cheap local labels" using
the "@" character. This, however, disables the "@" 24-bit enforcement.
.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.
@ -339,7 +356,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 +458,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 +508,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 +549,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 +571,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 +593,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 +879,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

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

View File

@ -61,7 +61,10 @@
/* exported globals */
int ncmos, cmosfl, w65816, n65816;
int masm = 0;
/* compatibility flags */
int masm = 0; /* MASM */
int ca65 = 0; /* CA65 */
int nolink = 0;
int romable = 0;
int romaddr = 0;
@ -71,10 +74,12 @@ int crossref = 0;
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;
@ -91,6 +96,7 @@ static int 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;
@ -117,9 +123,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 +180,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 +199,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 +221,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;
@ -276,6 +300,13 @@ 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 'o':
if(argv[i][2]==0) {
ofile=argv[++i];
@ -356,6 +387,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 +408,7 @@ int main(int argc,char *argv[])
if(verbose) fprintf(stderr, "%s\n",copyright);
if(1 /*!m_init()*/)
{
if(1 /*!b_init()*/)
@ -384,6 +422,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 */
@ -476,9 +516,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 +541,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,7 +661,7 @@ 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++];
ll=l;
@ -646,7 +692,7 @@ static int pass2(void)
} else
{
/* do not attempt address mode optimization on pass 2 */
er=t_p2(afile->mn.tmp+afile->mn.tmpe,&ll,1,&al);
er=t_p2_l(afile->mn.tmp+afile->mn.tmpe,&ll,1,&al);
if(er==E_NOLINE)
{
@ -752,7 +798,7 @@ fprintf(stderr, "offset = %i length = %i fstart = %i flen = %i charo = %c\n",
static int pass1(void)
{
signed char o[MAXLINE];
signed char o[2*MAXLINE]; /* doubled for token listing */
int l,er,temp_er,al;
memode=0;
@ -827,6 +873,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"
@ -844,6 +891,8 @@ static void usage(int default816, FILE *fp)
" -l filename sets labellist filename, default is none\n"
" -r adds crossreference list to labellist (if `-l' given)\n"
" -M allow ``:'' to appear in comments for MASM compatibility\n"
" -Xcompatset set compatibility flags for other assemblers, known values are:\n"
" MASM, CA65\n"
" -R start assembler in relocating mode\n");
fprintf(fp,
" -Llabel defines `label' as absolute, undefined label even when linking\n"
@ -900,7 +949,7 @@ static char *ertxt[] = {
"NewFile",
"CMOS-Befehl",
"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 +988,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",
@ -1062,9 +1110,20 @@ static int getline(char *s)
comcom = 1;
if (c=='\0')
break; /* hkfl = comcom = 0 */
if (c==':' && !hkfl && (!comcom || !masm)) {
gl=1;
break;
if (c==':' && !hkfl) {
/* if the next char is a "=" - so that we have a ":=" - and we
we have ca65 compatibility, we ignore the colon */
if (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;
}
}
}
j++;
} while (c!='\0' && j<MAXLINE-1 && i<MAXLINE-1);
@ -1072,7 +1131,9 @@ static int getline(char *s)
s[j]='\0';
} else
s[0]='\0';
#if 0
printf("got line: %s\n", s);
#endif
return(ec);
}
@ -1092,8 +1153,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 +1190,30 @@ 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 },
{ 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,7 +22,7 @@
#include "xah.h" /* For SEG_MAX */
extern int ncmos, cmosfl, w65816, n65816;
extern int masm, nolink;
extern int masm, ca65, nolink;
extern int noglob;
extern int showblk;
extern int relmode;

View File

@ -122,10 +122,12 @@ static int ag_term(signed char *s, int p, int *v, int *nafl, int *label)
/* 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 || ((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);
}
}
@ -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;
}
}

View File

@ -20,15 +20,22 @@
#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 200000L /* temporary memory buffer from Pass1 to Pass 2 */
typedef struct LabOcc {
struct LabOcc *next;
@ -42,9 +49,11 @@ typedef struct {
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;
int is_cll; /* 0 is normal label, 1 is cheap local label (used for listing) */
char *n;
struct LabOcc *occlist;
} Labtab;
@ -126,18 +135,24 @@ typedef struct {
#define W_OVER16M -73 /* included binary over 16M in 65816 mode */
/* warnings 74-76 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 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 +183,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;

View File

@ -50,6 +50,12 @@ static int b_get(int*);
static int b_test(int);
static int ll_def(char *s, int *n, int b);
static int b_new(void);
static void cll_init();
static int cll_get();
static void cll_clear();
static int cll_getcur();
/* local variables */
/*
@ -69,6 +75,7 @@ static Labtab *ltp;
int l_init(void)
{
cll_init();
return 0;
#if 0
int er;
@ -139,69 +146,157 @@ 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, 0);
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;
}
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;
int 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=0; /* when set, clear the cheap local label block */
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=1; /* 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) {
/* clear cheap local labels */
cll_clear();
}
if(!isalpha(s[i]) && s[i]!='_')
if(!isalpha(s[i]) && s[i]!='_' && !(ca65 && isdigit(s[i]) ) )
er=E_SYNTAX;
else
{
er=ll_search(s+i,&n);
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 +308,12 @@ 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))) /* 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 +325,23 @@ 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;
int 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=0;
if (s[0]=='@') {
cll_fl=1; /* also used as offset to the label length, so must be 1 */
s++;
}
er=ll_search(s,&n, cll_fl);
/*printf("l_search: lab=%s(l=%d, afl=%d, er=%d, n=%d, cll_fl=%d, cll_cur=%d)\n",s,*l, *afl,er,n, cll_fl, cll_getcur());*/
if(er==E_OK)
{
ltp=afile->la.lt+n;
*l=ltp->len;
*l=ltp->len + cll_fl;
if(ltp->fl == 1)
{
l_get(n,v,afl);/* *v=lt[n].val;*/
@ -251,12 +355,18 @@ int l_search(char *s, int *l, int *x, int *v, int *afl)
}
else
{
b_get(&b);
if(cll_fl) {
b=cll_get();
} else {
b_get(&b);
}
er=ll_def(s,x,b); /* ll_def(...,*v); */
ltp=afile->la.lt+(*x);
*l=ltp->len;
ltp->is_cll = cll_fl;
*l=ltp->len + cll_fl;
if(!er)
{
@ -303,6 +413,13 @@ void l_addocc(int n, int *v, int *afl) {
}
}
/* for the list functionality */
char *l_get_name(int n, int *is_cll) {
ltp=afile->la.lt+n;
*is_cll = ltp->is_cll;
return ltp->n;
}
int l_get(int n, int *v, int *afl)
{
if(crossref) l_addocc(n,v,afl);
@ -387,6 +504,7 @@ static int ll_def(char *s, int *n, int b) /* definiert naechstes Label
ltp->blk=b;
ltp->fl=0;
ltp->afl=0;
ltp->is_cll=0;
ltp->occlist=NULL;
hash=hashcode(s,j);
ltp->nextindex=afile->la.hashindex[hash];
@ -401,8 +519,14 @@ static int ll_def(char *s, int *n, int b) /* definiert naechstes Label
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
*/
int ll_search(char *s, int *n, int cll_fl) /* search Label in Tabelle ,nr->n */
{
int i,j=0,k,er=E_NODEF,hash;
@ -411,7 +535,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 +545,21 @@ 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) {
if (ltp->blk == cll_getcur()) {
er=E_OK;
break;
}
} 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 +584,7 @@ int ll_pdef(char *t)
{
int n;
if(ll_search(t,&n)==E_OK)
if(ll_search(t,&n, 0)==E_OK)
{
ltp=afile->la.lt+n;
if(ltp->fl)
@ -496,9 +629,22 @@ 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 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)
{
@ -509,6 +655,11 @@ int b_init(void)
return(E_OK);
}
int b_new(void)
{
return ++blk;
}
int b_depth(void)
{
return bi;
@ -519,19 +670,25 @@ 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;
bt[++bi]=b_new();
er=E_OK;
}
return(er);
}
/**
* close a block scope
*/
int b_close(void)
{
@ -542,10 +699,13 @@ int b_close(void)
} else {
return E_BLOCK;
}
cll_clear();
return(E_OK);
}
/**
* get the block number of the current innermost block
*/
static int b_get(int *n)
{
*n=bt[bi];
@ -553,6 +713,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 +725,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 +739,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;

View File

@ -21,6 +21,10 @@
#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);
@ -30,6 +34,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 +46,10 @@ 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, int *is_cll);
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, int cll_fl);
int ll_pdef(char *t);
int b_open(void);

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, 1, &afl);
if(l>254) {
errout(E_OPTLEN);

View File

@ -50,7 +50,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 +131,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,0) ? 1 : 0 );
return(0);
}

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;

View File

@ -25,6 +25,7 @@
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include "xad.h"
#include "xah.h"
@ -48,9 +49,21 @@ static void tg_dez(signed char*,int*,int*);
static void tg_hex(signed char*,int*,int*);
static void tg_oct(signed char*,int*,int*);
static void tg_bin(signed char*,int*,int*);
static int t_p2(signed char *t, int *ll, int fl, int *al);
static void do_listing(signed char *listing, int listing_len, signed char *bincode, int bincode_len);
/* assembly mnemonics and pseudo-op tokens */
/* ina and dea don't work yet */
/* Note AF 20110624: added some ca65 compatibility pseudo opcodes,
* many are still missing (and will most likely never by supported in this
* code base). Potential candidates are .hibytes, .lobytes, .asciiz,
* .addr, .charmap, .dbyt, .faraddr, .bankbytes, .segment (at least for the known ones)
* .incbin is similar to our .bin, but with parameters reversed (argh...)
* I like the .popseg/.pushseg pair;
* .global/.globalzp is equivalent to forward-defining a label in the global block
* .export/.exportzp could be implemented with a commandline switch to NOT export
* global labels, where .exported labels would still be exported in an o65 file.
*/
static char *kt[] ={
/* 1 2 3 4 5 6 7 8 9 10 */
"adc","and","asl","bbr","bbs","bcc","bcs","beq","bit","bmi",
@ -75,7 +88,9 @@ static char *kt[] ={
".byt",".word",".asc",".dsb", ".(", ".)", "*=", ".text",".data",".bss",
".zero",".fopt", ".byte", ".end", ".list", ".xlist", ".dupb", ".blkb", ".db", ".dw",
".align",".block", ".bend",".al",".as",".xl",".xs", ".bin", ".aasc"
".align",".block", ".bend",".al",".as",".xl",".xs", ".bin", ".aasc", ".code",
".include", ".import", ".importzp", ".proc", ".endproc",
".zeropage", ".org", ".reloc"
};
@ -84,8 +99,6 @@ static int lp[]= { 0,1,1,1,1,2,2,1,1,1,2,2,2,1,1,1,2,2 };
/* index into token array for pseudo-ops */
/* last valid mnemonic */
#define Lastbef 93
/* last valid token+1 */
#define Anzkey 123
#define Kbyt Lastbef+1
#define Kword Lastbef+2
@ -119,8 +132,26 @@ static int lp[]= { 0,1,1,1,1,2,2,1,1,1,2,2,2,1,1,1,2,2 };
#define Kbin Lastbef+28
#define Kaasc Lastbef+29
#define Kreloc Anzkey /* *= (relocation mode) */
#define Ksegment Anzkey+1
#define Kcode Lastbef+30 /* gets remapped to Ktext */
/* 93 + 30 -> 123 */
#define Kinclude Lastbef+31
#define Kimport Lastbef+32
#define Kimportzp Lastbef+33
#define Kproc Lastbef+34 /* mapped to Kopen */
/* 93 + 35 -> 128 */
#define Kendproc Lastbef+35 /* mapped to Kclose */
#define Kzeropage Lastbef+36 /* mapped to Kzero */
#define Korg Lastbef+37 /* mapped to Kpcdef - with parameter equivalent to "*=$abcd" */
#define Krelocx Lastbef+38 /* mapped to Kpcdef - without parameter equivalent to "*=" */
/* last valid token+1 */
#define Anzkey Lastbef+39 /* define last valid token number; last define above plus one */
#define Kreloc (Anzkey-256) /* *= (relocation mode) */
#define Ksegment (Anzkey+1-256) /* this actually now is above 127, which might be a problem as char is signed ... */
/* array used for hashing tokens (26 entries, a-z) */
@ -319,11 +350,14 @@ static int le[] ={ 1,2,2,2,2,2,2,2,3,3,3,2,3,3,3,2,
static int opt[] ={ -1,-1,-1,-1,-1,-1,-1,-1,1,2,3,-1,4,5,-1,-1,
/*new*/ -1,8,9,-1,-1,-1,-1,-1 }; /* abs -> zp */
/*********************************************************************************************/
/* pass 1 */
int t_p1(signed char *s, signed char *t, int *ll, int *al)
{
static int er,l,n,v,nk,na1,na2,bl,am,sy,i,label,byte; /*,j,v2 ;*/
int afl = 0;
int tlen; /* token listing length, to adjust length that is returned */
int inp; /* input pointer in t[] */
/* notes and typical conventions ... er = error code
am = addressing mode in use
@ -338,18 +372,68 @@ int t_p1(signed char *s, signed char *t, int *ll, int *al)
#ifdef DEBUG_AM
fprintf(stderr, "- p1 %d starting -\n", pc[segment]);
#endif
er=t_conv(s,t,&l,pc[segment],&nk,&na1,&na2,0,&byte);
/* leaving our token sequence in t */
/* As the t_p1 code below always works through the tokens
* from t_conv in such a way that it always produces a shorter
* result, the conversion below takes place "in place".
* This, however, means that the original token sequence, which
* would be useful for some assembler listing, is overwritten.
* While the original assumption was ok for a constrained
* environment like the Atari ST, this is no longer true.
* Converting the code below to have separate input and output
* areas would be error-prone, so we do some copy-magic here
* instead...*/
/* we keep three bytes buffer for "T_LISTING" and the length of the
* token list
*/
t[0]=T_LISTING;
er=t_conv(s,t+6,&l,pc[segment],&nk,&na1,&na2,0,&byte);
tlen = l+6;
t[1]=tlen&255;
t[2]=(tlen>>8)&255;
t[3]=segment;
t[4]=pc[segment]&255;
t[5]=(pc[segment]>>8)&255;
/* now duplicate the token sequence from the T_LISTING buffer
* to the end of "t", so we can then in-place convert it
* below. Non-overlapping, size is known in advance, so
* using memcpy is fine here
*/
memcpy(t+tlen, t+6, l);
t=t+tlen;
/* the result of this is that we always have a Klisting entry in the buffer
* for each tokenization call */
/* here continue as before, except for adjusting the returne *ll length
* in the end, just before return */
inp = 0;
/* discard label definitions */
while (inp<l && t[inp]==T_DEFINE) {
inp+=3;
}
if (inp) {
/* sorry, anything else would be way to risky below */
l -= inp;
if (l != 0) {
printf("t=%p, inp=%d, l=%d\n", t, inp, l);
memmove(t, t+inp, l);
}
}
/* return length default is input length */
*ll=l;
/*
#if 0
printf("t_conv (er=%d):",er);
for(i=0;i<l;i++)
printf("%02x,",t[i]);
printf("\n");
*/
#endif
/* if text/data produced, then no more fopt allowed in romable mode */
if((romable>1) && (t[0]<Kopen || t[0]==Kbyte || t[0]==Kpcdef)) {
/* TODO: need to check, Kbyte is being remapped to Kbyt. What is the effect here? */
if((romable>1) && (t[inp]<Kopen || t[inp]==Kbyte || t[inp]==Kpcdef)) {
afile->base[SEG_TEXT] = pc[SEG_TEXT] = romaddr + h_length();
romable=1;
}
@ -369,7 +453,26 @@ fprintf(stderr, "- p1 %d starting -\n", pc[segment]);
if(n==Kend || n==Klist || n==Kxlist) {
*ll = 0; /* ignore */
} else
if(n==Kinclude) {
*ll = 0; /* no output length */
i=1;
if(t[i]=='\"') {
int k,j=0;
char binfname[255];
i++;
k=t[i]+i+1;
i++;
while(i<k && !er) {
binfname[j++] = t[i++];
if (j > 255)
er = E_NOMEM; /* buffer overflow */
}
binfname[j] = '\0';
er=icl_open(binfname);
} else {
er=E_SYNTAX;
}
} else
if(n==Kfopt) {
if(romable==1) er=E_ROMOPT;
t[0] = Kbyt;
@ -658,6 +761,8 @@ printf(" wrote %02x %02x %02x %02x %02x %02x\n",
#ifdef DEBUG_AM
fprintf(stderr, "E_OK ... t_p2 xat.c\n");
#endif
/* this actually calls pass2 on the current tokenization stream,
* but without including the Klisting token listing */
er=t_p2(t,ll,(0 | byte), al);
}
@ -685,7 +790,7 @@ fprintf(stderr, "E_NODEF pass1 xat.c\n");
if(n>=0 && n<=Lastbef)
{
if(t[1]==T_END)
if(t[1]==T_END || t[1]==T_COMMENT)
{
sy=0; /* implied */
} else
@ -774,6 +879,48 @@ fprintf(stderr, "E_NODEF pass1 xat.c\n");
/* .byt, .asc, .word, .dsb, .fopt pseudo-op dispatch */
} else
if(n==Kimportzp) {
int i;
*ll=0; /* no output */
bl = 0; /* no output length */
/* import labels; next follow a comma-separated list of labels that are
imported. Tokenizer has already created label entries, we only need to
set the flags appropriately */
i=1;
/*printf("Kimport: t[i]=%d\n",t[i]);*/
while(t[i]==T_LABEL) {
int n = (t[i+1] & 255) | (t[i+2] << 8); /* label number */
/*printf("lg_import: %d\n",n);*/
lg_importzp(n);
i+=3;
while (t[i]==' ') i++;
if (t[i]!=',') break;
i++;
while (t[i]==' ') i++;
}
er=E_NOLINE;
} else
if(n==Kimport) {
int i;
*ll=0; /* no output */
bl = 0; /* no output length */
/* import labels; next follow a comma-separated list of labels that are
imported. Tokenizer has already created label entries, we only need to
set the flags appropriately */
i=1;
/*printf("Kimport: t[i]=%d\n",t[i]);*/
while(t[i]==T_LABEL) {
int n = (t[i+1] & 255) | (t[i+2] << 8); /* label number */
/*printf("lg_import: %d\n",n);*/
lg_import(n);
i+=3;
while (t[i]==' ') i++;
if (t[i]!=',') break;
i++;
while (t[i]==' ') i++;
}
er=E_NOLINE;
} else
if(n==Kbyt || n==Kasc || n==Kaasc)
{
#ifdef DEBUG_AM
@ -817,10 +964,75 @@ fprintf(stderr, "guessing instruction length is %d\n", bl);
if(segment==SEG_TEXT) pc[SEG_ABS]+=bl;
if(segment==SEG_ABS) pc[SEG_TEXT]+=bl;
/* adjust length by token listing buffer length */
*ll = *ll + tlen;
return(er);
}
/*t_pass 2*/
/*********************************************************************************************/
/* t_pass 2
*
* *t is the token list as given from pass1
* *ll is the returned length of bytes (doubles as
* input for whether OK or OKDEF status from pass1)
* fl defines if we allow zeropage optimization
*
* Conversion takes place "in place" in the *t array.
*/
/**
* function called from the main loop, where "only" the
* undefined labels have to be resolved and the affected
* opcodes are assembled, the rest is passed through from
* pass1 (pass-through is done in t_p2, when *ll<0)
*
* *t is the input token list
* *ll is the input length of the token list,
* and the output of how many bytes of the buffer are to be taken
* into the file
*/
int t_p2_l(signed char *t, int *ll, int fl, int *al)
{
int er = E_OK;
if (t[0] == T_LISTING) {
int tlen;
tlen=((t[2]&255)<<8) | (t[1]&255);
if (*ll<0) {
*ll=(*ll) + tlen;
} else {
*ll=(*ll) - tlen;
}
if (*ll != 0) {
er = t_p2(t+tlen, ll, fl, al);
}
/* do the actual listing (*ll-2 as we need to substract the place for the tlen value */
do_listing(t+3, tlen-3, t+tlen, *ll);
/* adapt back, i.e. remove token listing */
if (*ll != 0) {
memmove(t, t+tlen, abs(*ll));
}
} else {
er = t_p2(t, ll, fl, al);
}
return er;
}
/**
* This method does not handle a token list. Thus it
* is called internally from pass1 without the token listing, and
* from the t_p2_l() method that strips the token listing
* as well
*
* *t is the input token list
* *ll is the input length of the token list,
* and the output of how many bytes of the buffer are to be taken
* into the file
*
*/
int t_p2(signed char *t, int *ll, int fl, int *al)
{
static int afl,nafl, i,j,k,er,v,n,l,bl,sy,am,c,vv[3],v2,label;
@ -835,11 +1047,12 @@ int t_p2(signed char *t, int *ll, int fl, int *al)
er=E_OK;
bl=0;
if(*ll<0) /* <0 bei E_OK, >0 bei E_OKDEF */
if(*ll<0) /* <0 when E_OK, >0 when E_OKDEF */
{
*ll=-*ll;
bl=*ll;
er=E_OK;
} else
{
n=t[0];
@ -855,7 +1068,8 @@ int t_p2(signed char *t, int *ll, int fl, int *al)
v2=v;
} else {
if( (!(er=l_get(n,&v2, &afl)))
&& ((afl & A_FMASK)!=(SEG_UNDEF<<8)) )
&& ((afl & A_FMASK)!=(SEG_UNDEF<<8))
&& ((afl & A_FMASK)!=(SEG_UNDEFZP<<8)) )
{
if(t[3]=='+')
{
@ -1172,7 +1386,7 @@ fprintf(stderr, "Kdsb E_DSB %i\n", j);
}
dsb_len = 0;
} else
if(n<=Lastbef)
if(n>=0 && n<=Lastbef)
{
if((c=t[1])=='#')
{
@ -1501,10 +1715,11 @@ fprintf(stderr, "address mode: %i address: %i\n", am, vv[0]);
er=E_SYNTAX;
}
}
} else
er=E_SYNTAX;
}
#ifdef DEBUG_AM
fprintf(stderr, "-- endof P2\n");
#endif
@ -1515,6 +1730,11 @@ fprintf(stderr, "-- endof P2\n");
return(er);
}
/*********************************************************************************************/
/* helper function for the preprocessor, to compute an arithmetic value
* (e.g. for #if or #print).
* First tokenizes it, then calculates the value
*/
int b_term(char *s, int *v, int *l, int pc)
{
static signed char t[MAXLINE];
@ -1528,15 +1748,20 @@ int b_term(char *s, int *v, int *l, int pc)
return(er);
}
/* translate a string into a first-pass sequence of tokens */
/*********************************************************************************************/
/* translate a string into a first-pass sequence of tokens;
* Take the text from *s (stopping at \0 or ';'), tokenize it
* and write the result to *t, returning the length of the
* token sequence in *l
*/
static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk,
int *na1, int *na2, int af, int *bytep) /* Pass1 von s nach t */
/* tr. pass1, from s to t */
int *na1, int *na2, int af, int *bytep)
{
static int v,f;
static int operand,o;
int fl,afl;
int p,q,ud,n,ll,mk,er;
int p,q,ud,ll,mk,er;
int n; /* label number to be passed between l_def (definition) and l_set (set the value) */
int m, uz, byte;
static unsigned char cast;
@ -1586,6 +1811,7 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk,
if(s[p]=='=')
{
/*printf("Found = @%s\n",s+p);*/
t[q++]=T_OP;
t[q++]=n&255;
t[q++]=(n>>8)&255;
@ -1594,6 +1820,17 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk,
ll=n=0;
break;
} else
if(s[p]==':' && s[p+1]=='=') /* support := label assignments (ca65 compatibility) */
{
/*printf("Found := @%s\n", s+p);*/
t[q++]=T_OP;
t[q++]=n&255;
t[q++]=(n>>8)&255;
t[q++]='=';
p+=2;
ll=n=0;
break;
} else
if(f && s[p]!='\0' && s[p+1]=='=')
{
t[q++]=T_OP;
@ -1609,15 +1846,22 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk,
p++;
while(s[p]==' ') p++;
l_set(n,pc,segment); /* set as address value */
t[q++]=T_DEFINE;
t[q++]=n&255;
t[q++]=(n>>8)&255;
n=0;
} else { /* label ... syntax */
l_set(n,pc,segment); /* set as address value */
n=0;
t[q++]=T_DEFINE;
t[q++]=n&255;
t[q++]=(n>>8)&255;
n=0;
}
}
if((n & 0xff) <=Lastbef)
if(n>=0 && n<=Lastbef)
mk=1; /* 1= nur 1 Komma erlaubt *//* = only 1 comma ok */
}
@ -1674,8 +1918,10 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk,
if(operand)
{
/* are we forcing the operand into a particular
addressing mode? !, @, ` operators */
if(s[p]=='!' || s[p]=='@' || s[p]=='`')
addressing mode? !, @, ` operators
Note these are not available in ca65, but we only
switch off "@" which are used for cheap local labels*/
if(s[p]=='!' || (s[p]=='@' && !ca65) || s[p]=='`')
{
cast=s[p];
operand= -operand+1;
@ -1691,12 +1937,12 @@ static int t_conv(signed char *s, signed char *t, int *l, int pc, int *nk,
{
t[q++]=s[p++];
} else
/* maybe it's a label */
if(isalpha(s[p]) || s[p]=='_')
/* maybe it's a label
Note that for ca65 cheap local labels, we check for "@" */
if(isalpha(s[p]) || s[p]=='_' || (s[p]=='@' && ca65))
{
m=n;
er=l_search((char*)s+p,&ll,&n,&v,&afl);
/*
if(m==Kglobl || m==Kextzero) {
if(er==E_NODEF) {
@ -1912,13 +2158,17 @@ fprintf(stderr, "could not find %s\n", (char *)s+p);
}
}
/* FIXME: this is an unholy union of two "!" implementations :-( */
t[q++]='\0';
t[q++]=cast;
/* FIXME FIXME FIXME ... */
if (operand==1) {
t[q++]='\0';
t[q++]=cast;
}
*l=q;
if(bytep) *bytep=byte;
return(er);
}
/*********************************************************************************************/
static int t_keyword(signed char *s, int *l, int *n)
{
int i = 0, j = 0, hash;
@ -1961,6 +2211,12 @@ static int t_keyword(signed char *s, int *l, int *n)
if(i==Kdw) i=Kword;
if(i==Kblock) i=Kopen;
if(i==Kbend) i=Kclose;
if(i==Kcode) i=Ktext;
if(i==Kproc) i=Kopen;
if(i==Kendproc) i=Kclose;
if(i==Kzeropage) i=Kzero;
if(i==Korg) i=Kpcdef;
if(i==Krelocx) i=Kpcdef;
*l=j;
@ -2095,3 +2351,291 @@ fprintf(stderr, "tg_asc token = %i\n", n);
return(er);
}
/*********************************************************************************************/
/* this is the listing code
*
* Unfortunately this code has to go here (for now), as this file is the only one
* where we have access to the tables that allow to convert the tokens back to
* a listing
*/
static FILE *listfp = NULL;
static int list_string(char *buf, char *string);
static int list_tokens(char *buf, signed char *input, int len);
static int list_value(char *buf, int val);
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_byte(char *buf, int outbyte);
static int list_nibble(char *buf, int outnib);
void list_setfile(FILE *fp) {
listfp = fp;
}
/**
* 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);
signed char c = '?';
/* 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;
/* preamble <segment>':'<address>' ' */
switch(lst_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, lst_pc);
buf = buf + list_sp(buf);
/* binary output (up to 8 byte. If more than 8 byte, print 7 plus "..." */
n_hexb = bincode_len;
if (n_hexb >= 8) {
n_hexb = 7;
}
for (i = 0; i < n_hexb; i++) {
buf = buf + list_byte(buf, bincode[i]);
buf = buf + list_sp(buf);
}
if ((n_hexb == 7) && (bincode_len > 7)) {
buf = buf + list_nchar(buf, '.', 3);
} else {
/* can move loop into nchar ... */
for (; i < 8; i++) {
buf = buf + list_nchar(buf, ' ', 3);
}
}
buf = buf + list_sp(buf);
buf += list_tokens(buf, listing + 3, listing_len - 3);
/* for now only do a hex dump so we see what actually happens */
i = buf - outline;
if (i<80) buf += list_nchar(buf, ' ', 80-i);
buf += list_string(buf, " >>");
for (i = 3; i < listing_len; i++) {
buf = buf + list_byte(buf, listing[i]);
buf = buf + list_sp(buf);
}
buf[0] = 0;
fprintf(listfp, "%s\n", outline);
}
int list_tokens(char *buf, signed char *input, int len) {
int outp = 0;
int inp = 0;
int tmp;
char *name;
signed char c;
int is_cll;
int tabval;
if (inp >= len) return 0;
tmp = input[inp] & 255;
tabval = 0;
if (tmp == (T_DEFINE & 255)) {
while (tmp == (T_DEFINE & 255)) {
tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255);
name=l_get_name(tmp, &is_cll);
if (is_cll) outp += list_char(buf+outp, '@');
tmp = list_string(buf+outp, name);
tabval += tmp + 1 + is_cll;
outp += tmp;
outp += list_char(buf+outp, ' ');
inp += 3;
tmp = input[inp] & 255;
}
if (tabval < 10) {
outp += list_nchar(buf+outp, ' ', 10-tabval);
}
} else {
if (tmp >= 0 && tmp < Anzkey) {
outp += list_string(buf+outp, " ");
}
}
if (tmp >= 0 && tmp < Anzkey) {
/* assembler keyword */
/*printf("tmp=%d, kt[tmp]=%p\n", tmp, kt[tmp]);*/
if (kt[tmp] != NULL) {
outp += list_string(buf+outp, kt[tmp]);
}
outp += list_sp(buf + outp);
inp += 1;
}
while (inp < len) {
switch(input[inp]) {
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);
outp += list_value(buf+outp, tmp);
inp += 4;
break;
case T_LABEL:
/*outp += list_char(buf+outp, 'L');*/
/* 16 bit label number */
tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255);
name=l_get_name(tmp, &is_cll);
if (is_cll) outp += list_char(buf+outp, '@');
outp += list_string(buf+outp, name);
inp += 3;
break;
case T_OP:
/* arithmetic operation; inp[3] is operation like '=' or '+' */
tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255);
name=l_get_name(tmp, &is_cll);
if (is_cll) outp += list_char(buf+outp, '@');
outp += list_string(buf+outp, name);
outp += list_char(buf+outp, input[inp+3]);
inp += 4;
break;
case T_END:
/* end of operation */
/*outp += list_string(buf+outp, ";");*/
inp += 1;
goto end;
break;
case T_LINE:
/* newline marker - ignored? */
outp += list_string(buf+outp, "\\n ");
/* line number */
tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255);
outp += list_word(buf+outp, tmp);
inp += 3;
break;
case T_FILE:
/* new file marker - ignored? */
outp += list_string(buf+outp, "\\f ");
/* line number */
tmp = ((input[inp+2]&255)<<8) | (input[inp+1]&255);
outp += list_word(buf+outp, tmp);
/* file name */
tmp = list_string(buf+outp, (char*)input+inp+3);
outp += tmp;
inp += tmp + 3;
break;
case T_POINTER:
/* what is this? It's actually resolved during token conversion */
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 += 4;
break;
default:
c = input[inp];
if (c > 31) {
outp += list_char(buf+outp, input[inp]);
} else {
outp += list_char(buf+outp, '\'');
outp += list_byte(buf+outp, input[inp]);
}
inp += 1;
break;
}
}
end:
return outp;
}
int list_string(char *buf, char *string) {
int p = 0;
while (string[p] != 0) {
buf[p] = string[p];
p++;
}
return p;
}
int list_value(char *buf, int val) {
int p = 0;
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);
}
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) {
buf = buf + list_byte(buf, outword >> 8);
list_byte(buf, outword);
return 4;
}
int list_byte(char *buf, int outbyte) {
buf = buf + list_nibble(buf, (outbyte >> 4));
list_nibble(buf, outbyte);
return 2;
}
int list_nibble(char *buf, int outnib) {
outnib = outnib & 0xf;
if (outnib < 10) {
buf[0]='0'+outnib;
} else {
buf[0]='a'-10+outnib;
}
return 1;
}

View File

@ -21,8 +21,9 @@
extern int dsb_len;
void list_setfile(FILE *fp);
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 fl, int *al);
int b_term(char *s, int *v, int *l, int pc);
#endif /* __XA65_XAT_H__ */