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

official xa-2.4.0

This commit is contained in:
Andre Fachat 2023-11-19 21:24:38 +01:00
parent 0cfdf82384
commit e95549dfd1
185 changed files with 5779 additions and 1122 deletions

View File

@ -397,3 +397,44 @@ xa-2.3.14
-- Cameron Kaiser <ckaiser@floodgap.com> 7 February 2023 -- Cameron Kaiser <ckaiser@floodgap.com> 7 February 2023
xa-2.4.0
* Listing feature in plain text or HTML, along with .listbytes to control
how hex bytes get listed in the output.
* 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; also adds C option for
0x and 0 to specify hex or octal. As a result, -M is now deprecated,
and colons in comments may become the default in a future version.
* Implement CA65 "cheap local labels", ":=" label definitions,
and various pseudo-opcodes (.include, .import, .importzp,
.zeropage, .proc (anonymous only), .endproc, .code, .org, .reloc).
* -U option to allow all undefined labels in relocation mode; this
allows exporting them to an o65 file and link at a later time (or
specify one at a time with -L).
* Globals may also be specified manually with -g.
* #error allows preprocessor-level assertions.
* .assert allows assembler-level assertions.
* Better fix for segfault with smaller arity macro issue.
* Main Makefile fixes.
* Fixed parallel make in tests, incorporating a patch from Sergei
Trofimovich.
* Added a test case that failed in 2.3.14 from Tom Hargreaves.
* Some 2.3.x features still allowed with -XXA23, which is obviously
deprecated.
* The quote escape character is now the \ (backslash), except if -XXA23.
* Recursive /* */ comments are no longer allowed, except if -XXA23.
* XA_MAJOR and XA_MINOR predefined macros, except if -XXA23.
* Testsuite greatly expanded.
* The old loader/ testsuite and doc/ archive are now in attic/, which is
the repository for old unsupported components. It may be purged in a
future version.
* -M is now deprecated (use -XMASM), just in case you forgot.
* printcbm(1) is now deprecated (use VICE petcat, it does a lot more).
* Previously deprecated options (16-bit mvn/mvp argument, -S, -x) finally
removed. If you need this support, you must use 2.3.x.
-- André Fachat <afachat@gmx.de> and
-- Cameron Kaiser <ckaiser@floodgap.com>, 18 November, 2023

View File

@ -1,5 +1,6 @@
# Unix gcc or DOS go32 cross-compiling gcc # Unix gcc or DOS go32 cross-compiling gcc
# #
VERS = 2.4.0
CC = gcc CC = gcc
LD = gcc LD = gcc
# for testing. not to be used; build failures in misc/. # for testing. not to be used; build failures in misc/.
@ -37,8 +38,8 @@ killxa:
xa: xa:
(cd src && LD=${LD} CC="${CC} ${CFLAGS}" ${MAKE}) (cd src && LD=${LD} CC="${CC} ${CFLAGS}" ${MAKE})
load: #load:
(cd loader && CC="${CC} ${CFLAGS}" ${MAKE}) # (cd loader && CC="${CC} ${CFLAGS}" ${MAKE})
uncpk: uncpk:
(cd misc && CC="${CC} ${CFLAGS}" ${MAKE}) (cd misc && CC="${CC} ${CFLAGS}" ${MAKE})
@ -54,11 +55,11 @@ mingw: clean
clean: clean:
(cd src && ${MAKE} clean) (cd src && ${MAKE} clean)
(cd loader && ${MAKE} clean) #(cd loader && ${MAKE} clean)
(cd misc && ${MAKE} mrproper) (cd misc && ${MAKE} mrproper)
rm -f xa *.exe *.o65 *.s core rm -f xa *.exe *.o65 *.s core
install: xa uncpk install: all
$(MKDIR) $(BINDIR) $(MKDIR) $(BINDIR)
$(MKDIR) $(MANDIR) $(MKDIR) $(MANDIR)
$(INSTALL) xa reloc65 ldo65 file65 printcbm uncpk $(BINDIR) $(INSTALL) xa reloc65 ldo65 file65 printcbm uncpk $(BINDIR)
@ -66,9 +67,14 @@ install: xa uncpk
#$(MKDIR) $(DOCDIR)/xa65 #$(MKDIR) $(DOCDIR)/xa65
dist: clean dist: clean
cd .. ; tar cvf xa-2.3.14.tar xa-2.3.14 ; gzip xa-2.3.14.tar cd .. ; tar cvf xa-$(VERS).tar xa-$(VERS) ; gzip xa-$(VERS).tar
test: xa uncpk # no prereqs to force parallel make to play nice
test:
rm -rf xa
$(MAKE) xa
$(MAKE) uncpk
cd tests && ./harness \ cd tests && ./harness \
-tests="$(TESTS)" \ -tests="$(TESTS)" \
-make="$(MAKE)" -cc="$(CC)" -cflags="$(CFLAGS)" -cc="$(CC)" -cflags="$(CFLAGS)" \
-make="$(MAKE)" -makeflags="$(MAKEFLAGS)"

View File

@ -3,10 +3,20 @@ derivatives). xa is a small, fast, portable two-pass assembler that compiles
under most ANSI C compilers. It is distributed under the GNU Public License under most ANSI C compilers. It is distributed under the GNU Public License
(see COPYING). (see COPYING).
The current version is 2.3.10, a bug fix to the long-lived 2.3.0, itself with The current version is 2.4.0, the first new feature release literally in
compatibility improvements and new man-based documentation. It also completed years. It builds upon the improvements in 2.3.x and its unified 6502/65816
the merge of the 65816 and 6502/R65C02 versions and thus the current xa can assembler core by adding listing capability, greater flexibility with
generate code for all targets now. relocatable objects, and better cross-compatibility with other popular
cross-assemblers (notably ca65) because once you use xa, you'll want to keep
on using it. :)
Certain long-deprecated options and non-standard syntaxes have also been
removed in this release, so it is possible some very old code may not
assemble without errors. These changes have been a long time coming and we
gave lots of warnings, so if you require these features and cannot change
your code to work without them, you must use xa 2.3.14. Fortunately, most
code should continue to work just fine and the test suite is even bigger to
catch these sorts of regressions.
To install on a generic Unixy thing, you should be able to just type To install on a generic Unixy thing, you should be able to just type
@ -17,9 +27,8 @@ To install on a generic Unixy thing, you should be able to just type
This will create xa along with its various support utilities. Try assembling This will create xa along with its various support utilities. Try assembling
the cpk depacker in examples/ as a test. xa also comes with uncpk (a program the cpk depacker in examples/ as a test. xa also comes with uncpk (a program
for generating cpk archives) and printcbm (a program for listing Commodore for generating cpk archives) and printcbm (a program for listing Commodore
BASIC test) and file65, ldo65 and reloc65 for displaying, linking and BASIC test, now deprecated as of 2.4) and file65, ldo65 and reloc65 for
relocating o65 files in Andre's relocatable format (see doc/fileformats.txt). displaying, linking and relocating o65 files in Andre's relocatable format.
The loader/ directory also has goodies for managing relocatable binaries.
Don't forget the man pages in man/. Install these into your MANPATH at your Don't forget the man pages in man/. Install these into your MANPATH at your
leisure, or read them with nroff -man (and/or groff -man). leisure, or read them with nroff -man (and/or groff -man).
@ -38,6 +47,8 @@ Fabian Nunez. For mingw, use
make mingw make mingw
(but do it from within MSYS2).
Similarly, Amiga and Atari ST compilation should still also function with Similarly, Amiga and Atari ST compilation should still also function with
their particular compatible packages. their particular compatible packages.

16
xa/TODO
View File

@ -1,10 +1,18 @@
o nm65 that prints labels from o65 files o nm65 that prints labels from o65 files
o `-L' option for ldo65, such that globals can be suppressed,
but KERNEL can be kept
o inc a -> ina, dec a -> dea (right now uses bare inc and dec) o inc a -> ina, dec a -> dea (right now uses bare inc and dec)
o VICE label file support o VICE label file support
o Smarter -X that can cope with non-block-aligned segment sizes o Smarter -X that can cope with non-block-aligned segment sizes (in reloc65)
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 pre-processor handling, so pp constants are
resolved at parse time. Thus they appear as their value
in the listing.
- One situation is ".listbytes unlimited",
which will show as ".listbytes 0" in the listing

6
xa/attic/README Normal file
View File

@ -0,0 +1,6 @@
These are files that have been superseded and may be removed in the future.
loader/ Rewritten as tests/loader/
doc/ Replaced by man/
(for o65, see http://www.6502.org/users/andre/o65/ )

View File

@ -0,0 +1,19 @@
all: loader example test2 rom65
clean:
rm -f loader test2 example a.o65 rom65
loader: loader.a65 file.def
../../xa loader.a65 -o loader
example: test.a
../../xa -R test.a -o example
test2: test2.a
../../xa test2.a -o test2
rom65: test.a
# ugly!
# don't run if this system doesn't have bash
test -f /bin/bash || exit 0 && ( cd .. && ../mkrom.sh -O "-G" -S "-bd 1234" -R loader/rom65 loader/test.a loader/test.a ) && ( ../hextool -cmp=rom65.ok < rom65 )

BIN
xa/attic/loader/rom65.ok Normal file

Binary file not shown.

View File

@ -1,3 +1,3 @@
Also look at ../doc/ for previous documentation files and the Change log. Also look at ../attic/doc/ for previous documentation files.
Cameron Kaiser Cameron Kaiser

View File

@ -1,4 +1,4 @@
.TH FILE65 "1" "11 April 2006" .TH FILE65 "1" "18 November 2023"
.SH NAME .SH NAME
file65 \- print information for o65 object files file65 \- print information for o65 object files
@ -13,9 +13,12 @@ prints file information for files in the o65 object format.
.SH OPTIONS .SH OPTIONS
.TP .TP
.B \-V .B \-v
Print undefined and global labels. Print undefined and global labels.
.TP .TP
.B \-vv
Print undefined and global labels, and relocation tables.
.TP
.B \-P .B \-P
Print the segment end addresses (suitable for the Print the segment end addresses (suitable for the
.BR xa (1) .BR xa (1)

View File

@ -1,4 +1,4 @@
.TH LDO65 "1" "11 April 2006" .TH LDO65 "1" "18 November 2023"
.SH NAME .SH NAME
ldo65 \- linker for o65 object files ldo65 \- linker for o65 object files
@ -9,7 +9,7 @@ ldo65 \- linker for o65 object files
.SH DESCRIPTION .SH DESCRIPTION
.B ldo65 .B ldo65
is a linker for files in the `o65' object format, formerly is a linker for files in the o65 object format, formerly
.B ld65 .B ld65
but renamed to avoid conflicts with the but renamed to avoid conflicts with the
.B cc65 .B cc65
@ -32,9 +32,23 @@ man page for an explanation.
Set output filename. The default is Set output filename. The default is
.BR a.o65 \&. .BR a.o65 \&.
.TP .TP
.B \-L name
Allow label
.B name
to remain undefined, even after linking.
This option may be specified multiple times for multiple labels.
.TP
.B \-U
Allow any label to remain undefined, even after linking.
.TP
.B \-G .B \-G
Suppress writing of globals. Suppress writing of globals.
.TP .TP
.B \-g name
Only export global
.BR name .
This option may be specified multiple times for multiple globals.
.TP
.B \-\-help .B \-\-help
Show summary of options. Show summary of options.
.TP .TP

View File

@ -1,7 +1,17 @@
.TH PRINTCBM "1" "11 April 2006" .TH PRINTCBM "1" "DEPRECATED"
.SH NAME .SH NAME
printcbm \- list a Commodore BASIC file printcbm \- list a Commodore BASIC file (DEPRECATED)
.SH NOTICE
As of
.B xa
2.4,
.B printcbm
is deprecated and will be removed in a future version. Please consider
migrating your usage to VICE
.BR petcat(1) ,
which has many more options.
.SH SYNOPSIS .SH SYNOPSIS
.B printcbm .B printcbm

View File

@ -1,4 +1,4 @@
.TH RELOC65 "1" "11 April 2006" .TH RELOC65 "1" "18 November 2023"
.SH NAME .SH NAME
reloc65 \- relocator for o65 object files reloc65 \- relocator for o65 object files
@ -19,6 +19,9 @@ object format.
Set output filename. The default is Set output filename. The default is
.BR a.o65 \&. .BR a.o65 \&.
.TP .TP
.B \-v
Verbose output.
.TP
.B \-b? addr .B \-b? addr
Relocate segment Relocate segment
.B ? .B ?
@ -40,8 +43,9 @@ respectively. Not valid for bss or zero.
.B \-X .B \-X
Extract text and data segment together Extract text and data segment together
from the file instead of writing back the whole from the file instead of writing back the whole
file. Relocating data segment to the end of the text segment file. Relocating data segment to the end of the text segment and
(ignoring the \-xd option) before extracting. bss segment to the end of the data segment
(\-xd and \-xb options override the derived address) before extracting.
.TP .TP
.B \-\-help .B \-\-help
Show summary of options. Show summary of options.

View File

@ -1,4 +1,4 @@
.TH UNCPK "1" "11 April 2006" .TH UNCPK "1" "18 November 2023"
.SH NAME .SH NAME
uncpk \- manage c64 cpk archives uncpk \- manage c64 cpk archives

View File

@ -1,4 +1,4 @@
.TH XA "1" "24 November 2021" .TH XA "1" "18 November 2023"
.SH NAME .SH NAME
xa \- 6502/R65C02/65816 cross-assembler xa \- 6502/R65C02/65816 cross-assembler
@ -18,6 +18,9 @@ further in this manual page.
.SH OPTIONS .SH OPTIONS
.TP .TP
.B \-E
Do not stop after 20 errors, but show all errors.
.TP
.B \-v .B \-v
Verbose output. Verbose output.
.TP .TP
@ -45,11 +48,22 @@ use the special filename
.BR \- .BR \-
to output to standard output. to output to standard output.
.TP .TP
.B \-P filename
Set listing filename. The default is none; use the special filename
.BR \-
to print the listing to standard output.
.TP
.B \-F format
Set listing format; default is
.BR plain .
The only other currently supported format is
.BR html .
.TP
.B \-e filename .B \-e filename
Set errorlog filename, default is none. Set errorlog filename; default is none.
.TP .TP
.B \-l filename .B \-l filename
Set labellist filename, default is none. This is the symbol table and can Set labellist filename; default is none. This is the symbol table and can
be used by disassemblers such as be used by disassemblers such as
.BR dxa (1) .BR dxa (1)
to reconstruct source. to reconstruct source.
@ -58,12 +72,70 @@ to reconstruct source.
Add cross-reference list to labellist (requires Add cross-reference list to labellist (requires
.BR \-l ). .BR \-l ).
.TP .TP
.B \-Xcompatset
Enables compatibility settings to become more (not fully!) compatible with other 6502 assemblers and codebases.
Currently supported are compatibility sets
.BR MASM ,
.BR CA65
and
.BR C ,
with
.B XA23
available as a deprecated option for codebases relying on compatibility with
the previous version of
.BR xa .
Multiple compatibility sets may be specified and combined, e.g.,
.B \-XMASM
.BR \-XXA23 .
.IP
.B \-XMASM
allows colons to appear in comments for MASM compatibility.
This does not affect colon interpretation elsewhere and may become the default in a future version.
.IP
.B \-XCA65
adds syntactic features more compatible with
.BR ca65 (1).
It permits
.B :=
for defining labels (instead of plain
.BR = ),
and adds support for unnamed labels and "cheap" local labels using the
.B @
character, but disables its other meaning for 24-bit mode (see
.B ASSEMBLER
.BR SYNTAX ).
.IP
.B \-XC
enables the usage of
.B 0xHEX
and
.B 0OCTAL
C-style number encodings.
.IP
.B \-XXA23
restores partial compatibility with
.B xa
2.3.x. In particular, it uses
.B ^
for quote escapes instead of 2.4's
.BR \e ,
allows nested multi-line comments, and disables all predefined
.B xa
preprocessor macros. This option is inherently deprecated and may be removed
in the next 2.x or 3.x release.
.TP
.B \-M .B \-M
Allow colons to appear in comments; for MASM compatibility. This does This option is deprecated and will be removed in a future version; use
not affect colon interpretation elsewhere. .B \-XMASM
instead. Allows colons to appear in comments for MASM compatibility. This does
not affect colon interpretation elsewhere, and may become the default in a
future version.
.TP .TP
.B \-R .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 .TP
.B \-Llabel .B \-Llabel
Defines Defines
@ -121,27 +193,12 @@ Characters may need to be quoted for your shell (example:
). ).
.TP .TP
.B \-\-help .B \-\-help
Show summary of options. Show summary of options
.RB ( -?
is a synonym).
.TP .TP
.B \-\-version .B \-\-version
Show version of program. Show version of program.
.LP
The following options are
.BR deprecated
and will be removed in 2.4 and later versions:
.TP
.B \-x
Use old filename behaviour (overrides
.BR \-o ,
.B \-e
and
.BR \-l ).
.TP
.B \-S
Allow preprocessor substitution within strings (this is now disallowed
for better
.BR cpp (1)
compatibility).
.SH ASSEMBLER SYNTAX .SH ASSEMBLER SYNTAX
@ -177,9 +234,15 @@ decimal value
.TP .TP
.B $234 .B $234
hexadecimal value hexadecimal value
.RB ( 0x234
accepted with
.BR -XC )
.TP .TP
.B &123 .B &123
octal octal
.RB ( 0123
accepted with
.BR -XC )
.TP .TP
.B %010110 .B %010110
binary binary
@ -221,7 +284,14 @@ statements such as
.IP .IP
.B * = $c000 .B * = $c000
.LP .LP
which sets the program counter to decimal location 49152. With the exception which sets the program counter to decimal location 49152. If
.B \-XCA65
is specified, you can also use
.B :=
as well as
.BR = .
.LP
With the exception
of the program counter, labels cannot be assigned multiple times. To explicitly of the program counter, labels cannot be assigned multiple times. To explicitly
declare redefinition of a label, place a - (dash) before it, e.g., declare redefinition of a label, place a - (dash) before it, e.g.,
.IP .IP
@ -251,6 +321,52 @@ as a linker; see
and and
.BR LINKING . .BR LINKING .
.LP .LP
If
.B \-XCA65
is specified, "cheap" local labels may be used, marked by the
.B @
prefix. Additionally, unnamed labels may be specified with
.B :
(i.e., no label, just a colon); branches may then reference these unnamed
labels with a colon and plus signs for forward branching or minus signs
for backward branching. For example (from the
.B ca65
documentation),
.LP
: lda (ptr1),y ; #1
.BR
cmp (ptr2),y
.BR
bne :+ ; -> #2
.BR
tax
.BR
beq :+++ ; -> #4
.BR
iny
.BR
bne :- ; -> #1
.BR
inc ptr1+1
.BR
inc ptr2+1
.BR
bne :- ; -> #1
.BR
.BR
: bcs :+ ; #2 -> #3
.BR
ldx #$FF
.BR
rts
.BR
.BR
: ldx #$01 ; #3
.BR
: rts ; #4
.LP
For those instructions where the accumulator is the implied argument (such as For those instructions where the accumulator is the implied argument (such as
.B asl .B asl
and and
@ -308,10 +424,14 @@ less than or equal to (7)
less than (7) less than (7)
.TP .TP
.B = .B =
equal to (6) equal to (6);
.B ==
also accepted
.TP .TP
.B <> >< .B <> ><
does not equal (6) does not equal (6);
.B !=
also accepted
.TP .TP
.B & .B &
bitwise AND (5) bitwise AND (5)
@ -360,11 +480,10 @@ or zero page value, do not attempt to optimize to a zero page argument
for those opcodes that support it (i.e., keep as 16 bit word) for those opcodes that support it (i.e., keep as 16 bit word)
.TP .TP
.B @ .B @
render as 24-bit quantity for 65816 (must specify render as 24-bit quantity for 65816, even if smaller than 24 bits (must specify
.B \-w .B \-w
command-line option). command-line option, must not specify
.B This is required to specify any .BR \-XCA65 )
.B 24-bit quantity!
.TP .TP
.B ` .B `
force further optimization, even if the length of the instruction cannot force further optimization, even if the length of the instruction cannot
@ -422,8 +541,9 @@ comments, such that
.B ; a comment:lda #0 .B ; a comment:lda #0
.LP .LP
is understood as a comment followed by an opcode. To defeat this, use the is understood as a comment followed by an opcode. To defeat this, use the
.B \-M .B \-XMASM
command line option to allow colons within comments. This does not apply to compatibility mode to allow colons within comments; this may become the
default in a future version. Colon statement separation does not apply to
.B /* */ .B /* */
and and
.B // .B //
@ -464,7 +584,7 @@ and
are synonymous, so you can mix things such as are synonymous, so you can mix things such as
.B .byt $43, 22, """a character string""" .B .byt $43, 22, """a character string"""
and get the expected result. The string is subject to the current character 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 .TP
.B .aasc """text1""","text2",... .B .aasc """text1""","text2",...
Specifies a character string that is Specifies a character string that is
@ -487,7 +607,8 @@ repetitions of
will be inserted into the assembled object. For example, will be inserted into the assembled object. For example,
.B .dsb 5,$10 .B .dsb 5,$10
will insert five bytes, each being 16 decimal, into the object. The arguments will insert five bytes, each being 16 decimal, into the object. The arguments
may be expressions. See may be expressions. If only a single argument is provided, then the argument
is treated as a number of null bytes to insert. See
.B LINKING .B LINKING
for how to use this pseudo-op to link multiple objects. for how to use this pseudo-op to link multiple objects.
.TP .TP
@ -496,8 +617,10 @@ Inlines a binary file without further interpretation specified by
.B filename .B filename
from offset from offset
.B offset .B offset
to length (relative to the beginning of the file)
.BR length . for
.B length
bytes.
This allows you to insert data such as a previously assembled object file This allows you to insert data such as a previously assembled object file
or an image or other binary data structure, inlined directly into this or an image or other binary data structure, inlined directly into this
file's object. If file's object. If
@ -518,10 +641,23 @@ a block, precede the label with
or precede it with or precede it with
.B & .B &
to declare it within the previous level only (or globally if you are only 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.
.IP
.B \.block
is accepted as a synonym for
.BR \&.( ,
as well as
.B \.proc
(but you cannot specify an explicit scope name as in
.BR ca65 ;
only anonymous blocks are supported).
.TP .TP
.B \&.) .B \&.)
Closes a block. Closes a block.
.B .bend
or
.B .endproc
are accepted as synonyms.
.TP .TP
.B \.as \.al \.xs \.xl .B \.as \.al \.xs \.xl
Only relevant in 65816 mode (with the Only relevant in 65816 mode (with the
@ -548,31 +684,98 @@ and
generate errors if generate errors if
.B \-w .B \-w
is not specified. is not specified.
.TP
.B \.assert expression,"message"
Evaluates
.B expression
and if it is false (i.e., evaluates to zero), prints
.B message
as a fatal error, terminating assembly immediately.
For example, a block of assembly code
that creates high ROM might have
.IP
\&.assert *<$fffa, "hit vectors"
.IP
to ensure that assembled code does not leak into the 6502 high vectors. If
the preceding code is too long, the assertion will be false, and the
condition will be detected in a controlled fashion. Any operation may be
used as part of the expression, including logical comparisons such as
.BR = ,
.BR == ,
.BR < ,
.BR <= ,
.BR > ,
.BR >= ,
.B !=
and
.BR <> .
.TP
.B \.include "filename"
Includes another file in place of the pseudo-op, as if the preprocessor had
done so with an
.B #include
directive (see
.BR PREPROCESSOR ),
but at the assembler
phase after preprocessing has already occurred.
.LP .LP
The following pseudo-ops apply primarily to relocatable .o65 objects. The following pseudo-op applies to listing mode.
.TP
.B \.listbytes number
In the listing output, sets the maximum number of hex bytes to be printed
in the listing for pseudo-ops like
.BR .byt ,
by default 8. The special argument
.B unlimited
sets no upper limit. If listing mode is disabled, this pseudo-op has no
observable effect.
.LP
The following pseudo-ops apply primarily to relocatable
.B .o65
objects.
A full discussion of the relocatable format is beyond the A full discussion of the relocatable format is beyond the
scope of this manpage, as it is currently a format in flux. Documentation scope of this manpage; see
on the proposed v1.2 format is in .B http://www.6502.org/users/andre/o65/
.B doc/fileformat.txt for the most current specification.
within the
.B xa
installation directory.
.TP .TP
.B .text .data .bss .zero .B .text .data .bss .zero
These pseudo-ops switch between the different segments, .text being the actual These pseudo-ops switch between the different segments,
code section, .data being the data segment, .bss being uninitialized label .B .text
space for allocation and .zero being uninitialized zero page space for being the actual code section,
allocation. In .bss and .zero, only labels are evaluated. These pseudo-ops .B .data
are valid in relative and absolute modes. being the data segment,
.B .bss
being uninitialized label space for allocation and
.B .zero
being uninitialized zero page space for allocation. In
.B .bss
and
.BR .zero ,
only labels are evaluated. These pseudo-ops
are valid in relocating and absolute modes.
.TP
.B .code
For
.B ca65
compatibility, this is currently mapped to
.BR .text .
.TP
.B .zeropage
For
.B ca65
compatibility, this is currently mapped to
.BR .zero .
.TP .TP
.B .align value .B .align value
Aligns the current segment to a byte boundary (2, 4 or 256) as specified by Aligns the current segment to a byte boundary (2, 4 or 256) as specified by
.B .B
value value
(and places it in the header when relative mode is enabled). Other values (and places it in the header when relocating mode is enabled). Other values
generate an error. generate an error.
.TP .TP
.B .fopt type,value1,value2,value3,... .B .fopt type, value1, value2, value3, ...
Acts like Acts like
.B .byt/.asc .B .byt/.asc
except that the values are embedded into the object file as file options. except that the values are embedded into the object file as file options.
@ -582,6 +785,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 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, are interpreted as values to insert. Any number of values may be specified,
and may also be strings. 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, like the
.B -L
command line parameter.
.TP
.B .importzp label1, label2, label3, ...
Analogous to
.BR .import ,
except that it only imports zeropage labels (i.e., byte values).
.SH PREPROCESSOR .SH PREPROCESSOR
@ -665,8 +879,19 @@ may interpret too early until the file actually gets to
.B xa .B xa
itself for processing. itself for processing.
.LP .LP
The following preprocessor directives are supported. The following predefined macros are supported, except if
.B \-XXA23
is specified:
.TP
.B XA_MAJOR
The current major version of
.BR xa .
.TP
.B XA_MINOR
The current minor version of
.BR xa .
.LP
The following preprocessor directives are supported:
.TP .TP
.B #include """filename""" .B #include """filename"""
Inserts the contents of file Inserts the contents of file
@ -691,6 +916,9 @@ Computes the value of expression
.B expression .B expression
and prints it into the errorlog file. and prints it into the errorlog file.
.TP .TP
.B #error message
Displays the message as an error and terminates assembly.
.TP
.B #define DEFINE text .B #define DEFINE text
Equates macro Equates macro
.B DEFINE .B DEFINE
@ -724,12 +952,6 @@ satisfied, then the source code between the directive and its terminating
.B #endif .B #endif
are expunged and not assembled. Up to fifteen levels of nesting are supported. are expunged and not assembled. Up to fifteen levels of nesting are supported.
.TP .TP
.B #endif
Closes a conditional block.
.TP
.B #else
Implements alternate path for a conditional block.
.TP
.B #ifdef DEFINE .B #ifdef DEFINE
True only if macro True only if macro
.B DEFINE .B DEFINE
@ -760,6 +982,12 @@ is defined
.I and .I and
assigned with a value. assigned with a value.
.I This works on labels, not macros! .I This works on labels, not macros!
.TP
.B #else
Implements alternate path for a conditional block.
.TP
.B #endif
Closes a conditional block.
.LP .LP
Unclosed conditional blocks at the end of included files generate warnings; Unclosed conditional blocks at the end of included files generate warnings;
unclosed conditional blocks at the end of assembly generate an error. unclosed conditional blocks at the end of assembly generate an error.
@ -920,8 +1148,8 @@ and
use two eight bit parameters, the only instructions in the entire use two eight bit parameters, the only instructions in the entire
instruction set to do so. Older versions of instruction set to do so. Older versions of
.B xa .B xa
took a single 16-bit absolute value. Since 2.3.7, the standard syntax is took a single 16-bit absolute value. As of 2.4.0, this old syntax is
now accepted and the old syntax is deprecated (a warning will be generated). no longer accepted.
.LP .LP
Forward-defined labels -- that is, labels that are defined after the current Forward-defined labels -- that is, labels that are defined after the current
instruction is processed -- cannot be optimized into zero instruction is processed -- cannot be optimized into zero
@ -943,31 +1171,6 @@ Indiscriminately forcing the issue can be fraught with peril, however, and
is not recommended; to discourage this, the assembler will complain about its is not recommended; to discourage this, the assembler will complain about its
use in addressing mode situations where no ambiguity exists, such as indirect use in addressing mode situations where no ambiguity exists, such as indirect
indexed, branching and so on. indexed, branching and so on.
.LP
Also, as a further consequence of the way optimization is managed, we repeat
that
.B all
24-bit quantities and labels that reference a 24-bit quantity in 65816 mode,
anteriorly declared or otherwise,
.B MUST
be prepended with the
.B @
prefix. Otherwise, the assembler will attempt to optimize to 16 bits, which
may be undesirable.
.SH "IMMINENT DEPRECATION"
The following options and modes will be
.B REMOVED
in 2.4 and later versions of
.BR xa :
.LP
.B \-x
.LP
.B \-S
.LP
the original
.B mvn $xxxx
syntax
.SH "SEE ALSO" .SH "SEE ALSO"
.BR file65 (1), .BR file65 (1),
@ -985,7 +1188,7 @@ Original xa package (C)1989-1997 Andre Fachat. Additional changes
(C)1989-2023 Andre Fachat, Jolse Maginnis, David Weinehall, (C)1989-2023 Andre Fachat, Jolse Maginnis, David Weinehall,
Cameron Kaiser. The official maintainer is Cameron Kaiser. Cameron Kaiser. The official maintainer is Cameron Kaiser.
.SH 30 YEARS OF XA .SH OVER 30 YEARS OF XA
Yay us? Yay us?
.SH WEBSITE .SH WEBSITE

View File

@ -2,7 +2,7 @@
XCBMLIB = .. XCBMLIB = ..
# -Wall -ansi et al. cause compile problems. # -Wall -ansi et al. cause compile problems.
CFLAGS = -O2 CFLAGS = -O2 -g
LIBS = #-lncurses -ltermcap -lm LIBS = #-lncurses -ltermcap -lm

View File

@ -48,6 +48,8 @@ int rompar = 0;
int romoff = 0; int romoff = 0;
int labels = 0; int labels = 0;
int verbose = 0;
void usage(FILE *fp) void usage(FILE *fp)
{ {
fprintf(fp, fprintf(fp,
@ -62,13 +64,14 @@ void usage(FILE *fp)
" in the same ROM. Add offset to start address.\n" " in the same ROM. Add offset to start address.\n"
" -A offset same as `-a', but only print the start address of the next\n" " -A offset same as `-a', but only print the start address of the next\n"
" file in the ROM\n" " file in the ROM\n"
" -V print undefined and global labels\n" " -v print undefined and global labels\n"
" -vv print undefined and global labels, and relocation tables\n"
" --version output version information and exit\n" " --version output version information and exit\n"
" --help display this help and exit\n"); " --help display this help and exit\n");
} }
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
int i = 1, n, mode, hlen; int i, j, n, mode, hlen;
FILE *fp; FILE *fp;
char *aligntxt[4]= {"[align 1]","[align 2]","[align 4]","[align 256]"}; char *aligntxt[4]= {"[align 1]","[align 2]","[align 4]","[align 256]"};
if(argc<=1) { if(argc<=1) {
@ -76,12 +79,14 @@ int main(int argc, char *argv[]) {
exit(1); exit(1);
} }
if (strstr(argv[1], "--help")) { i = 1;
if (strstr(argv[i], "--help") || strstr(argv[i], "-?")) {
usage(stdout); usage(stdout);
exit(0); exit(0);
} }
if (strstr(argv[1], "--version")) { if (strstr(argv[i], "--version")) {
version(programname, progversion, author, copyright); version(programname, progversion, author, copyright);
exit(0); exit(0);
} }
@ -90,11 +95,12 @@ int main(int argc, char *argv[]) {
if(argv[i][0]=='-') { if(argv[i][0]=='-') {
/* process options */ /* process options */
switch(argv[i][1]) { switch(argv[i][1]) {
case 'V':
labels = 1;
break;
case 'v': case 'v':
printf("file65: Version 0.2\n"); j = 1;
while (argv[i][j] == 'v') {
verbose ++;
j++;
}
break; break;
case 'a': case 'a':
case 'A': case 'A':
@ -142,7 +148,7 @@ int main(int argc, char *argv[]) {
printf(" zero segment @ $%04x - $%04x [$%04x bytes]\n", hdr[21]*256+hdr[20], hdr[21]*256+hdr[20]+hdr[23]*256+hdr[22], hdr[23]*256+hdr[22]); printf(" zero segment @ $%04x - $%04x [$%04x bytes]\n", hdr[21]*256+hdr[20], hdr[21]*256+hdr[20]+hdr[23]*256+hdr[22], hdr[23]*256+hdr[22]);
printf(" stack size $%04x bytes %s\n", hdr[25]*256+hdr[24], printf(" stack size $%04x bytes %s\n", hdr[25]*256+hdr[24],
(hdr[25]*256+hdr[24])==0?"(i.e. unknown)":""); (hdr[25]*256+hdr[24])==0?"(i.e. unknown)":"");
if(labels) { if(verbose) {
read_options(fp); read_options(fp);
print_labels(fp, hdr[11]*256+hdr[10] + hdr[15]*256+hdr[14]); print_labels(fp, hdr[11]*256+hdr[10] + hdr[15]*256+hdr[14]);
} }
@ -231,13 +237,13 @@ void print_option(unsigned char *buf, int len) {
} }
int read_options(FILE *fp) { int read_options(FILE *fp) {
int c, l=0; int c, d, l=0;
unsigned char tb[256]; unsigned char tb[256];
c=fgetc(fp); l++; c=fgetc(fp); l++;
while(c && c!=EOF) { while(c && c!=EOF) {
c&=255; c&=255;
fread(tb, 1, c-1, fp); d = fread(tb, 1, c-1, fp);
if(labels) print_option(tb, c); if(labels) print_option(tb, c);
l+=c; l+=c;
c=fgetc(fp); c=fgetc(fp);
@ -247,11 +253,17 @@ int read_options(FILE *fp) {
int print_labels(FILE *fp, int offset) { int print_labels(FILE *fp, int offset) {
int i, nud, c, seg, off; int i, nud, c, seg, off;
const char *segments[] = { "undef", "abs", "text", "data", "bss", "zero" };
const char *reltype[] = { "-", "LOW", "HIGH", "-", "WORD", "SEG", "SEGADDR" };
/* /*
printf("print_labels:offset=%d\n",offset); printf("print_labels:offset=%d\n",offset);
*/ */
fseek(fp, offset, SEEK_CUR); fseek(fp, offset, SEEK_CUR);
// -----------------------------------------------------------
// print undefined labels
nud = (fgetc(fp) & 0xff); nud = (fgetc(fp) & 0xff);
nud += ((fgetc(fp) << 8) & 0xff00); nud += ((fgetc(fp) << 8) & 0xff00);
@ -269,25 +281,59 @@ printf("print_labels:offset=%d\n",offset);
printf("\n"); printf("\n");
} }
// ---------------------------------------------------------
// skip relocation tables
// two tables, one for text one for data
for(i=0;i<2;i++) { for(i=0;i<2;i++) {
unsigned char lowbyte;
unsigned short index;
unsigned short offset = 0;
if (verbose > 1) {
printf("Relocation table for %s:\n", i ? "text":"data");
}
c=fgetc(fp); c=fgetc(fp);
while(c && c!=EOF) { while(c && c!=EOF) {
c&= 0xff; c&= 0xff;
while(c == 255 && c!= EOF) { while(c == 255 && c!= EOF) {
offset += 254;
c=fgetc(fp); c=fgetc(fp);
if(c==EOF) break; if(c==EOF) break;
c&= 0xff; c&= 0xff;
} }
if(c==EOF) break; if(c==EOF) break;
offset += c;
c=fgetc(fp); c=fgetc(fp);
if( (c & 0xe0) == 0x40 ) fgetc(fp); if( (c & 0xe0) == 0x40 ) {
if( (c & 0x07) == 0 ) { fgetc(fp); fgetc(fp); } lowbyte = fgetc(fp);
}
if( (c & 0x07) == 0 ) {
index = fgetc(fp) & 0xff;
index += (fgetc(fp) & 0xff) << 8;
}
if (verbose > 1) {
printf("\t%d:%s(%s (%d)", offset, reltype[ (c>>5) & 0xf], segments[c & 0x07], (c&0x07));
if ( (c & 0xe0) == 0x40) {
printf(", %02x", lowbyte);
}
if ( (c & 0x07) == 0) {
printf(", %04x", index);
}
printf(")");
}
c=fgetc(fp); c=fgetc(fp);
} }
if (verbose > 1) {
printf("\n");
}
} }
// ---------------------------------------------------------
// print global labels
nud = (fgetc(fp) & 0xff); nud = (fgetc(fp) & 0xff);
nud += ((fgetc(fp) << 8) & 0xff00); nud += ((fgetc(fp) << 8) & 0xff00);
printf("Global Labels: %d\n", nud); printf("Global Labels: %d\n", nud);

File diff suppressed because it is too large Load Diff

View File

@ -46,6 +46,8 @@ void usage(FILE *fp)
fprintf(fp, fprintf(fp,
"Usage: %s [OPTION]... [FILE]...\n" "Usage: %s [OPTION]... [FILE]...\n"
"List CBM BASIC programs\n" "List CBM BASIC programs\n"
"This tool is deprecated as of xa 2.4 and will be removed in a future version.\n"
"Please consider migrating to VICE petcat, which has many more options.\n"
"\n" "\n"
" --version output version information and exit\n" " --version output version information and exit\n"
" --help display this help and exit\n", " --help display this help and exit\n",
@ -62,7 +64,7 @@ int main(int argc, char *argv[])
exit(1); exit(1);
} }
if (strstr(argv[1], "--help")) { if (strstr(argv[1], "--help") || strstr(argv[1], "-?")) {
usage(stdout); usage(stdout);
exit(0); exit(0);
} }

View File

@ -74,6 +74,7 @@ void usage(FILE *fp)
" -X extracts the file such that text and data\n" " -X extracts the file such that text and data\n"
" segments are chained, i.e. possibly relocating\n" " segments are chained, i.e. possibly relocating\n"
" the data segment to the end of the text segment\n" " the data segment to the end of the text segment\n"
" -v verbose output\n"
" --version output version information and exit\n" " --version output version information and exit\n"
" --help display this help and exit\n"); " --help display this help and exit\n");
} }
@ -87,13 +88,14 @@ int main(int argc, char *argv[]) {
int *base; int *base;
char *outfile = "a.o65"; char *outfile = "a.o65";
int extract = 0; int extract = 0;
int verbose = 0;
if (argc <= 1) { if (argc <= 1) {
usage(stderr); usage(stderr);
exit(1); exit(1);
} }
if (strstr(argv[1], "--help")) { if (strstr(argv[1], "--help") || strstr(argv[1], "-?")) {
usage(stdout); usage(stdout);
exit(0); exit(0);
} }
@ -107,6 +109,9 @@ int main(int argc, char *argv[]) {
if(argv[i][0]=='-') { if(argv[i][0]=='-') {
/* process options */ /* process options */
switch(argv[i][1]) { switch(argv[i][1]) {
case 'v':
verbose = 1;
break;
case 'o': case 'o':
if(argv[i][2]) outfile=argv[i]+2; if(argv[i][2]) outfile=argv[i]+2;
else if(i + 1 < argc) outfile=argv[++i]; else if(i + 1 < argc) outfile=argv[++i];
@ -192,25 +197,53 @@ int main(int argc, char *argv[]) {
file.tbase = file.buf[ 9]*256+file.buf[ 8]; file.tbase = file.buf[ 9]*256+file.buf[ 8];
file.tlen = file.buf[11]*256+file.buf[10]; 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.dbase = file.buf[13]*256+file.buf[12];
file.dlen = file.buf[15]*256+file.buf[14]; file.dlen = file.buf[15]*256+file.buf[14];
file.ddiff = dflag ? dbase - file.dbase : 0;
if (extract == 3) { if (extract == 3) {
if (dflag) { if (dflag) {
fprintf(stderr,"reloc65: %s: Warning: data segment address ignored for -X option\n", argv[i]); fprintf(stderr,"reloc65: %s: Warning: data segment address overrides -X option\n", argv[i]);
} } else {
dbase = file.tbase + file.tdiff + file.tlen; dbase = file.tbase + file.tdiff + file.tlen;
file.ddiff = dbase - file.dbase; file.ddiff = dbase - file.dbase;
} else { }
file.ddiff = dflag? dbase - file.dbase : 0;
} }
file.bbase = file.buf[17]*256+file.buf[16]; file.bbase = file.buf[17]*256+file.buf[16];
file.blen = file.buf[19]*256+file.buf[18]; file.blen = file.buf[19]*256+file.buf[18];
file.bdiff = bflag? bbase - file.bbase : 0; file.bdiff = bflag ? bbase - file.bbase : 0;
file.zbase = file.buf[21]*256+file.buf[20]; if (extract == 3) {
file.zlen = file.buf[23]*256+file.buf[21]; if (bflag) {
file.zdiff = zflag? zbase - file.zbase : 0; 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.segt = file.buf + hlen;
file.segd = file.segt + file.tlen; file.segd = file.segt + file.tlen;
file.utab = file.segd + file.dlen; file.utab = file.segd + file.dlen;

View File

@ -65,7 +65,7 @@ int main(int argc, char *argv[])
exit(1); exit(1);
} }
if (strstr(argv[1], "--help")) { if (strstr(argv[1], "--help") || strstr(argv[1], "-?")) {
usage(stdout); usage(stdout);
exit(0); exit(0);
} }

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

View File

@ -19,7 +19,7 @@
#ifndef __XA65_VERSION_H__ #ifndef __XA65_VERSION_H__
#define __XA65_VERSION_H__ #define __XA65_VERSION_H__
void version(const char *programname, const char *progversion, void version(const char *programname, const char *version,
const char *authors, const char *copyright) const char *authors, const char *copyright)
{ {
fprintf(stdout, fprintf(stdout,
@ -31,7 +31,7 @@ void version(const char *programname, const char *progversion,
"copying conditions. There is NO\n" "copying conditions. There is NO\n"
"warranty; not even for MERCHANTABILIY or " "warranty; not even for MERCHANTABILIY or "
"FITNESS FOR A PARTICULAR PURPOSE.\n", "FITNESS FOR A PARTICULAR PURPOSE.\n",
programname, progversion, authors, copyright); programname, version, authors, copyright);
} }
#endif /* __XA65_VERSION_H__ */ #endif /* __XA65_VERSION_H__ */

View File

@ -45,6 +45,7 @@
#include "xar.h" #include "xar.h"
#include "xat.h" #include "xat.h"
#include "xacharset.h" #include "xacharset.h"
#include "xalisting.h"
#include "version.h" #include "version.h"
@ -55,27 +56,34 @@
#define ANZWARN 13 #define ANZWARN 13
#define programname "xa" #define programname "xa"
#define progversion "v2.3.14" /* progversion now in xa.h */
#define authors "Written by Andre Fachat, Jolse Maginnis, David Weinehall and Cameron Kaiser" #define authors "Written by Andre Fachat, Jolse Maginnis, David Weinehall and Cameron Kaiser"
#define copyright "Copyright (C) 1989-2023 Andre Fachat, Jolse Maginnis, David Weinehall\nand Cameron Kaiser." #define copyright "Copyright (C) 1989-2023 Andre Fachat, Jolse Maginnis, David Weinehall\nand Cameron Kaiser."
/* exported globals */ /* exported globals */
int ncmos, cmosfl, w65816, n65816; int ncmos, cmosfl, w65816, n65816;
int masm = 0;
int ppinstr = 0; /* compatibility flags */
int masm = 0; /* MASM */
int ca65 = 0; /* CA65 */
int xa23 = 0; /* ^ and recursive comments, disable \ escape */
int ctypes = 0; /* C compatibility, like "0xab" types */
int nolink = 0; int nolink = 0;
int romable = 0; int romable = 0;
int romaddr = 0; int romaddr = 0;
int noglob = 0; int noglob = 0;
int showblk = 0; int showblk = 0;
int crossref = 0; int crossref = 0;
int undefok = 0; // -R only accepts -Llabels; with -U all undef'd labels are ok in -R mode
char altppchar; char altppchar;
/* local variables */ /* local variables */
static char out[MAXLINE]; static char out[MAXLINE];
static time_t tim1, tim2; static time_t tim1, tim2;
static FILE *fpout, *fperr, *fplab; static FILE *fpout, *fperr, *fplab, *fplist;
static int ner = 0; static int ner = 0;
static int ner_max = 20;
static int align = 1; static int align = 1;
@ -86,12 +94,14 @@ static int x_init(void);
static int pass1(void); static int pass1(void);
static int pass2(void); static int pass2(void);
static int puttmp(int); static int puttmp(int);
static int puttmpw(int);
static int puttmps(signed char *, int); static int puttmps(signed char *, int);
static void chrput(int); static void chrput(int);
static int xa_getline(char *); static int xa_getline(char *);
static void lineout(void); static void lineout(void);
static long ga_p1(void); static long ga_p1(void);
static long gm_p1(void); static long gm_p1(void);
static int set_compat(char *compat_name);
/* text */ /* text */
int memode,xmode; int memode,xmode;
@ -111,16 +121,18 @@ int main(int argc,char *argv[])
signed char *s=NULL; signed char *s=NULL;
char *tmpp; char *tmpp;
char *listformat = NULL;
int mifiles = 5; int mifiles = 5;
int nifiles = 0; int nifiles = 0;
int verbose = 0; int verbose = 0;
int oldfile = 0;
int no_link = 0; int no_link = 0;
char **ifiles; char **ifiles;
char *ofile; char *printfile; /* print listing to this file */
char *efile; char *ofile; /* output file */
char *lfile; char *efile; /* error listing goes there */
char *lfile; /* labels go here */
char *ifile; char *ifile;
char old_e[MAXLINE]; char old_e[MAXLINE];
@ -161,7 +173,7 @@ int main(int argc,char *argv[])
exit(1); exit(1);
} }
if (strstr(argv[1], "--help")) { if (strstr(argv[1], "--help") || strstr(argv[1], "-?")) {
usage(w65816, stdout); usage(w65816, stdout);
exit(0); exit(0);
} }
@ -174,6 +186,7 @@ int main(int argc,char *argv[])
ofile="a.o65"; ofile="a.o65";
efile=NULL; efile=NULL;
lfile=NULL; lfile=NULL;
printfile=NULL;
if(pp_init()) { if(pp_init()) {
logout("fatal: pp: no memory!"); logout("fatal: pp: no memory!");
@ -192,6 +205,9 @@ int main(int argc,char *argv[])
while(i<argc) { while(i<argc) {
if(argv[i][0]=='-') { if(argv[i][0]=='-') {
switch(argv[i][1]) { switch(argv[i][1]) {
case 'E':
ner_max = 0;
break;
case 'p': case 'p':
/* intentionally not allowing an argument to follow with a /* intentionally not allowing an argument to follow with a
space to avoid - being seen as the alternate space to avoid - being seen as the alternate
@ -209,11 +225,21 @@ int main(int argc,char *argv[])
"warning: extra characters to -p ignored\n"); "warning: extra characters to -p ignored\n");
break; break;
case 'M': case 'M':
fprintf(stderr, "Warning: -M is deprecated (use -XMASM) and will be removed in a future version\n");
masm = 1; /* MASM compatibility mode */ masm = 1; /* MASM compatibility mode */
break; break;
case 'S': case 'X': /* compatibility across assemblers... */
ppinstr = 1; /* preprocessor substitution in strings ok */ {
fprintf(stderr, "Warning: -S is deprecated and will be removed in 2.4+!\n"); 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; break;
case 'O': /* output charset */ case 'O': /* output charset */
{ {
@ -256,6 +282,9 @@ int main(int argc,char *argv[])
case 'R': case 'R':
relmode = 1; relmode = 1;
break; break;
case 'U':
undefok = 1;
break;
case 'D': case 'D':
s = (signed char*)strstr(argv[i]+2,"="); s = (signed char*)strstr(argv[i]+2,"=");
if(s) *s = ' '; if(s) *s = ' ';
@ -280,10 +309,6 @@ int main(int argc,char *argv[])
case 'B': case 'B':
showblk = 1; showblk = 1;
break; break;
case 'x': /* old filename behaviour */
oldfile = 1;
fprintf(stderr, "Warning: -x is now deprecated and will be removed in 2.4+!\n");
break;
case 'I': case 'I':
if(argv[i][2]==0) { if(argv[i][2]==0) {
if (i + 1 < argc) reg_include(argv[++i]); if (i + 1 < argc) reg_include(argv[++i]);
@ -295,6 +320,20 @@ int main(int argc,char *argv[])
reg_include(argv[i]+2); reg_include(argv[i]+2);
} }
break; 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': case 'o':
if(argv[i][2]==0) { if(argv[i][2]==0) {
if (i + 1 < argc) ofile=argv[++i]; if (i + 1 < argc) ofile=argv[++i];
@ -377,17 +416,14 @@ int main(int argc,char *argv[])
exit(0); exit(0);
} }
if(oldfile) {
strcpy(old_e, ifiles[0]);
strcpy(old_o, ifiles[0]);
strcpy(old_l, ifiles[0]);
if(setfext(old_e,".err")==0) efile = old_e;
if(setfext(old_o,".obj")==0) ofile = old_o;
if(setfext(old_l,".lab")==0) lfile = old_l;
}
if(verbose) fprintf(stderr, "%s\n",copyright); if(verbose) fprintf(stderr, "%s\n",copyright);
if (printfile!=NULL && !strcmp(printfile, "-")) {
printfile=NULL;
fplist = stdout;
} else {
fplist= printfile ? xfopen(printfile,"w") : NULL;
}
fplab= lfile ? xfopen(lfile,"w") : NULL; fplab= lfile ? xfopen(lfile,"w") : NULL;
fperr= efile ? xfopen(efile,"w") : NULL; fperr= efile ? xfopen(efile,"w") : NULL;
if(!strcmp(ofile,"-")) { if(!strcmp(ofile,"-")) {
@ -401,6 +437,8 @@ int main(int argc,char *argv[])
exit(1); exit(1);
} }
if(verbose) fprintf(stderr, "%s\n",copyright);
if(1 /*!m_init()*/) if(1 /*!m_init()*/)
{ {
if(1 /*!b_init()*/) if(1 /*!b_init()*/)
@ -414,6 +452,8 @@ int main(int argc,char *argv[])
/* if(fperr) fprintf(fperr,"%s\n",copyright); */ /* if(fperr) fprintf(fperr,"%s\n",copyright); */
if(verbose) logout(ctime(&tim1)); if(verbose) logout(ctime(&tim1));
list_setfile(fplist);
/* Pass 1 */ /* Pass 1 */
pc[SEG_ABS]= 0; /* abs addressing */ pc[SEG_ABS]= 0; /* abs addressing */
@ -438,7 +478,7 @@ int main(int argc,char *argv[])
if(verbose) logout(out); if(verbose) logout(out);
er=pp_open(ifile); er=pp_open(ifile);
puttmp(0); puttmpw(0);
puttmp(T_FILE); puttmp(T_FILE);
puttmp(0); puttmp(0);
puttmp(0); puttmp(0);
@ -491,6 +531,8 @@ int main(int argc,char *argv[])
{ {
if(verbose) logout("xAss65: Pass 2:\n"); if(verbose) logout("xAss65: Pass 2:\n");
list_start(listformat);
seg_pass2(); seg_pass2();
if(relmode) { if(relmode) {
@ -502,6 +544,8 @@ int main(int argc,char *argv[])
r_mode(RMODE_ABS); r_mode(RMODE_ABS);
} }
er=pass2(); er=pass2();
list_end();
} }
if(fplab) printllist(fplab); if(fplab) printllist(fplab);
@ -510,9 +554,10 @@ int main(int argc,char *argv[])
if((!er) && relmode) seg_end(fpout); /* write reloc/label info */ if((!er) && relmode) seg_end(fpout); /* write reloc/label info */
if(fplist && fplist!=stdout) fclose(fplist);
if(fperr) fclose(fperr); if(fperr) fclose(fperr);
if(fplab) fclose(fplab); if(fplab) fclose(fplab);
if(fpout) fclose(fpout); if(fpout && fpout!=stdout) fclose(fpout);
} else { } else {
logout("fatal: x: no memory!\n"); logout("fatal: x: no memory!\n");
@ -534,7 +579,12 @@ int main(int argc,char *argv[])
if(ner || er) if(ner || er)
{ {
if (ner_max > 0) {
fprintf(stderr, "Break after %d error%c\n",ner,ner?'s':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();*/ /*unlink();*/
if(ofile) { if(ofile) {
unlink(ofile); unlink(ofile);
@ -649,39 +699,41 @@ static int pass2(void)
filep=&datei; filep=&datei;
afile->mn.tmpe=0L; 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; 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(!l)
{ {
if(afile->mn.tmp[afile->mn.tmpe]==T_LINE) 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); datei.fline=(afile->mn.tmp[afile->mn.tmpe+1]&255)+(afile->mn.tmp[afile->mn.tmpe+2]<<8);
afile->mn.tmpe+=3; afile->mn.tmpe+=3;
list_line(datei.fline); /* set line number of next listing output */
} else } else
if(afile->mn.tmp[afile->mn.tmpe]==T_FILE) 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); 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)); memcpy(&datei.fname, afile->mn.tmp+afile->mn.tmpe+3, sizeof(datei.fname));
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); list_filename(datei.fname); /* set file name of next listing output */
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);
*/
} }
} else } else
{ {
/* do not attempt address mode optimization on pass 2 */ /* 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) if(er==E_NOLINE)
{ {
} else } else
@ -786,16 +838,14 @@ fprintf(stderr, "offset = %i length = %i fstart = %i flen = %i charo = %c\n",
static int pass1(void) static int pass1(void)
{ {
signed char o[MAXLINE]; signed char o[2*MAXLINE]; /* doubled for token listing */
int l,er,temp_er,al; int l,er,al;
memode=0; memode=0;
xmode=0; xmode=0;
tlen=0; tlen=0;
ner=0; ner=0;
temp_er = 0;
/*FIXIT*/ /*FIXIT*/
while(!(er=xa_getline(s))) while(!(er=xa_getline(s)))
{ {
@ -808,7 +858,7 @@ static int pass1(void)
case SEG_ZERO: zlen += al; break; 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) if(l)
{ {
@ -816,14 +866,14 @@ static int pass1(void)
{ {
if(er==E_OKDEF) if(er==E_OKDEF)
{ {
if(!(er=puttmp(l))) if(!(er=puttmpw(l)))
er=puttmps(o,l); er=puttmps(o,l);
} else } else
if(er==E_NOLINE) if(er==E_NOLINE)
er=E_OK; er=E_OK;
} else } else
{ {
if(!(er=puttmp(-l))) if(!(er=puttmpw(-l)))
er=puttmps(o,l); er=puttmps(o,l);
} }
} }
@ -860,6 +910,7 @@ static void usage(int default816, FILE *fp)
programname); programname);
fprintf(fp, fprintf(fp,
" -v verbose output\n" " -v verbose output\n"
" -E do not break after 20 errors, but show all\n"
" -C no CMOS-opcodes\n" " -C no CMOS-opcodes\n"
" -W no 65816-opcodes%s\n" " -W no 65816-opcodes%s\n"
" -w allow 65816-opcodes%s\n", " -w allow 65816-opcodes%s\n",
@ -873,11 +924,19 @@ static void usage(int default816, FILE *fp)
fprintf(fp, fprintf(fp,
" -e filename sets errorlog filename, default is none\n" " -e filename sets errorlog filename, default is none\n"
" -l filename sets labellist 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" " -r adds crossreference list to labellist (if `-l' given)\n"
" -M allow ``:'' to appear in comments for MASM compatibility\n" " -M allow ``:'' to appear in comments for MASM compatibility\n"
" -R start assembler in relocating mode\n"); " (deprecated: prefer -XMASM)\n"
" -Xcompatset set compatibility flags for other assemblers, known values are:\n"
" C, MASM, CA65, XA23 (deprecated: for better 2.3 compatibility)\n"
" -R start assembler in relocating mode\n"
" -U allow all undefined labels in relocating mode\n");
fprintf(fp, fprintf(fp,
" -Llabel defines `label' as absolute, undefined label even when linking\n" " -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" " -b? addr set segment base address to integer value addr\n"
" `?' stands for t(ext), d(ata), b(ss) and z(ero) segment\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"); " (address can be given more than once, last one is used)\n");
@ -893,104 +952,89 @@ static void usage(int default816, FILE *fp)
" -Idir add directory `dir' to include path (before XAINPUT)\n" " -Idir add directory `dir' to include path (before XAINPUT)\n"
" --version output version information and exit\n" " --version output version information and exit\n"
" --help display this help and exit\n"); " --help display this help and exit\n");
fprintf(fp,
"== These options are deprecated and will be removed in 2.4+! ==\n"
" -x old filename behaviour (overrides `-o', `-e', `-l')\n"
" -S allow preprocessor substitution within strings\n");
} }
/*
static char *ertxt[] = { "Syntax","Label definiert",
"Label nicht definiert","Labeltabelle voll",
"Label erwartet","Speicher voll","Illegaler Opcode",
"Falsche Adressierungsart","Branch ausserhalb des Bereichs",
"Ueberlauf","Division durch Null","Pseudo-Opcode erwartet",
"Block-Stack-Ueberlauf","Datei nicht gefunden",
"End of File","Block-Struktur nicht abgeschlossen",
"NoBlk","NoKey","NoLine","OKDef","DSB","NewLine",
"NewFile","CMOS-Befehl","pp:Falsche Anzahl Parameter" };
*/
static char *ertxt[] = { static char *ertxt[] = {
"Syntax", "Syntax", // E_SYNTAX =-1
"Label already defined", "Label already defined", // E_LABDEF =-2
"Label not defined", "Label not defined", // E_NODEF =-3
"Label table full", "Label table full", // E_LABFULL =-4
"Label expected", "Label expected", // E_LABEXP =-5
"Out of memory", "Out of memory", // E_NOMEM =-6
"Illegal opcode", "Illegal opcode", // E_ILLCODE =-7
"Wrong addressing mode", "Wrong addressing mode", // E_ADRESS =-8
"Branch out of range", "Branch out of range", // E_RANGE =-9
"Overflow", "Overflow", // E_OVERFLOW =-10
"Division by zero", "Division by zero", // E_DIV =-11
"Pseudo-opcode expected", "Pseudo-opcode expected", // E_PSOEXP =-12
"Block stack overflow", "Block stack overflow", // E_BLKOVR =-13
"File not found", "File not found", // E_FNF =-14
"End of file", "End of file", // E_EOF =-15
"Unmatched block close", "Unmatched block close", // E_BLOCK =-16
"NoBlk", "NoBlk", // E_NOBLK =-17
"NoKey", "NoKey", // E_NOKEY =-18
"NoLine", "NoLine", // E_NOLINE =-19
"OKDef", "OKDef", // E_OKDEF =-20
"DSB", "DSB", // E_DSB =-21
"NewLine", "NewLine", // E_NEWLINE =-22
"NewFile", "NewFile", // E_NEWFILE =-23
"CMOS instruction used with -C", "CMOS instruction used with -C", // E_DMOS =-24
"pp:Wrong parameter count", "pp:Wrong parameter count", // E_ANZPAR =-25
"Illegal pointer arithmetic", "Illegal pointer arithmetic (-26)", // E_ILLPOINTER =-26
"Illegal segment", "Illegal segment", // E_ILLSEGMENT =-27
"File header option too long", "File header option too long", // E_OPTLEN =-28
"File option not at file start (when ROM-able)", "File option not at file start (when ROM-able)", // E_ROMOPT =-29
"Illegal align value", "Illegal align value", // E_ILLALIGN =-30
"65816 mode used/required", "65816 mode used/required", // E_65816 =-31
"Exceeded recursion limit for label evaluation", "Exceeded recursion limit for label evaluation", // E_ORECMAC =-32
"Unresolved preprocessor directive at end of file", "Unresolved preprocessor directive at end of file", // E_OPENPP =-33
"Data underflow", "Data underflow", // E_OUTOFDATA =-34
"Illegal quantity", "Illegal quantity", // E_ILLQUANT =-35
".bin", ".bin", // E_BIN =-36
"#error directive", // E_UERROR =-37
"Assertion", // E_AERROR =-38
"DSB has negative length", // E_NEGDSBLEN =-39
/* placeholders for future fatal errors */ /* placeholders for future fatal errors */
"", "", // -40
"", "", // -41
"", "", // -42
"", "", // -43
"", "", // -44
"", "", // -45
"", "", // -46
"", "", // -47
"", "", // -48
"", "", // -49
"", "", // -50
"", "", // -51
"", "", // -52
"", "", // -53
"", "", // -54
"", "", // -55
"", "", // -56
"", "", // -57
"", "", // -58
"", "", // -59
"", "", // -60
"", "", // -61
"", "", // -62
"", "", // -63
"", "", // -64 (was missing...)
"",
"",
"",
/* warnings */ /* warnings */
"Cutting word relocation in byte value", "Cutting word relocation in byte value", // W_ADRRELOC =-65
"Byte relocation in word value", "Byte relocation in word value", // W_BYTERELOC =-66
"Illegal pointer arithmetic", "Illegal pointer arithmetic (-66)", // E_WPOINTER =-67
"Address access to low or high byte pointer", "Address access to low or high byte pointer", // W_ADDRACC =-68
"High byte access to low byte pointer", "High byte access to low byte pointer", // W_HIGHACC =-69
"Low byte access to high byte pointer", "Low byte access to high byte pointer", // W_LOWACC =-70
"Can't optimize forward-defined label; using absolute addressing", "Can't optimize forward-defined label; using absolute addressing", // W_FORLAB =-71
"Open preprocessor directive at end of file (intentional?)", "Open preprocessor directive at end of file (intentional?)", // W_OPENPP =-72
"Included binary data exceeds 64KB", "Included binary data exceeds 64KB", // W_OVER64K =-73
"Included binary data exceeds 16MB", "Included binary data exceeds 16MB", // W_OVER16M =-74
"MVN/MVP $XXXX syntax is deprecated and will be removed", "Subtracting pointer from constant not supported in -R mode", // W_SUBTRACT =-75
/* more placeholders */ /* more placeholders */
"", "", // -76
"", "", // -77
}; };
@ -1013,7 +1057,9 @@ static int x_init(void)
static int puttmp(int c) static int puttmp(int c)
{ {
int er=E_NOMEM; 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) if(afile->mn.tmpz<TMPMEM)
{ {
afile->mn.tmp[afile->mn.tmpz++]=c; afile->mn.tmp[afile->mn.tmpz++]=c;
@ -1022,17 +1068,37 @@ static int puttmp(int c)
return(er); 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) static int puttmps(signed char *s, int l)
{ {
int i=0,er=E_NOMEM; 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) if(afile->mn.tmpz+l<TMPMEM)
{ {
while(i<l) while(i<l) {
afile->mn.tmp[afile->mn.tmpz++]=s[i++]; //printf(" %02x", 0xff & s[i]);
afile->mn.tmp[afile->mn.tmpz++]=s[i++];
}
er=E_OK; er=E_OK;
} }
// printf("\n");
return(er); return(er);
} }
@ -1062,25 +1128,19 @@ static int xa_getline(char *s)
if(ec==E_NEWLINE) if(ec==E_NEWLINE)
{ {
puttmp(0); puttmpw(0);
puttmp(T_LINE); puttmp(T_LINE);
puttmp((filep->fline)&255); puttmpw(filep->fline);
puttmp(((filep->fline)>>8)&255); ec=E_OK;
ec=E_OK;
} }
else else
if(ec==E_NEWFILE) if(ec==E_NEWFILE)
{ {
puttmp(0); puttmpw(0);
puttmp(T_FILE); puttmp(T_FILE);
puttmp((filep->fline)&255); puttmpw(filep->fline);
puttmp(((filep->fline)>>8)&255);
puttmps((signed char*)&(filep->fname), sizeof(filep->fname)); puttmps((signed char*)&(filep->fname), sizeof(filep->fname));
/*
puttmps((signed char*)filep->fname,
1+(int)strlen(filep->fname));
*/
ec=E_OK; ec=E_OK;
} }
} while(!ec && l[i]=='\0'); } while(!ec && l[i]=='\0');
@ -1089,6 +1149,7 @@ static int xa_getline(char *s)
gl=0; gl=0;
if(!ec || ec==E_EOF) if(!ec || ec==E_EOF)
{ {
int startofline = 1;
do { do {
c=s[j]=l[i++]; c=s[j]=l[i++];
@ -1096,21 +1157,42 @@ static int xa_getline(char *s)
hkfl^=1; hkfl^=1;
if (!comcom && !(hkfl&1) && c=='\'') if (!comcom && !(hkfl&1) && c=='\'')
hkfl^=2; hkfl^=2;
if (c==';' && !hkfl) if (c==';' && !hkfl) {
comcom = 1; comcom = 1;
if (c=='\0') }
break; /* hkfl = comcom = 0 */ if (c=='\0') {
if (c==':' && !hkfl && (!comcom || !masm)) { // end of line
gl=1; break; /* hkfl = comcom = 0 */
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 */
// 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++; j++;
} while (c!='\0' && j<MAXLINE-1 && i<MAXLINE-1); } while (c!='\0' && j<MAXLINE-1 && i<MAXLINE-1);
s[j]='\0'; s[j]='\0';
} else } else
s[0]='\0'; s[0]='\0';
#if 0
printf("got line: %s\n", s);
#endif
return(ec); return(ec);
} }
@ -1130,8 +1212,8 @@ static void lineout(void)
void errout(int er) void errout(int er)
{ {
if (er<-ANZERR || er>-1) { if (er<=-ANZERR || er>-1) {
if(er>=-(ANZERR+ANZWARN) && er < -ANZERR) { if(er>=-(ANZERR+ANZWARN) && er <= -ANZERR) {
sprintf(out,"%s:line %d: %04x: Warning - %s\n", sprintf(out,"%s:line %d: %04x: Warning - %s\n",
filep->fname, filep->fline, pc[segment], ertxt[(-er)-1]); filep->fname, filep->fline, pc[segment], ertxt[(-er)-1]);
} else { } else {
@ -1167,3 +1249,37 @@ void logout(char *s)
fprintf(fperr,"%s",s); fprintf(fperr,"%s",s);
} }
/*****************************************************************/
typedef struct {
char *name;
int *flag;
} compat_set;
static compat_set compat_sets[] = {
{ "MASM", &masm },
{ "CA65", &ca65 },
{ "C", &ctypes },
{ "XA23", &xa23 },
{ 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;
/* warn on old versions of xa */
if (xa23) fprintf(stderr,
"Warning: -XXA23 is explicitly deprecated\n");
return 0;
}
i++;
}
return -1;
}

View File

@ -21,12 +21,18 @@
#include "xah.h" /* For SEG_MAX */ #include "xah.h" /* For SEG_MAX */
#define progmajor "2"
#define progminor "4"
#define progpatch "0"
#define progversion progmajor "." progminor "." progpatch
extern int ncmos, cmosfl, w65816, n65816; extern int ncmos, cmosfl, w65816, n65816;
extern int masm, nolink, ppinstr; extern int masm, ca65, xa23, nolink, undefok;
extern int noglob; extern int noglob;
extern int showblk; extern int showblk;
extern int relmode; extern int relmode;
extern int crossref; extern int crossref;
extern int ctypes;
extern char altppchar; extern char altppchar;
extern int tlen, tbase; extern int tlen, tbase;

View File

@ -32,7 +32,7 @@
static int pr[]= { P_START,P_ADD,P_ADD,P_MULT,P_MULT,P_SHIFT,P_SHIFT,P_CMP, static int pr[]= { P_START,P_ADD,P_ADD,P_MULT,P_MULT,P_SHIFT,P_SHIFT,P_CMP,
P_CMP,P_EQU,P_CMP,P_CMP,P_EQU,P_AND,P_XOR,P_OR, P_CMP,P_EQU,P_CMP,P_CMP,P_EQU,P_AND,P_XOR,P_OR,
P_LAND,P_LOR }; P_LAND,P_LOR,P_EQU,P_START };
static int pp,pcc; static int pp,pcc;
static int fundef; static int fundef;
@ -77,7 +77,8 @@ int a_term(signed char *s, int *v, int *l, int xpc, int *pfl, int *label, int f)
if(afl) *pfl=A_HIGH | ((afl<<8) & A_FMASK) | (*v & 255); if(afl) *pfl=A_HIGH | ((afl<<8) & A_FMASK) | (*v & 255);
*v=(*v>>8)&255; *v=(*v>>8)&255;
} }
else { else
if(s[pp]!=T_END) {
er=ag_term(s,P_START,v,&afl, label); er=ag_term(s,P_START,v,&afl, label);
bfl = afl & (A_MASK>>8); bfl = afl & (A_MASK>>8);
if(bfl && (bfl != (A_ADR>>8)) ) { if(bfl && (bfl != (A_ADR>>8)) ) {
@ -85,10 +86,12 @@ int a_term(signed char *s, int *v, int *l, int xpc, int *pfl, int *label, int f)
errout(W_ADDRACC); errout(W_ADDRACC);
} }
if(afl) *pfl = A_ADR | ((afl<<8) & A_FMASK); if(afl) *pfl = A_ADR | ((afl<<8) & A_FMASK);
} else {
er = E_SYNTAX;
} }
*l=pp; *l=pp;
/* printf("a_term: afl->%04x *pfl=%04x, (pc=%04x)\n",afl,*pfl, xpc); */ //fprintf(stderr, "a_term: nolink=%d, noundef=%d ->er=%d; l=%d, pp=%d, afl->%04x *pfl=%04x, (pc=%04x)\n",nolink, noundef ,er, *l, pp, afl,*pfl, xpc);
return(er); return(er);
} }
@ -98,15 +101,28 @@ static int ag_term(signed char *s, int p, int *v, int *nafl, int *label)
afl = 0; afl = 0;
/* //fprintf(stderr, "ag_term(%02x %02x %02x %02x %02x %02x\n",s[0],s[1],s[2],s[3],s[4],s[5]);
printf("ag_term(%02x %02x %02x %02x %02x %02x\n",s[0],s[1],s[2],s[3],s[4],s[5]);
*/
while(s[pp]=='-') while(s[pp]=='-')
{ {
pp++; pp++;
mf=-mf; mf=-mf;
} }
#if(0) /* NYI: this is hacked into .assert for now */
if(s[pp]==18) /* logical not */
{
pp++;
if(!(er=ag_term(s,P_START,v,&afl,label)))
{
if(s[pp]!=')')
er=E_SYNTAX;
else
pp++;
}
*v = !(*v);
} else
#endif
if(s[pp]=='(') if(s[pp]=='(')
{ {
pp++; pp++;
@ -121,25 +137,31 @@ printf("ag_term(%02x %02x %02x %02x %02x %02x\n",s[0],s[1],s[2],s[3],s[4],s[5]);
if(s[pp]==T_LABEL) if(s[pp]==T_LABEL)
{ {
er=l_get(cval(s+pp+1),v, &afl); er=l_get(cval(s+pp+1),v, &afl);
/* /*
printf("label: er=%d, seg=%d, afl=%d, nolink=%d, fundef=%d\n", printf("label: er=%d, seg=%d, afl=%d, nolink=%d, fundef=%d\n",
er, segment, afl, nolink, fundef); er, segment, afl, nolink, fundef);
*/ */
if(er==E_NODEF && segment != SEG_ABS && 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; er = E_OK;
*v = 0; *v = 0;
afl = SEG_UNDEF; if(afl!=SEG_UNDEFZP) {
afl = SEG_UNDEF;
}
*label = cval(s+pp+1); *label = cval(s+pp+1);
} }
} }
pp+=3; pp+=3;
} }
else else
if(s[pp]==T_VALUE) if(s[pp]==T_VALUE || s[pp] == T_CAST)
{ {
while (s[pp] == T_CAST) {
pp+=2;
}
*v=lval(s+pp+1); *v=lval(s+pp+1);
pp+=4; pp+=5;
/* /*
printf("value: v=%04x\n",*v); printf("value: v=%04x\n",*v);
*/ */
@ -149,7 +171,7 @@ printf("value: v=%04x\n",*v);
{ {
afl = s[pp+1]; afl = s[pp+1];
*v=cval(s+pp+2); *v=cval(s+pp+2);
pp+=4; pp+=6;
/* /*
printf("pointer: v=%04x, afl=%04x\n",*v,afl); printf("pointer: v=%04x, afl=%04x\n",*v,afl);
*/ */
@ -160,15 +182,16 @@ printf("pointer: v=%04x, afl=%04x\n",*v,afl);
*v=pcc; *v=pcc;
pp++; pp++;
afl = segment; afl = segment;
} }
else { else {
er=E_SYNTAX; er=E_SYNTAX;
} }
*v *= mf; *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)
{ {
//fprintf(stderr, "ag_term while: s[pp=%d]=%02x\n", pp, s[pp]);
er=get_op(s,&o); er=get_op(s,&o);
if(!er && pr[o]>p) if(!er && pr[o]>p)
@ -177,18 +200,24 @@ printf("pointer: v=%04x, afl=%04x\n",*v,afl);
if(!(er=ag_term(s,pr[o],&w, nafl, label))) if(!(er=ag_term(s,pr[o],&w, nafl, label)))
{ {
if(afl || *nafl) { /* check pointer arithmetic */ 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 */ afl = 0; /* subtract two pointers */
} else } else
if(((afl && !*nafl) || (*nafl && !afl)) && o==1) { if(((afl && !*nafl) || (*nafl && !afl)) && o==1) {
afl=(afl | *nafl); /* add constant to pointer */ afl=(afl | *nafl); /* add constant to pointer */
} else } else
if((afl && !*nafl) && o==2) { if((afl && !*nafl) && o==2) {
afl=(afl | *nafl); /* substract constant from pointer */ afl=(afl | *nafl); /* subtract constant from pointer */
} else { } else {
/* allow math in the same segment */ if((!afl && *nafl) && o==2) {
/* subtract pointer from constant */
errout(W_SUBTRACT);
}
/* allow math in the same segment */
if(segment!=SEG_ABS && segment != afl) { if(segment!=SEG_ABS && segment != afl) {
if(!dsb_len) { 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_ILLSEGMENT; er=E_ILLSEGMENT;
} }
} }
@ -211,10 +240,18 @@ static int get_op(signed char *s, int *o)
*o=s[pp]; *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; er=E_SYNTAX;
else } else {
er=E_OK; er=E_OK;
}
return(er); return(er);
} }

View File

@ -31,11 +31,12 @@
#define cval(s) 256 * ((s)[1] & 255) + ((s)[0]&255) #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 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++] = T_VALUE; \
t[i++] = v & 255; \ t[i++] = v & 255; \
t[i++] = (v >> 8) & 255; \ t[i++] = (v >> 8) & 255; \
t[i++] = (v >> 16) & 255; \ t[i++] = (v >> 16) & 255; \
t[i++] = f & 255; \
} while (0) } while (0)
#endif /* __XA65_XAD_H__ */ #endif /* __XA65_XAD_H__ */

View File

@ -20,15 +20,29 @@
#ifndef __XA65_XAH_H__ #ifndef __XA65_XAH_H__
#define __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 LABMEM 40000L
#define MAXLAB 32 #define MAXLAB 32
#define MAXBLK 16 #define MAXBLK 16
#define MAXFILE 7 #define MAXFILE 7
#define MAXLINE 2048 #define MAXLINE 2048
#define MAXPP 40000L #define MAXPP 40000L
#define ANZDEF 2340 /* mal 14 -> Byte, ANZDEF * 14 < 32768 */ #define ANZDEF 2340 /* multiplied by sizeof(List) -> Byte, ANZDEF * 20 < 32768 */
#define TMPMEM 200000L /* Zwischenspeicher von Pass1 nach Pass 2 */ #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
} xalabel_t;
typedef struct LabOcc { typedef struct LabOcc {
struct LabOcc *next; struct LabOcc *next;
@ -36,17 +50,29 @@ typedef struct LabOcc {
char *fname; char *fname;
} LabOcc; } LabOcc;
/**
* struct that defines a label, after it has been parsed
*/
typedef struct { typedef struct {
int blk; int blk;
int origblk; // only for fl=3
int val; int val;
int len; int len;
int fl; /* 0 = label value not valid/known, int fl; /* 0 = label value not valid/known,
* 1 = label value known * 1 = label value known
* 2 = label value not known, external global label (imported on link)
* 3 = label value not known, temporarily on external global label list (for -U)
*/ */
int afl; /* 0 = no address (no relocation), 1 = address label */ int afl; /* 0 = no address (no relocation), 1 = address label */
int nextindex; int nextindex;
xalabel_t is_cll; /* 0 is normal label, 1 is cheap local label (used for listing) */
char *n; char *n;
struct LabOcc *occlist; 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; } Labtab;
typedef struct { typedef struct {
@ -71,20 +97,20 @@ typedef struct {
#define BUFSIZE 4096 /* File-Puffegroesse (wg Festplatte) */ #define BUFSIZE 4096 /* File-Puffegroesse (wg Festplatte) */
#define E_OK 0 /* Fehlernummern */ #define E_OK 0 /* No error */
#define E_SYNTAX -1 /* Syntax Fehler */ #define E_SYNTAX -1 /* Syntax error */
#define E_LABDEF -2 /* Label definiert */ #define E_LABDEF -2 /* Label already defined (duplicate label definition) */
#define E_NODEF -3 /* Label nicht definiert */ #define E_NODEF -3 /* Label not defined */
#define E_LABFULL -4 /* Labeltabelle voll */ #define E_LABFULL -4 /* Label table full */
#define E_LABEXP -5 /* Label erwartet */ #define E_LABEXP -5 /* Label expected but not found */
#define E_NOMEM -6 /* kein Speicher mehr */ #define E_NOMEM -6 /* out of memory */
#define E_ILLCODE -7 /* Illegaler Opcode */ #define E_ILLCODE -7 /* Illegal Opcode */
#define E_ADRESS -8 /* Illegale Adressierung */ #define E_ADRESS -8 /* Illegal Addressing mode */
#define E_RANGE -9 /* Branch out of range */ #define E_RANGE -9 /* Branch out of range */
#define E_OVERFLOW -10 /* Ueberlauf */ #define E_OVERFLOW -10 /* overflow */
#define E_DIV -11 /* Division durch Null */ #define E_DIV -11 /* Division by zero */
#define E_PSOEXP -12 /* Pseudo-Opcode erwartet */ #define E_PSOEXP -12 /* Pseudo-Opcode expected but not found */
#define E_BLKOVR -13 /* Block-Stack Uebergelaufen */ #define E_BLKOVR -13 /* Block-Stack overflow */
#define E_FNF -14 /* File not found (pp) */ #define E_FNF -14 /* File not found (pp) */
#define E_EOF -15 /* End of File */ #define E_EOF -15 /* End of File */
#define E_BLOCK -16 /* Block inkonsistent */ #define E_BLOCK -16 /* Block inkonsistent */
@ -112,6 +138,9 @@ typedef struct {
#define E_OUTOFDATA -34 /* out of data */ #define E_OUTOFDATA -34 /* out of data */
#define E_ILLQUANT -35 /* generic illegal quantity error */ #define E_ILLQUANT -35 /* generic illegal quantity error */
#define E_BIN -36 /* okdef */ #define E_BIN -36 /* okdef */
#define E_UERROR -37 /* #error */
#define E_AERROR -38 /* .assert failed */
#define E_NEGDSBLEN -39 /* .dsb has negative length */
/* errors thru 64 are placeholders available for use */ /* errors thru 64 are placeholders available for use */
#define W_ADRRELOC -65 /* word relocation in byte value */ #define W_ADRRELOC -65 /* word relocation in byte value */
@ -124,21 +153,28 @@ typedef struct {
#define W_OPENPP -72 /* warning about open preprocessor directive */ #define W_OPENPP -72 /* warning about open preprocessor directive */
#define W_OVER64K -73 /* included binary over 64K in 6502 mode */ #define W_OVER64K -73 /* included binary over 64K in 6502 mode */
#define W_OVER16M -74 /* included binary over 16M in 65816 mode */ #define W_OVER16M -74 /* included binary over 16M in 65816 mode */
#define W_OLDMVNS -75 /* use of old mv? $xxxx syntax */ #define W_SUBTRACT -75 /* subtract a segment pointer from a constant - not supported in -R mode */
/* warnings 76-77 are placeholders available for use */ /* warnings 75-77 are placeholders available for use */
#define T_VALUE -1 /* Meta-values for the token list. Note must not overlap with the
#define T_LABEL -2 * K* definitions in xat.c, which have outgrown the positive numbers
#define T_OP -3 * and are now growing up from -128 ... */
#define T_END -4 #define T_VALUE -1 /* following is a 24 bit value in the token list */
#define T_LINE -5 #define T_LABEL -2 /* referring to a label, following the token is the 16bit label number */
#define T_FILE -6 #define T_OP -3 /* label oriented operation; following is the label number (16bit), plus the operation char (e.g. '+') */
#define T_POINTER -7 #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_START 0 /* arithmetic operation priorities */
#define P_LOR 1 /* Von zwei Operationen wird immer */ #define P_LOR 1 /* of any two operations, the one with */
#define P_LAND 2 /* die mit der hoeheren Prioritaet */ #define P_LAND 2 /* the higher priority will be done first */
#define P_OR 3 /* zuerst ausgefuehrt */ #define P_OR 3
#define P_XOR 4 #define P_XOR 4
#define P_AND 5 #define P_AND 5
#define P_EQU 6 #define P_EQU 6
@ -169,6 +205,8 @@ typedef struct {
#define SEG_ZERO 5 #define SEG_ZERO 5
#define SEG_MAX 6 #define SEG_MAX 6
#define SEG_UNDEFZP 7 /* is being mapped to UNDEF */
typedef struct Fopt { typedef struct Fopt {
signed char *text; /* text after pass1 */ signed char *text; /* text after pass1 */
int len; int len;
@ -189,8 +227,11 @@ typedef struct File {
int base[SEG_MAX]; int base[SEG_MAX];
int len[SEG_MAX]; int len[SEG_MAX];
struct { struct {
// temporary memory between pass1 and pass2
signed char *tmp; signed char *tmp;
// write pointer
unsigned long tmpz; unsigned long tmpz;
// read pointer
unsigned long tmpe; unsigned long tmpe;
} mn; } mn;
struct { struct {

View File

@ -48,46 +48,24 @@ static int b_fget(int*,int);
static int b_ltest(int,int); static int b_ltest(int,int);
static int b_get(int*); static int b_get(int*);
static int b_test(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, xalabel_t ltype);
static int b_link(int);
/* local variables */ static int b_new(void);
/* static void cll_init();
static int hashindex[256]; static int cll_get();
static Labtab *lt = NULL; static void cll_clear();
static int lti = 0; static int cll_getcur();
static int ltm = 0;
*/
/*
static char *ln;
static unsigned long lni;
static long sl;
*/
static Labtab *ltp; static Labtab *ltp;
int l_init(void) int l_init(void)
{ {
cll_init();
//unn_init();
return 0; return 0;
#if 0
int er;
for(er=0;er<256;er++)
hashindex[er]=0;
/*sl=(long)sizeof(Labtab);*/
/* if(!(er=m_alloc((long)(sizeof(Labtab)*ANZLAB),(char**)&lt)))
er=m_alloc((long)LABMEM,&ln);*/
er=m_alloc((long)(sizeof(Labtab)*ANZLAB),(char**)&lt);
lti=0;
/* lni=0L;*/
return(er);
#endif
} }
int ga_lab(void) int ga_lab(void)
@ -139,86 +117,221 @@ 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 lg_set(char *s ) {
int n, er; int n, er;
er = ll_search(s,&n); er = ll_search(s,&n, STD);
if(er==E_OK) { if(er==E_OK) {
fprintf(stderr,"Warning: global label doubly defined!\n"); fprintf(stderr,"Warning: global label doubly defined!\n");
} else { } else {
if(!(er=ll_def(s,&n,0))) { if(!(er=ll_def(s,&n,0, STD))) {
ltp=afile->la.lt+n; return lg_import(n);
ltp->fl=2; }
ltp->afl=SEG_UNDEF;
}
} }
return er; 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;
}
/*
* re-define a previously undef'd label as globally undefined
* (for -U option)
*/
int lg_toglobal(char *s ) {
int n, er;
//printf("lg_toglobal(%s)\n", s);
er = ll_search(s,&n, STD);
if(er==E_OK && ltp->fl != 3) {
// fonnd, but not yet set as global undef'd label
ltp=afile->la.lt+n;
ltp->fl=3;
ltp->afl=SEG_UNDEF;
ltp->origblk=ltp->blk;
ltp->blk=0;
}
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 l_def(char *s, int *l, int *x, int *f)
{ {
int n,er,b,i=0; int n,er,b,i=0;
xalabel_t cll_fl;
*f=0; *f=0; /* flag (given as param) that the label is to be re-defined and the
b=0; "label defined error" is to be skipped */
n=0; 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]=='-') if(s[0]=='-')
{ {
*f+=1; *f+=1; /* label is being redefined */
i++; i++;
} else } 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]=='+') if(s[0]=='+')
{ {
i++; i++;
n++; n++; /* block number b is absolute */
b=0; b=0; /* global block number */
} }
while(s[i]=='&') while(s[i]=='&')
{ {
n=0; if (n) b=0; /* reset block number */
n=0; /* block number is relative */
i++; 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); 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; 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) if(er==E_OK)
{ {
//printf("l_def OK: cll_fl=%d, i=%d, s=%s\n", cll_fl, i, s);
/* we actually found an existing label in the same scope */
ltp=afile->la.lt+n; ltp=afile->la.lt+n;
if(*f) if(*f)
{ {
/* redefinition of label */
*l=ltp->len+i; *l=ltp->len+i;
} else } else
if(ltp->fl==0) 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; *l=ltp->len+i;
if(b_ltest(ltp->blk,b)) if(b_ltest(ltp->blk,b))
er=E_LABDEF; er=E_LABDEF;
else else
ltp->blk=b; ltp->blk=b;
} else
if(ltp->fl == 3)
{
/* label has been defined as -U undef'd label so far - we need to check */
*l=ltp->len+i;
if(b_ltest(ltp->origblk,b))
er=E_LABDEF;
else
ltp->blk=b;
} else } else
er=E_LABDEF; er=E_LABDEF;
} else } else
if(er==E_NODEF) 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; ltp=afile->la.lt+n;
*l=ltp->len+i; *l=ltp->len+i;
ltp->fl=0; ltp->fl=0;
ltp->is_cll=cll_fl;
} }
//printf("l_def NODEF: n=%d, s=%s\n", n, ltp->n);
} }
*x=n; *x=n;
@ -229,15 +342,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 l_search(char *s, int *l, int *x, int *v, int *afl)
{ {
int n,er,b; int n,er,b;
xalabel_t cll_fl;
*afl=0; *afl=0;
er=ll_search(s,&n); /* check cheap local label */
/*printf("l_search: lab=%s(l=%d), afl=%d, er=%d, n=%d\n",s,*l, *afl,er,n);*/ 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) if(er==E_OK)
{ {
ltp=afile->la.lt+n; ltp=afile->la.lt+n;
*l=ltp->len; *l=ltp->len + ((cll_fl == STD) ? 0 : 1);
if(ltp->fl == 1) if(ltp->fl == 1)
{ {
l_get(n,v,afl);/* *v=lt[n].val;*/ l_get(n,v,afl);/* *v=lt[n].val;*/
@ -251,12 +380,22 @@ int l_search(char *s, int *l, int *x, int *v, int *afl)
} }
else else
{ {
b_get(&b); if(cll_fl == CHEAP) {
er=ll_def(s,x,b); /* ll_def(...,*v); */ 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); ltp=afile->la.lt+(*x);
ltp->is_cll = cll_fl;
*l=ltp->len;
*l=ltp->len + ((cll_fl == STD) ? 0 : 1);
//*l=ltp->len + cll_fl;
if(!er) if(!er)
{ {
@ -303,11 +442,87 @@ void l_addocc(int n, int *v, int *afl) {
} }
} }
/* for the list functionality */
char *l_get_name(int n, xalabel_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) int l_get(int n, int *v, int *afl)
{ {
if(crossref) l_addocc(n,v,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; (*v)=ltp->val;
lz=ltp->n; lz=ltp->n;
*afl = ltp->afl; *afl = ltp->afl;
@ -321,7 +536,8 @@ void l_set(int n, int v, int afl)
ltp->val = v; ltp->val = v;
ltp->fl = 1; ltp->fl = 1;
ltp->afl = afl; ltp->afl = afl;
/*printf("l_set('%s'(%d), v=$%04x, afl=%d\n",ltp->n, n, v, afl);*/
//printf("l_set('%s'(%d), v=$%04x, afl=%d\n",ltp->n, n, v, afl);
} }
static void ll_exblk(int a, int b) static void ll_exblk(int a, int b)
@ -335,19 +551,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, xalabel_t ltype)
{ {
int j=0,er=E_NOMEM,hash; 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) { if(!afile->la.lt) {
// ... does not exist yet, so malloc it
afile->la.lti = 0; afile->la.lti = 0;
afile->la.ltm = 1000; afile->la.ltm = 1000;
afile->la.lt = malloc(afile->la.ltm * sizeof(Labtab)); afile->la.lt = malloc(afile->la.ltm * sizeof(Labtab));
} }
if(afile->la.lti>=afile->la.ltm) { if(afile->la.lti>=afile->la.ltm) {
// ... or is at its capacity limit, so realloc it
afile->la.ltm *= 1.5; afile->la.ltm *= 1.5;
afile->la.lt = realloc(afile->la.lt, afile->la.ltm * sizeof(Labtab)); afile->la.lt = realloc(afile->la.lt, afile->la.ltm * sizeof(Labtab));
} }
@ -355,54 +575,66 @@ static int ll_def(char *s, int *n, int b) /* definiert naechstes Label
fprintf(stderr, "Oops: no memory!\n"); fprintf(stderr, "Oops: no memory!\n");
exit(1); 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]=='_')) // current pointer in label table
{ ltp = afile->la.lt + afile->la.lti;
s2[j]=s[j];
j++; if (ltype != UNNAMED) {
} // alloc space and copy over name
*/ if (ltype == UNNAMED_DEF) {
while((s[j]!='\0') && (isalnum(s[j]) || (s[j]=='_'))) j++; // unnamed lables are like ":--" or ":+" with variable length
s2 = malloc(j+1); while((s[j]!='\0') && (s[j]=='+' || s[j]=='-')) j++;
if(!s2) { } 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"); fprintf(stderr,"Oops: no memory!\n");
exit(1); exit(1);
}
strncpy(s2,s,j);
s2[j]=0;
} }
strncpy(s2,s,j);
s2[j]=0; // init new entry in label table
/*
if(j<MAXLAB)
{
*/
er=E_OK; er=E_OK;
ltp->len=j; ltp->len=j; // length of label
ltp->n = s2; ltp->n = s2; // name of label (char*)
ltp->blk=b; ltp->blk=b; // block number
ltp->fl=0; ltp->fl=0;
ltp->afl=0; ltp->afl=0;
ltp->occlist=NULL; ltp->is_cll=ltype; // STD, CHEAP, or UNNAMED label
hash=hashcode(s,j); ltp->occlist=NULL;
ltp->nextindex=afile->la.hashindex[hash]; hash=hashcode(s,j); // compute hashcode
afile->la.hashindex[hash]=afile->la.lti; ltp->nextindex=afile->la.hashindex[hash]; // and link in before last entry with same hashcode
*n=afile->la.lti; afile->la.hashindex[hash]=afile->la.lti; // set as start of list for that hashcode
afile->la.lti++;
/* lni+=j+1;*/ // TODO: does not work across files!
/* } ltp->blknext = -1; // no next block
} ltp->blkprev = b_link( afile->la.lti ); // previous block, linked within block
*/
/*printf("ll_def return: %d\n",er);*/ 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); 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, xalabel_t cll_fl) /* search Label in Tabelle ,nr->n */
{ {
int i,j=0,k,er=E_NODEF,hash; int i,j=0,k,er=E_NODEF,hash;
@ -411,7 +643,6 @@ int ll_search(char *s, int *n) /* search Label in Tabelle ,nr->n */
hash=hashcode(s,j); hash=hashcode(s,j);
i=afile->la.hashindex[hash]; i=afile->la.hashindex[hash];
/*printf("search?\n");*/
if(i>=afile->la.ltm) return E_NODEF; if(i>=afile->la.ltm) return E_NODEF;
do do
@ -422,11 +653,25 @@ int ll_search(char *s, int *n) /* search Label in Tabelle ,nr->n */
{ {
for (k=0;(k<j)&&(ltp->n[k]==s[k]);k++); for (k=0;(k<j)&&(ltp->n[k]==s[k]);k++);
if((j==k)&&(!b_test(ltp->blk))) if (cll_fl == CHEAP) {
{ if (ltp->blk == cll_getcur()) {
er=E_OK; er=E_OK;
break; break;
} }
} else
if (cll_fl == UNNAMED) {
// TODO
} else {
//printf("ll_search:match labels %s with %p (%s) from block %d, block check is %d\n", s, ltp, ltp->n, ltp->blk, b_test(ltp->blk));
/* 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) if(!i)
@ -444,6 +689,8 @@ int ll_search(char *s, int *n) /* search Label in Tabelle ,nr->n */
getchar(); getchar();
} }
#endif #endif
//printf("l_search(%s) returns er=%d, n=%d\n", s, er, *n);
return(er); return(er);
} }
@ -451,7 +698,7 @@ int ll_pdef(char *t)
{ {
int n; int n;
if(ll_search(t,&n)==E_OK) if(ll_search(t,&n, STD)==E_OK)
{ {
ltp=afile->la.lt+n; ltp=afile->la.lt+n;
if(ltp->fl) if(ltp->fl)
@ -460,6 +707,9 @@ int ll_pdef(char *t)
return(E_NODEF); return(E_NODEF);
} }
/*
* Write out the list of global labels in an o65 file
*/
int l_write(FILE *fp) int l_write(FILE *fp)
{ {
int i, afl, n=0; int i, afl, n=0;
@ -469,25 +719,39 @@ int l_write(FILE *fp)
fputc(0, fp); fputc(0, fp);
return 0; return 0;
} }
// calculate number of global labels
for (i=0;i<afile->la.lti;i++) { for (i=0;i<afile->la.lti;i++) {
ltp=afile->la.lt+i; ltp=afile->la.lt+i;
if((!ltp->blk) && (ltp->fl==1)) { if((!ltp->blk) && (ltp->fl==1)) {
n++; n++;
} }
} }
// write number of globals to file
fputc(n&255, fp); fputc(n&255, fp);
fputc((n>>8)&255, fp); fputc((n>>8)&255, fp);
// iterate over labels and write out label
for (i=0;i<afile->la.lti;i++) for (i=0;i<afile->la.lti;i++)
{ {
ltp=afile->la.lt+i; ltp=afile->la.lt+i;
if((!ltp->blk) && (ltp->fl==1)) { if((!ltp->blk) && (ltp->fl==1)) {
// write global name
fprintf(fp, "%s",ltp->n); fprintf(fp, "%s",ltp->n);
fputc(0,fp); fputc(0,fp);
// segment byte
afl = ltp->afl; afl = ltp->afl;
/* hack to switch undef and abs flag from internal to file format */ // hack to switch undef and abs flag from internal to file format
/*printf("label %s, afl=%04x, A_FMASK>>8=%04x\n", ltp->n, afl, A_FMASK>>8);*/ // if asolute of undefined (< SEG_TEXT, i.e. 0 or 1)
if( (afl & (A_FMASK>>8)) < SEG_TEXT) afl^=1; // then invert bit 0 (0 = absolute)
if( (afl & (A_FMASK>>8)) < SEG_TEXT) {
afl^=1;
}
// remove residue flags, only write out real segment number
// according to o65 file format definition
afl = afl & (A_FMASK >> 8);
fputc(afl,fp); fputc(afl,fp);
// value
fputc(ltp->val&255, fp); fputc(ltp->val&255, fp);
fputc((ltp->val>>8)&255, fp); fputc((ltp->val>>8)&255, fp);
} }
@ -496,19 +760,39 @@ int l_write(FILE *fp)
return 0; return 0;
} }
static int bt[MAXBLK]; /*******************************************************************************************
static int blk; * block management code. Here the ".(" and ".)" blocks are maintained.
static int bi; *
* 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) int b_init(void)
{ {
blk =0; blk =0;
bi =0; bi =0;
bt[bi]=blk; bt[bi]=blk;
labind=-1;
return(E_OK); return(E_OK);
} }
int b_new(void)
{
return ++blk;
}
int b_depth(void) int b_depth(void)
{ {
return bi; return bi;
@ -519,19 +803,26 @@ int ga_blk(void)
return(blk); return(blk);
} }
/**
* open a new block scope
*/
int b_open(void) int b_open(void)
{ {
int er=E_BLKOVR; int er=E_BLKOVR;
if(bi<MAXBLK-1) if(bi<MAXBLK-1)
{ {
bt[++bi]=++blk; bi++;
bt[bi]=b_new();
er=E_OK; er=E_OK;
} }
return(er); return(er);
} }
/**
* close a block scope
*/
int b_close(void) int b_close(void)
{ {
@ -542,10 +833,14 @@ int b_close(void)
} else { } else {
return E_BLOCK; return E_BLOCK;
} }
cll_clear();
//unn_clear();
return(E_OK); return(E_OK);
} }
/**
* get the block number of the current innermost block
*/
static int b_get(int *n) static int b_get(int *n)
{ {
*n=bt[bi]; *n=bt[bi];
@ -553,6 +848,9 @@ static int b_get(int *n)
return(E_OK); 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) static int b_fget(int *n, int i)
{ {
if((bi-i)>=0) if((bi-i)>=0)
@ -562,6 +860,10 @@ static int b_fget(int *n, int i)
return(E_OK); 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) static int b_test(int n)
{ {
int i=bi; int i=bi;
@ -572,6 +874,9 @@ static int b_test(int n)
return( i+1 ? E_OK : E_NOBLK ); 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)] */ 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; int i=0,er=E_OK;
@ -593,3 +898,10 @@ static int b_ltest(int a, int b) /* testet ob bt^-1(b) in intervall [0,bt^-1(
return(er); 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 */ #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; extern char *lz;
int l_init(void); int l_init(void);
int ga_lab(void); int ga_lab(void);
int gm_lab(void); int gm_lab(void);
@ -30,6 +35,10 @@ long gm_labm(void);
long ga_labm(void); long ga_labm(void);
int lg_set(char *); int lg_set(char *);
int lg_import(int);
int lg_importzp(int);
// used to re-define undef'd labels as global for -U option
int lg_toglobal(char *);
int b_init(void); int b_init(void);
int b_depth(void); int b_depth(void);
@ -40,9 +49,11 @@ int ga_blk(void);
int l_def(char *s, int* l, int *x, int *f); 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 l_search(char *s, int *l, int *x, int *v, int *afl);
void l_set(int n, int v, int afl); void l_set(int n, int v, int afl);
char* l_get_name(int n, xalabel_t *is_cll);
char* l_get_unique_name(int n);
int l_get(int n, int *v, int *afl); int l_get(int n, int *v, int *afl);
int l_vget(int n, int *v, char **s); int l_vget(int n, int *v, char **s);
int ll_search(char *s, int *n); int ll_search(char *s, int *n, xalabel_t labeltype);
int ll_pdef(char *t); int ll_pdef(char *t);
int b_open(void); int b_open(void);

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

@ -0,0 +1,750 @@
/* 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
if (*p == '>') {
strcpy(q, "&gt;");
q+=4;
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) {
int i;
char c;
/* line number in file */
snprintf(buf, 10, "% 5d", lineno);
i = strlen(buf);
buf += i;
buf += list_char(buf, ' ');
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, num_last_line, tmp, overflow;
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
num_last_line = 11;
tmp = listing[3] & 255;
if (tmp == (T_DEFINE & 255)) {
// we have label definition
num_last_line = 8;
}
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;
xalabel_t is_cll;
int tabval, operator;
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
}
operator = 0;
while (inp < len) {
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 '"': {
int i, len;
// string display
inp++;
outp += list_char(buf+outp, '"');
len = input[inp] & 0xff;
for (i = 0; i < len; i++) {
inp++;
outp += list_char(buf+outp, input[inp]);
}
inp++;
outp += list_char(buf+outp, '"');
break;
}
case '*': {
// If '*' appears as operand, it is the PC. We need to switch to operator then
inp++;
outp += list_char(buf+outp, '*');
operator = 1;
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 <= 20) { // sizeof(arith_ops)
outp += list_string(buf+outp, formatp->escape(arith_ops[op]));
inp += 1;
operator = 0;
}
// note: falls through for closing brackets which are where an operator would normally be.
// closing bracket is then printed in upper (operand) part in default case before
// another operator is expected after the bracket
}
}
end:
return outp;
}
int list_string(char *buf, char *string) {
int p = 0;
if (buf == NULL || string == NULL) {
fprintf(stderr, "NULL pointer: buf=%p, string=%p\n", buf, string);
fflush(stderr);
//exit(1);
return 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; return NULL;
} }
// copy to xname by replacing windows backslashes with the proper DIRCHAR
for(i=0;i<l+1;i++) { for(i=0;i<l+1;i++) {
xname[i]=((fn[i]=='\\')?DIRCHAR:fn[i]); xname[i]=((fn[i]=='\\')?DIRCHAR:fn[i]);
} }
//printf("name=%s, xname=%s, mode=%s\n",fn,xname, mode);
if(mode[0]=='r') if(mode[0]=='r')
{ {
if((file=fopen(fn,mode))==NULL if((file=fopen(fn,mode))==NULL
@ -68,7 +71,6 @@ FILE *xfopen(const char *fn,const char *mode)
strcpy(n2,n); strcpy(n2,n);
strcat(n2,xname); strcat(n2,xname);
strcat(n,fn); strcat(n,fn);
/* printf("name=%s,n2=%s,mode=%s\n",n,n2,mode); */
file=fopen(n,mode); file=fopen(n,mode);
if(!file) file=fopen(n2,mode); if(!file) file=fopen(n2,mode);
} }
@ -87,7 +89,6 @@ FILE *xfopen(const char *fn,const char *mode)
strcpy(n2,n); strcpy(n2,n);
strcat(n2,xname); strcat(n2,xname);
strcat(n,fn); strcat(n,fn);
/* printf("name=%s,n2=%s,mode=%s\n",n,n2,mode); */
file=fopen(n,mode); file=fopen(n,mode);
if(!file) file=fopen(n2,mode); if(!file) file=fopen(n2,mode);
} }

View File

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

View File

@ -40,7 +40,8 @@
#include "xap.h" #include "xap.h"
/* define this for recursive evaluation output */ /* define this for recursive evaluation output */
/* #define DEBUG_RECMAC */ #undef DEBUG_RECMAC
#undef DEBUG_REPLACE
char s[MAXLINE]; char s[MAXLINE];
Datei *filep; Datei *filep;
@ -50,24 +51,27 @@ static int pp_replace(char*,char*,int,int);
static int searchdef(char*); static int searchdef(char*);
static int fgetline(char*,int len, int *rlen, FILE*); 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_else(char*),pp_endif(char*);
static int pp_echo(char*),pp_if(char*),pp_print(char*),pp_prdef(char*); static int pp_echo(char*),pp_if(char*),pp_print(char*),pp_prdef(char*);
static int pp_ifldef(char*),pp_iflused(char*); static int pp_ifldef(char*),pp_iflused(char*);
static int pp_undef(char*); static int pp_undef(char*);
static int pp_error(char*);
#define ANZBEF 13 #define ANZBEF 14
#define VALBEF 6 #define VALBEF 7
static int quotebs = 0; static int quotebs = 0;
static int inquote = 0; static int inquote = 0;
static char *cmd[]={ "echo","include","define","undef","printdef","print", static char *cmd[]={
"echo","include","define","undef","printdef","print","error", /* VALBEF */
"ifdef","ifndef","else","endif", "ifdef","ifndef","else","endif",
"ifldef","iflused","if" }; "ifldef","iflused","if" }; /* ANZBEF */
static int (*func[])(char*) = { pp_echo,icl_open,pp_define,pp_undef, static int (*func[])(char*) = { pp_echo,icl_open,pp_define,pp_undef,
pp_prdef,pp_print, pp_ifdef,pp_ifndef, pp_prdef,pp_print,pp_error,pp_ifdef,pp_ifndef,
pp_else,pp_endif, pp_else,pp_endif,
pp_ifldef,pp_iflused,pp_if }; pp_ifldef,pp_iflused,pp_if };
@ -131,7 +135,7 @@ int pp_ifldef(char *t)
int pp_iflused(char *t) int pp_iflused(char *t)
{ {
int n; int n;
loopfl=(loopfl<<1)+( ll_search(t,&n) ? 1 : 0 ); loopfl=(loopfl<<1)+( ll_search(t,&n,STD) ? 1 : 0 );
return(0); return(0);
} }
@ -177,21 +181,29 @@ int pp_print(char *t)
return(0); return(0);
} }
int pp_error(char *t)
{
/* the offending line is printed for us */
return E_UERROR;
}
int pp_if(char *t) int pp_if(char *t)
{ {
int a,f,l,er; int a,f,l,er;
if((er=pp_replace(s,t,-1,rlist))) /* XXX: #if XYZ, if XYZ is not defined, XYZ gets treated as a label. */
if((er=pp_replace(s,t,-1,rlist))) {
errout(er); errout(er);
else } else
{ {
dsb_len = 1; dsb_len = 1;
f=b_term(s,&a,&l,pc[segment]); f=b_term(s,&a,&l,pc[segment]);
dsb_len = 0; dsb_len = 0;
if((!loopfl) && f) if((!loopfl) && f) {
errout(f); errout(f);
else } else
loopfl=(loopfl<<1)+( a ? 0 : 1 ); loopfl=(loopfl<<1)+( a ? 0 : 1 );
} }
return(0); return(0);
@ -362,7 +374,10 @@ int pp_define(char *k)
{ {
i++; i++;
liste[rl].p_anz++; 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) if(j<memfre)
{ {
strncpy(mem,t+i,j); strncpy(mem,t+i,j);
@ -371,6 +386,8 @@ int pp_define(char *k)
memfre-=j+1; memfre-=j+1;
} }
i+=j; i+=j;
// skip trailing whitespace after parameter name
while(isspace(t[i])) i++;
} }
if(t[i]==')') if(t[i]==')')
i++; i++;
@ -379,7 +396,7 @@ int pp_define(char *k)
i++; i++;
t+=i; t+=i;
pp_replace(h,t,-1,0); er = pp_replace(h,t,-1,rlist);
t=h; t=h;
@ -442,97 +459,107 @@ int tcompare(char s[],char *v[], int n)
return((i==n)? -1 : i); 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.
*
* to -> original output buffer for overflow check (only!)
* t -> where to write the output
* n -> replace macro n in liste[]
* sl -> length of liste[n].search (= liste[n].s_len)
* recursive ->
* l ->
* blist ->
*
*/
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 er = E_OK;
int i,l,n,sl,d,ld,er=E_OK,hkfl,klfl; int i, d;
char fti[MAXLINE],fto[MAXLINE]; char c;
/*
int flag=!strncmp(ti,"TOUT",4);
if(flag) printf("flag=%d\n",flag);
*/
(void)strcpy(t,ti);
if(rlist) // 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
while(t[0]!='\0') // with global variables...
{ char *saved_mem = mem;
/* find start of a potential token to be replaced */
while(!isalpha(t[0]) && t[0]!='_') {
/* escape strings quoted with " */
if (!ppinstr && t[0] == '\"') {
do {
t++;
ti++;
} while (t[0] && t[0]!='\"');
}
/* escape strings quoted with ' */ #ifdef DEBUG_RECMAC
if (!ppinstr && t[0] == '\'') { printf("replace part: n=%d, sl=%d, rec=%d, %s\n", n, sl, recursive, t);
do { #endif
t++;
ti++;
} while (t[0] && t[0]!='\'');
}
if(t[0]=='\0') // yes, mark replacement string
break; /*return(E_OK);*/ char *rs=liste[n].replace;
else
{ // does it have parameters?
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++;
if(i==sl)
{
rs=liste[n].replace;
if(liste[n].p_anz) 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); (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; er=E_NOMEM;
else else
{ {
y=t+sl; // ... passed
x=liste[n].search+sl+1; // y points to the char behind the input name (i.e. the '(')
if(*y!='(') 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; er=E_SYNTAX;
}
else else
{ {
mx=mem-1; // 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(i=0;i<liste[n].p_anz;i++) for(i=0;i<liste[n].p_anz;i++)
{ {
liste[rlist+i].search=x; char c;
liste[rlist+i].s_len=(int)strlen(x); int hkfl=0; // quote flag
int klfl=0; // brackets counter
// 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; x+=strlen(x)+1;
liste[rlist+i].p_anz=0; // points to first char of the parameter name in the input
liste[rlist+i].replace=mx+1; // copy over first char into text memory (note that the position
// is already stored in liste[].replace above)
c=*(++mx)=*(++y); c=*(++mx)=*(++y);
hkfl=klfl=0; // copy over the other characters
while(c!='\0' while(c!='\0'
&& ((hkfl!=0 && ((hkfl!=0
|| klfl!=0) || klfl!=0)
@ -551,69 +578,135 @@ int pp_replace(char *to, char *ti, int a,int b)
klfl--; klfl--;
} }
c=*(++mx)=*(++y); c=*(++mx)=*(++y);
} }
// zero-terminate stored string
*mx='\0'; *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) ? ')' : ',')) if(c!=((i==liste[n].p_anz-1) ? ')' : ','))
{ {
er=E_ANZPAR; er=E_ANZPAR;
// note: this break only exits the innermost loop!
break; 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 #ifdef DEBUG_RECMAC
printf("replace:\n"); printf("replace (er=%d):\n", er);
printf("%s=%s\n",liste[n].search,liste[n].replace); printf("%s=%s\n",liste[n].search,liste[n].replace);
#endif #endif
// loop over all arguments
for(i=0;i<liste[n].p_anz;i++) { for(i=0;i<liste[n].p_anz;i++) {
/* recursively evaluate arguments */ /* recursively evaluate arguments */
char nfto[MAXLINE]; char nfto[MAXLINE];
char nfwas[MAXLINE]; char nfwas[MAXLINE];
int j = 0; //int j = 0;
int k; //int k = 0;
(void)strcpy(nfwas, liste[rlist+i].replace); // copy over the replacement string into a buffer nfwas
if (!er) (void)strcpy(nfwas, liste[blist+i].replace);
er=pp_replace(nfto,nfwas,-1,rlist); 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 #ifdef DEBUG_RECMAC
printf("-%s=%s\n",liste[rlist+i].search,liste[rlist+i].replace); printf("-%s=%s\n",liste[rlist+i].search,liste[rlist+i].replace);
printf("SUBB: -%s=%s\n", nfwas, nfto); printf("SUBB: -%s=%s\n", nfwas, nfto);
#endif #endif
#if 0
// as long as the strings don't match, loop...
while ((k = strcmp(nfto, nfwas))) { while ((k = strcmp(nfto, nfwas))) {
// copy original from nfwas back to nfto
(void)strcpy(nfto, nfwas); (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); er=pp_replace(nfto,nfwas,-1,rlist);
}
// and copy result into input buffer
(void)strcpy(nfwas, nfto); (void)strcpy(nfwas, nfto);
#ifdef DEBUG_RECMAC #ifdef DEBUG_RECMAC
printf("SUBB2 (%i): -%s=%s\n", k, liste[rlist+i].replace, nfto); printf("SUBB2 (%i): -%s=%s\n", k, liste[rlist+i].replace, nfto);
#endif #endif
if (++j>10) if (++j>10) {
// we ran into 10 recursions deep - that does not look sound, bail out
errout(E_ORECMAC); errout(E_ORECMAC);
}
} }
#endif
// catch an error situation
if (liste[rlist+i].replace == NULL) { if (liste[rlist+i].replace == NULL) {
errout(E_ANZPAR); errout(E_ANZPAR);
return E_ANZPAR; return E_ANZPAR;
} }
(void)strcpy(liste[rlist+i].replace, nfto);
// 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 #ifdef DEBUG_RECMAC
printf("FINAL: -%s=%s\n",liste[rlist+i].search,liste[rlist+i].replace); printf("FINAL: -%s=%s\n",liste[rlist+i].search,liste[rlist+i].replace);
#endif #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);*/ /* if(flag) printf("sl=%d,",sl);*/
sl=(int)((long)y+1L-(long)t); sl=(int)((long)y+1L-(long)t);
/* if(flag) printf("sl=%d\n",sl);*/ /* if(flag) printf("sl=%d\n",sl);*/
rs=fto; rs=fto;
/* printf("->%s\n",fto);*/ #ifdef DEBUG_RECMAC
printf("->%s\n",fto);
#endif
} }
} }
if(er) if(er) {
mem = saved_mem;
return(er); return(er);
} }
} // end if(liste[n].p_anz), i.e. if it has parameters
d=(int)strlen(rs)-sl; d=(int)strlen(rs)-sl;
if(strlen(to)+d>=MAXLINE) if(strlen(to)+d>=MAXLINE) {
mem = saved_mem;
return(E_NOMEM); return(E_NOMEM);
}
/* /*
if(d<0) if(d<0)
@ -628,129 +721,155 @@ int pp_replace(char *to, char *ti, int a,int b)
t[ll+d]=t[ll]; t[ll+d]=t[ll];
} }
*/ */
if(d) if(d) {
(void)strcpy(t+sl+d,ti+sl); // 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; i=0;
while((c=rs[i])) while((c=rs[i])) {
t[i++]=c; 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) && (quotefl || 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;
#ifdef DEBUG_RECMAC
printf("macro entry: name=%s, sl=%d, p_anz=%d\n", liste[n].search, sl, liste[n].p_anz);
#endif
// 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) if(!n)
break; break;
// next index in linked list for given hash code
n=liste[n].nextindex; n=liste[n].nextindex;
} while(1); } while(1);
} else } 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--) for(n=b-1;n>=a;n--)
{ {
sl=liste[n].s_len; sl=liste[n].s_len;
if(sl && (sl==l)) if(sl && (sl==l) && check_name(t, n))
{ {
i=0; er = pp_replace_part(to, t, n, sl, 1, &l, b);
x=liste[n].search; break;
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;
}
} }
} }
} }
// advance input by length of name
ti+=ld; ti+=ld;
// advance output by l
t+=l; t+=l;
} } /* end while(t[0] != 0) */
} } /* end if(rlist) */
return(E_OK); return(E_OK);
} }
@ -774,6 +893,11 @@ int pp_init(void)
if(!er) { if(!er) {
liste=malloc((long)ANZDEF*sizeof(List)); liste=malloc((long)ANZDEF*sizeof(List));
if(!liste) er=E_NOMEM; if(!liste) er=E_NOMEM;
if(!er && !xa23) {
er = pp_define("XA_MAJOR " progmajor);
if (!er) er = pp_define("XA_MINOR " progminor);
if (!er) er = pp_define("XA_PATCH " progpatch);
}
} }
return(er); return(er);
} }
@ -781,17 +905,20 @@ int pp_init(void)
int pp_open(char *name) int pp_open(char *name)
{ {
FILE *fp; FILE *fp;
int l;
fp=xfopen(name,"r"); fp=xfopen(name,"r");
l = strlen(name);
/* we have to alloc it dynamically to make the name survive another /* we have to alloc it dynamically to make the name survive another
pp_open - it's used in the cross-reference list */ 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) { if(!flist[0].fname) {
fprintf(stderr,"Oops, no more memory!\n"); fprintf(stderr,"Oops, no more memory!\n");
exit(1); exit(1);
} }
(void)strcpy(flist[0].fname,name); (void)strncpy(flist[0].fname,name,l+1);
flist[0].fline=0; flist[0].fline=0;
flist[0].bdepth=b_depth(); flist[0].bdepth=b_depth();
flist[0].filep=fp; flist[0].filep=fp;
@ -835,7 +962,8 @@ int icl_close(int *c)
int icl_open(char *tt) int icl_open(char *tt)
{ {
FILE *fp2; FILE *fp2;
int j,i=0; char *namep;
int len,j,i=0;
pp_replace(s,tt,-1,rlist); pp_replace(s,tt,-1,rlist);
@ -858,14 +986,17 @@ int icl_open(char *tt)
fsp++; fsp++;
namep = s+i;
len = strlen(namep);
/* we have to alloc it dynamically to make the name survive another /* we have to alloc it dynamically to make the name survive another
pp_open - it's used in the cross-reference list */ 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) { if(!flist[fsp].fname) {
fprintf(stderr,"Oops, no more memory!\n"); fprintf(stderr,"Oops, no more memory!\n");
exit(1); exit(1);
} }
strcpy(flist[fsp].fname,s+i); strncpy(flist[fsp].fname,namep, len+1);
flist[fsp].fline=0; flist[fsp].fline=0;
flist[fsp].bdepth=b_depth(); flist[fsp].bdepth=b_depth();
flist[fsp].flinep=NULL; flist[fsp].flinep=NULL;
@ -875,6 +1006,7 @@ int icl_open(char *tt)
return(0); return(0);
} }
int pgetline(char *t) int pgetline(char *t)
{ {
int c,er=E_OK; int c,er=E_OK;
@ -887,32 +1019,43 @@ int pgetline(char *t)
filep =flist+fsp; filep =flist+fsp;
do { do {
c=fgetline(in_line, MAXLINE, &rlen, flist[fsp].filep); int is_continuation = 0;
/* continuation lines */ tlen = 0; // start of current line in in_line[]
tlen = rlen; do {
while(c=='\n' && tlen && in_line[tlen-1]=='\\') { c=fgetline(in_line + tlen, MAXLINE - tlen, &rlen, flist[fsp].filep);
c=fgetline(in_line + tlen-1, MAXLINE-tlen, &rlen, flist[fsp].filep); //fprintf(stderr, "fgetline -> c=%02x, rlen->%d, t->%s\n", c, rlen, in_line+tlen);
tlen += rlen-1;
/* 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)
{ tlen += rlen;
} while (is_continuation);
if(in_line[0]=='#' || in_line[0] == altppchar)
{
if (in_line[1]==' ') { /* cpp comment -- pp_comand doesn't if (in_line[1]==' ') { /* cpp comment -- pp_comand doesn't
handle this right */ handle this right */
er=pp_cpp(in_line+1); er=pp_cpp(in_line+1);
} else { } else {
if((er=pp_comand(in_line+1))) if((er=pp_comand(in_line+1)))
{ {
if(er!=1) if(er!=1)
{ {
logout(in_line); logout(in_line);
logout("\n"); logout("\n");
} }
} }
} }
} else } else {
er=1; er=1;
}
if(c==EOF) { if(c==EOF) {
if (loopfl && fsp) { if (loopfl && fsp) {
char bletch[MAXLINE]; char bletch[MAXLINE];
sprintf(bletch, sprintf(bletch,
@ -936,8 +1079,15 @@ int pgetline(char *t)
er= (er==1) ? E_OK : er ; 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); er=pp_replace(t,in_line,-1,rlist);
#ifdef DEBUG_REPLACE
printf(">>>: %s\n", t);
#endif
}
if(!er && nff) if(!er && nff)
er=E_NEWFILE; er=E_NEWFILE;
@ -947,7 +1097,8 @@ int pgetline(char *t)
filep=flist+fsp; filep=flist+fsp;
filep->flinep=in_line; filep->flinep=in_line;
//fprintf(stderr, "pgetline -> er=%d, t=%s\n", er, t);
return(er); return(er);
} }
@ -988,8 +1139,9 @@ int rgetc(FILE *fp)
nlf=1; nlf=1;
} }
/* check for start of comment anyway, to allow for nestesd comments */ /* check for start of comment anyway, to allow for nested comments */
if(!inquote && c=='/') /* only allow this with 2.3 compatibility */
if(!inquote && c=='/' && (xa23 || !incomment))
{ {
d = getc(fp); d = getc(fp);
@ -998,6 +1150,10 @@ int rgetc(FILE *fp)
do { do {
c = getc(fp); c = getc(fp);
} while (c != '\n' && c != EOF); } while (c != '\n' && c != EOF);
if (c == '\n') {
flist[fsp].fline++;
nlf=1;
}
} else } else
if (d == '*') { if (d == '*') {
/* start block comment */ /* start block comment */
@ -1037,19 +1193,15 @@ int rgetc(FILE *fp)
inquote ^= 1; inquote ^= 1;
} }
#if(0) /* implement backslashed quotes for 2.4 */
/* implement backslashed quotes for 2.4 */ if(!xa23 && c=='\\') quotebs=1; else quotebs=0;
if(c=='\\') quotebs=1; else quotebs=0;
#endif
} else { } else {
/* in comment */ /* in comment */
/* check for end of comment */ /* check for end of comment */
/* note: incomment only set true if not quoted, and quote not changed in comment */ /* note: for xa2.3, incomment only set true if not quoted, and quote not changed in comment */
if((!inquote) && (c=='*')) if((!inquote || !xa23) && (c=='*'))
{ {
if((d=getc(fp))!='/') { if((d=getc(fp))!='/') {
d_isvalid = 1; d_isvalid = 1;
@ -1075,6 +1227,11 @@ int rgetc(FILE *fp)
return(c-'\t'?c:' '); 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) int fgetline(char *t, int len, int *rlen, FILE *fp)
{ {
static int c,i; static int c,i;

View File

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

View File

@ -30,22 +30,30 @@
#include "xao.h" #include "xao.h"
#include "xau.h" #include "xau.h"
#undef DEBUG_RELOC
File *afile = NULL; File *afile = NULL;
int rmode = RMODE_RELOC; int rmode = RMODE_RELOC;
/*
int r_set(int pc, int afl, int l) { 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_TEXT) return rt_set(pc,afl,l,0);
if(segment==SEG_DATA) return rd_set(pc,afl,l,0); if(segment==SEG_DATA) return rd_set(pc,afl,l,0);
return 0; return 0;
} }
*/
int u_set(int pc, int afl, int label, int l) { int u_set(int pc, int afl, int label, int l) {
/*printf("set relocation @$%04x, l=%d, afl=%04x, segment=%d, label=%d\n", #ifdef DEBUG_RELOC
pc, l, afl,segment, label);*/ printf("set relocation @$%04x, l=%d, afl=%04x, segment=%d, label=%d\n",
if((afl & A_FMASK) == (SEG_UNDEF<<8)) pc, l, afl,segment, label);
#endif
if(((afl & A_FMASK) == (SEG_UNDEF<<8))
|| ((afl & A_FMASK) == (SEG_UNDEFZP<<8))
) {
label = u_label(label); /* set label as undefined */ label = u_label(label); /* set label as undefined */
}
if(segment==SEG_TEXT) return rt_set(pc,afl,l,label); if(segment==SEG_TEXT) return rt_set(pc,afl,l,label);
if(segment==SEG_DATA) return rd_set(pc,afl,l,label); if(segment==SEG_DATA) return rd_set(pc,afl,l,label);
return 0; return 0;
@ -77,7 +85,9 @@ int rt_set(int pc, int afl, int l, int lab) {
/*printf("Warning: byte relocation in word value at PC=$%04x!\n",pc);*/ /*printf("Warning: byte relocation in word value at PC=$%04x!\n",pc);*/
} }
if(l==1 && ((afl&A_MASK)==A_ADR)) { 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);*/ /*printf("afl=%04x\n",afl);*/
errout(W_ADRRELOC); errout(W_ADRRELOC);
} }
@ -147,10 +157,16 @@ int rt_write(FILE *fp, int pc) {
} }
fputc(pc2-pc, fp); fputc(pc2-pc, fp);
pc=pc2; pc=pc2;
fputc((afl>>8)&255, fp); if((afile->rt.rlist[p].afl&A_FMASK)==(SEG_UNDEFZP<<8)) {
if((afile->rt.rlist[p].afl&A_FMASK)==(SEG_UNDEF<<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 & 255, fp);
fputc((afile->rt.rlist[p].lab>>8) & 255, fp); fputc((afile->rt.rlist[p].lab>>8) & 255, fp);
}
} }
if((afl&A_MASK)==A_HIGH) fputc(afl&255,fp); if((afl&A_MASK)==A_HIGH) fputc(afl&255,fp);
} }

View File

@ -25,7 +25,7 @@
extern File *alloc_file(void); extern File *alloc_file(void);
/* jumps to r[td]_set, depending on segment */ /* 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 u_set(int pc, int reloc, int label, int len);
int rt_set(int pc, int reloc, int len, int label); 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); fputc(pc2-pc, fp);
pc=pc2; pc=pc2;
fputc((afl>>8)&255, fp); if((afile->rd.rlist[p].afl&A_FMASK)==(SEG_UNDEFZP<<8)) {
if((afile->rd.rlist[p].afl&A_FMASK)==(SEG_UNDEF<<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 & 255, fp);
fputc((afile->rd.rlist[p].lab>>8) & 255, fp); fputc((afile->rd.rlist[p].lab>>8) & 255, fp);
} }
}
if((afl&A_MASK)==A_HIGH) fputc(afl&255,fp); if((afl&A_MASK)==A_HIGH) fputc(afl&255,fp);
} }
p=afile->rd.rlist[p].next; 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; extern int dsb_len;
int t_p1(signed char *s, signed char *t, int *ll, int *al); 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); 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__ */ #endif /* __XA65_XAT_H__ */

View File

@ -1,6 +1,6 @@
/* xa65 - 65xx/65816 cross-assembler and utility suite /* xa65 - 65xx/65816 cross-assembler and utility suite
* *
* Copyright (C) 1989-1997 André Fachat (a.fachat@physik.tu-chemnitz.de) * Copyright (C) 1989-1997 André Fachat (fachat@web.de)
* *
* Undefined label tracking module (also see xal.c) * Undefined label tracking module (also see xal.c)
* *
@ -27,15 +27,13 @@
#include "xah.h" #include "xah.h"
#include "xal.h" #include "xal.h"
/* #undef DEBUG_UNDEF
static int *ulist = NULL;
static int un = 0;
static int um = 0;
*/
int u_label(int labnr) { int u_label(int labnr) {
int i; int i;
/*printf("u_label: %d\n",labnr);*/ #ifdef DEBUG_UNDEF
printf("u_label: %d\n",labnr);
#endif
if(!afile->ud.ulist) { if(!afile->ud.ulist) {
afile->ud.ulist = malloc(200*sizeof(int)); afile->ud.ulist = malloc(200*sizeof(int));
if(afile->ud.ulist) afile->ud.um=200; if(afile->ud.ulist) afile->ud.um=200;

View File

@ -1,13 +1,19 @@
This is a directory of test suites for complex or pathological cases that This is a directory of test suites for complex or pathological cases that
have been repaired (?) in the current version. It is primarily for internal have been repaired (?) in the current version. It is primarily for internal
testing, but is here for your interest. testing, but is here for your interest. It requires a reasonably compatible
`make` and Perl.
Starting with 2.3.6, you should not normally need to run these directly You can run specific tests from the main source directory with
unless 'make test' fails. If you do, use harness:
make test TESTS=test,test,test,...
or, if `make test` doesn't work right on your system, you can run the Perl
harness directly:
./harness -cc=... -cflags=... -make=... -tests=testdir,testdir,testdir,... ./harness -cc=... -cflags=... -make=... -tests=testdir,testdir,testdir,...
If -tests is omitted, all tests are run. If -tests is omitted, all tests are run.
Don't run the makefiles directly, if they exist; they may not work properly. Don't run the makefiles directly, if they exist; they may not work properly.
If a Makefile is not present, then the test harness assembles "test.s" and If a Makefile is not present, then the test harness assembles "test.s" and
compares it with "ok". compares it with "ok".
@ -33,9 +39,12 @@ ppstrings/ Don't substitute inside strings (unless -S)
neg_offset/ Test negative offsets/values with/without relocation neg_offset/ Test negative offsets/values with/without relocation
chppch/ Changing preprocessor characters (-p) chppch/ Changing preprocessor characters (-p)
charset/ Tests of when charsets should be honoured and when not charset/ Tests of when charsets should be honoured and when not
ca65/ Compatibility tests for ca65 compatibility
relmode/ tests concerning switches between segments and absolute mode
mvnmvp/ Test MVN MVP unusual addressing mode ('816) mvnmvp/ Test MVN MVP unusual addressing mode ('816)
dos51/ Regression test, label scoping, "real world code" dos51/ Regression test, label scoping, "real world code"
cpktest/ Regression test, label listing, "real world code" cpktest/ Regression test, label listing, "real world code"
listing/ Test of listing feature
op816/ Regression test for '816 opcodes (thanks Alessandro Gatti) op816/ Regression test for '816 opcodes (thanks Alessandro Gatti)
branch/ Branch range test branch/ Branch range test
masmcom/ Another test for -M that generates totally valid code masmcom/ Another test for -M that generates totally valid code
@ -46,6 +55,9 @@ math/ Math tests (currently divide by zero, thanks Frederic Cambus)
alxl/ Various '816 width tests (includes Samuel Falvo's test) alxl/ Various '816 width tests (includes Samuel Falvo's test)
pparity/ Tests of preprocessor macro arity (with Emil Johansson's test) pparity/ Tests of preprocessor macro arity (with Emil Johansson's test)
recucom/ Recursive comments test recucom/ Recursive comments test
aserror/ Tests of .assert and #error syntax/function
reset_segment/ Verifies conditions under which a segment is reset
expando/ Test of preprocessor expansion (thanks Tom Hargreaves)
Cameron Kaiser, André Fachat Cameron Kaiser, André Fachat

16
xa/tests/aserr/Makefile Normal file
View File

@ -0,0 +1,16 @@
default: test.s
@echo expected to fail....
../../xa -DBAD0 test.s || exit 0 && exit 1
../../xa -DBAD1 test.s || exit 0 && exit 1
../../xa -DBAD2 test.s || exit 0 && exit 1
../../xa -DBAD3 test.s || exit 0 && exit 1
../../xa -DBAD4 test.s || exit 0 && exit 1
../../xa -DBAD5 test.s || exit 0 && exit 1
@echo no more failures!
../../xa test.s
../hextool -cmp=ok < a.o65
clean:
rm -f a.o65

1
xa/tests/aserr/ok Normal file
View File

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

41
xa/tests/aserr/test.s Normal file
View File

@ -0,0 +1,41 @@
#if XA_MAJOR != 2
#error make sure this is up to date for future tests
#endif
#if XA_MINOR != 4
#error make sure this is up to date for future tests
#endif
* = $1000
#ifdef BAD0
.assert w=w, "what the"
#endif
w
#ifdef BAD1
#error bad1
#endif
#ifdef BAD2
.assert *<>$1000, "everything is bad"
#endif
lda #1
.assert *-2=w, "everything is really bad"
.assert w==w, "everything sucks"
.assert ((w & $ff00)>>8)=16, "everything is hideous"
#ifdef BAD3
.assert *==$1003, "everything is terrible"
#endif
#ifdef BAD4
.assert w!=w, "everything sucks and is terrible and hideous and bad"
#endif
#ifdef BAD5
#if XA_MAJOR != 1
#error I want a really old version
#endif
#endif

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

@ -0,0 +1,39 @@
#
# Makefile for tests
#
XA=../../xa
CA65=ca65
LD65=ld65
OBJS=unnamed1 unnamed2 escape2
# escape1 test only relevant if xa23 mode is on
#tests: unnamed1 unnamed2 escape1 escape2 clean
tests: $(OBJS)
# BSD make won't populate $< in these and GNU make doesn't like $>
unnamed1: unnamed1.a65
#${CA65} unnamed1.a65; ${LD65} -t none -o unnamed1.ca65 unnamed1.o; rm unnamed1.o
${XA} -XCA65 unnamed1.a65 -o $@
../hextool -cmp=unnamed1.ca65 < $@
unnamed2: unnamed2.a65
#${CA65} unnamed2.a65; ${LD65} -t none -o unnamed2.ca65 unnamed2.o; rm unnamed2.o
${XA} -XCA65 unnamed2.a65 -o $@ 2>a.err || true
../hextool -cmp=unnamed2.ca65 < $@
# add -XXA23 to actually test this
escape1: escape1.a65
${XA} escape1.a65 -o $@
../hextool -cmp=escape1.out < $@
escape2: escape2.a65
#${CA65} escape2.a65; ${LD65} -t none -o escape2.ca65 escape2.o; rm escape2.o
${XA} -XCA65 escape2.a65 -o $@ 2>a.err || true
../hextool -cmp=escape2.ca65 < $@
clean:
rm -f *.err a.o65 $(OBJS)

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

@ -1 +1 @@
©A©A1234512345"''" ©A©A1234512345"''"n

View File

@ -7,10 +7,10 @@
.asc "12345" .asc "12345"
.asc '12345' .asc '12345'
.asc "^"" ; ^ is escape character .asc "\"" ; \ is escape character
.asc '^'' .asc '\''
.asc "'" .asc "'"
.asc '"' .asc '"'
.asc "^n" .asc "\n"

View File

@ -1,10 +1,10 @@
default: default:
../../xa -l test.l -o test.o pack_eng.a65 ../../xa -l test.l -o test.o pack_eng.a65
cmp test.l english.l || exit 1 ../hextool -cmp=test.l < english.l || exit 1
../hextool -cmp=eng.ok < test.o ../hextool -cmp=eng.ok < test.o
../../xa -l test.l -o test.o pack_ger.a65 ../../xa -l test.l -o test.o pack_ger.a65
cmp test.l deutsch.l || exit 1 ../hextool -cmp=test.l < deutsch.l || exit 1
../hextool -cmp=de.ok < test.o ../hextool -cmp=de.ok < test.o
clean: clean:
rm -f *.o test.l rm -f *.o test.l

Binary file not shown.

1
xa/tests/expando/ok Normal file
View File

@ -0,0 +1 @@


23
xa/tests/expando/test.s Normal file
View File

@ -0,0 +1,23 @@
PBI=6
#define NIB(x) PBI+((x&1)>>0), \
PBI+((x&2)>>1), \
PBI+((x&4)>>2), \
PBI+((x&8)>>3)
tab0
.byt NIB(10),NIB(12),NIB(0), NIB(0)
.byt NIB(10),NIB(12),NIB(15),NIB(0)
.byt NIB(10),NIB(12),NIB(0), NIB(15)
.byt NIB(10),NIB(12),NIB(15),NIB(15)
; oh well.
tab1
.byt PBI+0,PBI+1,PBI+0,PBI+1,PBI+0,PBI+0,PBI+1,PBI+1
.byt PBI+0,PBI+0,PBI+0,PBI+0,PBI+0,PBI+0,PBI+0,PBI+0
.byt PBI+0,PBI+1,PBI+0,PBI+1,PBI+0,PBI+0,PBI+1,PBI+1
.byt PBI+1,PBI+1,PBI+1,PBI+1,PBI+0,PBI+0,PBI+0,PBI+0
.byt PBI+0,PBI+1,PBI+0,PBI+1,PBI+0,PBI+0,PBI+1,PBI+1
.byt PBI+0,PBI+0,PBI+0,PBI+0,PBI+1,PBI+1,PBI+1,PBI+1
.byt PBI+0,PBI+1,PBI+0,PBI+1,PBI+0,PBI+0,PBI+1,PBI+1
.byt PBI+1,PBI+1,PBI+1,PBI+1,PBI+1,PBI+1,PBI+1,PBI+1

View File

@ -1,11 +1,21 @@
#!/usr/bin/perl -s #!/usr/bin/perl -s
$make ||= "make";
$cc ||= "cc"; $cc ||= "cc";
$make ||= "make";
$cflags ||= ''; $cflags ||= '';
$ENV{'MAKE'} = $make; $makeflags ||= '';
# defeat multiple jobs, this doesn't do parallel right now
#$make =~ s/-j\d*(\s|$)//;
#$make =~ s/--jobserver-[^\s]+//;
#$makeflags =~ s/-j\d*(\s|$)//;
#$makeflags =~ s/--jobserver-[^\s]+//;
$ENV{'CC'} = $cc; $ENV{'CC'} = $cc;
$ENV{'MAKE'} = $make;
$ENV{'CFLAGS'} = $cflags; $ENV{'CFLAGS'} = $cflags;
$ENV{'MFLAGS'} = $makeflags;
$ENV{'MAKEFLAGS'} = $makeflags;
$|++; $|++;
$ntests = 0; $ntests = 0;
@ -16,8 +26,7 @@ print <<"EOF";
CC = $cc CC = $cc
CFLAGS = $cflags CFLAGS = $cflags
MAKE = $make MAKE = $make
tests to run: $dtests MAKEFLAGS = $makeflags
EOF EOF
# Get a list of all directories. If there is a Makefile there, do it. # Get a list of all directories. If there is a Makefile there, do it.
@ -25,9 +34,26 @@ EOF
# Otherwise, do nothing (acknowledge and ignore directories we don't grok). # Otherwise, do nothing (acknowledge and ignore directories we don't grok).
opendir(D, ".") || die("test harness failed: $!\n"); opendir(D, ".") || die("test harness failed: $!\n");
W: while($x = readdir(D)) { while($x = readdir(D)) {
next W if ($x =~ /^\./); next if ($x =~ /^\./ || $x =~ /\s/);
next W if (length($tests) && ($tests !~ /$x/)); next if (length($tests) && ($tests !~ /$x/));
next if (! -d $x);
if (-r "$x/Makefile") {
push(@mtests, $x);
} else {
push(@stests, $x);
}
}
closedir(D);
@tests = ();
push(@tests, sort @mtests) if (scalar(@mtests));
push(@tests, sort @stests) if (scalar(@stests));
print "matching tests: ";
print join(",", @tests);
print "\n\n";
W: foreach $x (@tests) {
next W if (!chdir($x)); next W if (!chdir($x));
$x = substr($x . " " . ("." x 79), 0, 50); $x = substr($x . " " . ("." x 79), 0, 50);
print STDOUT "$x > "; print STDOUT "$x > ";
@ -58,7 +84,6 @@ W: while($x = readdir(D)) {
} }
chdir(".."); chdir("..");
} }
closedir(D);
print STDOUT "=" x 79, "\n"; print STDOUT "=" x 79, "\n";
if ($ntests) { # ntestacy is a terrible thing if ($ntests) { # ntestacy is a terrible thing
print STDOUT "\n## ALL SELECTED TESTS PASS ($dtests, n=$ntests) ##\n"; print STDOUT "\n## ALL SELECTED TESTS PASS ($dtests, n=$ntests) ##\n";

3
xa/tests/ldoreloc/10.s Normal file
View File

@ -0,0 +1,3 @@
jsr bla
loop: jmp loop
lda l1

6
xa/tests/ldoreloc/20.s Normal file
View File

@ -0,0 +1,6 @@
jsr bla
loop: jmp loop
lda #<loop
lda #>loop
lda #<l1
lda #>l1

2
xa/tests/ldoreloc/30.s Normal file
View File

@ -0,0 +1,2 @@
jsr bla
loop: jmp loop

2
xa/tests/ldoreloc/31.s Normal file
View File

@ -0,0 +1,2 @@
jsr loop
bla: jmp bla

4
xa/tests/ldoreloc/40.s Normal file
View File

@ -0,0 +1,4 @@
foo =$1234
jsr bla
loop: jmp loop

7
xa/tests/ldoreloc/41.s Normal file
View File

@ -0,0 +1,7 @@
jsr loop
bla: jmp bla
lda foo
lda #<foo
lda #>foo

8
xa/tests/ldoreloc/50.s Normal file
View File

@ -0,0 +1,8 @@
foo =$1234
jsr bla
loop: jmp loop
.data
bar .word bla

11
xa/tests/ldoreloc/51.s Normal file
View File

@ -0,0 +1,11 @@
jsr loop
bla: lda bar
.data
.word foo
.word bar
.byte <foo
.byte >foo

13
xa/tests/ldoreloc/60.s Normal file
View File

@ -0,0 +1,13 @@
.zero
ptr .word 0
.text
foo =$1234
lda ptr2
loop: jmp loop
.data
bar .word bla

15
xa/tests/ldoreloc/61.s Normal file
View File

@ -0,0 +1,15 @@
jsr loop
bla: lda ptr
lda #ptr
.zero
ptr2 .byt 0
.data
.word foo
.word bar
.byte <foo
.byte >foo

View File

@ -1,24 +1,130 @@
default: all default: all
all: t all: t1 t2 t10 t11 t20 t21 t30 t31 t40 t41 t50 t51 t60 t61 t62
1.o65: 1.s # BSD only has suffix rules
../../xa -R -c -o 1.o65 1.s
../hextool 1.o65 > 1.o65.hex
2.o65: 2.s .SUFFIXES: .o65 .hex
../../xa -R -c -o 2.o65 2.s
../hextool 2.o65 > 2.o65.hex #%.o65: %.s
.s.o65:
../../xa -R -c -o $@ $<
#%.hex: %.o65
.o65.hex:
../hextool $< > $@
linked.o65: 1.o65 2.o65 linked.o65: 1.o65 2.o65
../../ldo65 -o linked.o65 1.o65 2.o65 ../../ldo65 -o $@ 1.o65 2.o65
../hextool linked.o65 > linked.o65.hex
t: linked.o65 linked2.o65: 1.o65 2.o65
../../reloc65 -bt 32768 -xt -o t linked.o65 ../../ldo65 -o $@ 2.o65 1.o65
../hextool t > t.hex
../hextool -cmp=t < t.ok linked10.o65: 10.o65 2.o65
../../ldo65 -U -o $@ 10.o65 2.o65
linked11.o65: 10.o65 2.o65
../../ldo65 -U -o $@ 2.o65 10.o65
linked20.o65: 20.o65 2.o65
../../ldo65 -Ll1 -o $@ 2.o65 20.o65
linked21.o65: 20.o65 2.o65
../../ldo65 -L l1 -o $@ 20.o65 2.o65
linked22.o65: 20.o65 2.o65
../../ldo65 -o $@ 20.o65 2.o65 && exit 1 || exit 0
linked30.o65: 30.o65 31.o65
../../ldo65 -o $@ 30.o65 31.o65
linked31.o65: 30.o65 31.o65
../../ldo65 -o $@ 31.o65 30.o65
linked40.o65: 40.o65 41.o65
../../ldo65 -o $@ 40.o65 41.o65
linked41.o65: 40.o65 41.o65
../../ldo65 -o $@ 41.o65 40.o65
linked50.o65: 50.o65 51.o65
../../ldo65 -o $@ 50.o65 51.o65
linked51.o65: 50.o65 51.o65
../../ldo65 -o $@ 51.o65 50.o65
linked60.o65: 60.o65 61.o65
../../ldo65 -o $@ 60.o65 61.o65
linked61.o65: 60.o65 61.o65
../../ldo65 -o $@ 61.o65 60.o65
linked62.o65: 60.o65 61.o65
../../ldo65 -bd 65529 -bt 65523 -bz 255 -o $@ 61.o65 60.o65 && exit 1 || exit 0
# BSD make doesn't populate $< in these rules and GNU make doesn't like $>
t1: linked.o65
../../reloc65 -bt 32768 -xt -o $@ linked.o65
../hextool -cmp=$@ < t1.ok
t2: linked2.o65
../../reloc65 -bt 32768 -xt -o $@ linked2.o65
../hextool -cmp=$@ < t2.ok
t10: linked10.o65
../../reloc65 -bt 32768 -xt -o $@ linked10.o65
../hextool -cmp=$@ < t10.ok
t11: linked11.o65
../../reloc65 -bt 32768 -xt -o $@ linked11.o65
../hextool -cmp=$@ < t11.ok
t20: linked20.o65
../../reloc65 -bt 32768 -xt -o $@ linked20.o65
../hextool -cmp=$@ < t20.ok
t21: linked21.o65
../../reloc65 -bt 32768 -xt -o $@ linked21.o65
../hextool -cmp=$@ < t21.ok
t22: linked22.o65
# should fail, so no action
t30: linked30.o65
../../reloc65 -bt 32768 -xt -o $@ linked30.o65
../hextool -cmp=$@ < t30.ok
t31: linked31.o65
../../reloc65 -bt 32768 -xt -o $@ linked31.o65
../hextool -cmp=$@ < t31.ok
t40: linked40.o65
../../reloc65 -bt 32768 -xt -o $@ linked40.o65
../hextool -cmp=$@ < t40.ok
t41: linked41.o65
../../reloc65 -bt 32768 -xt -o $@ linked41.o65
../hextool -cmp=$@ < t41.ok
t50: linked50.o65
../../reloc65 -bt 32768 -bd 40960 -o $@ linked50.o65
../hextool -cmp=$@ < t50.ok
t51: linked51.o65
../../reloc65 -bt 32768 -bd 40960 -o $@ linked51.o65
../hextool -cmp=$@ < t51.ok
t60: linked60.o65
../../reloc65 -bt 32768 -bd 40960 -o $@ linked60.o65
../hextool -cmp=$@ < t60.ok
t61: linked61.o65
../../reloc65 -bt 32768 -bd 40960 -o $@ linked61.o65
../hextool -cmp=$@ < t61.ok
t62: linked62.o65
clean: clean:
rm -f *.o65 *.hex t rm -f *.o65 *.hex t1 t2 t10 t11 t20 t21 t30 t31 t40 t41 t50 t51 t60 t61

1
xa/tests/ldoreloc/t1.ok Normal file
View File

@ -0,0 +1 @@
€L€`

BIN
xa/tests/ldoreloc/t10.ok Normal file

Binary file not shown.

BIN
xa/tests/ldoreloc/t11.ok Normal file

Binary file not shown.

BIN
xa/tests/ldoreloc/t2.ok Normal file

Binary file not shown.

BIN
xa/tests/ldoreloc/t20.ok Normal file

Binary file not shown.

BIN
xa/tests/ldoreloc/t21.ok Normal file

Binary file not shown.

1
xa/tests/ldoreloc/t30.ok Normal file
View File

@ -0,0 +1 @@
€L€L €

1
xa/tests/ldoreloc/t31.ok Normal file
View File

@ -0,0 +1 @@
€L€L €

1
xa/tests/ldoreloc/t40.ok Normal file
View File

@ -0,0 +1 @@
<09>L<03> <03>L <09><>4<12>4<EFBFBD>

1
xa/tests/ldoreloc/t41.ok Normal file
View File

@ -0,0 +1 @@
<10>L<03><>4<12>4<EFBFBD> <03>L<10>

BIN
xa/tests/ldoreloc/t50.ok Normal file

Binary file not shown.

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