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
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
#
VERS = 2.4.0
CC = gcc
LD = gcc
# for testing. not to be used; build failures in misc/.
@ -37,8 +38,8 @@ killxa:
xa:
(cd src && LD=${LD} CC="${CC} ${CFLAGS}" ${MAKE})
load:
(cd loader && CC="${CC} ${CFLAGS}" ${MAKE})
#load:
# (cd loader && CC="${CC} ${CFLAGS}" ${MAKE})
uncpk:
(cd misc && CC="${CC} ${CFLAGS}" ${MAKE})
@ -54,11 +55,11 @@ mingw: clean
clean:
(cd src && ${MAKE} clean)
(cd loader && ${MAKE} clean)
#(cd loader && ${MAKE} clean)
(cd misc && ${MAKE} mrproper)
rm -f xa *.exe *.o65 *.s core
install: xa uncpk
install: all
$(MKDIR) $(BINDIR)
$(MKDIR) $(MANDIR)
$(INSTALL) xa reloc65 ldo65 file65 printcbm uncpk $(BINDIR)
@ -66,9 +67,14 @@ install: xa uncpk
#$(MKDIR) $(DOCDIR)/xa65
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 \
-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
(see COPYING).
The current version is 2.3.10, a bug fix to the long-lived 2.3.0, itself with
compatibility improvements and new man-based documentation. It also completed
the merge of the 65816 and 6502/R65C02 versions and thus the current xa can
generate code for all targets now.
The current version is 2.4.0, the first new feature release literally in
years. It builds upon the improvements in 2.3.x and its unified 6502/65816
assembler core by adding listing capability, greater flexibility with
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
@ -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
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
BASIC test) and file65, ldo65 and reloc65 for displaying, linking and
relocating o65 files in Andre's relocatable format (see doc/fileformats.txt).
The loader/ directory also has goodies for managing relocatable binaries.
BASIC test, now deprecated as of 2.4) and file65, ldo65 and reloc65 for
displaying, linking and relocating o65 files in Andre's relocatable format.
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).
@ -38,6 +47,8 @@ Fabian Nunez. For mingw, use
make mingw
(but do it from within MSYS2).
Similarly, Amiga and Atari ST compilation should still also function with
their particular compatible packages.

16
xa/TODO
View File

@ -1,10 +1,18 @@
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 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

View File

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

View File

@ -1,4 +1,4 @@
.TH LDO65 "1" "11 April 2006"
.TH LDO65 "1" "18 November 2023"
.SH NAME
ldo65 \- linker for o65 object files
@ -9,7 +9,7 @@ ldo65 \- linker for o65 object files
.SH DESCRIPTION
.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
but renamed to avoid conflicts with the
.B cc65
@ -32,9 +32,23 @@ man page for an explanation.
Set output filename. The default is
.BR a.o65 \&.
.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
Suppress writing of globals.
.TP
.B \-g name
Only export global
.BR name .
This option may be specified multiple times for multiple globals.
.TP
.B \-\-help
Show summary of options.
.TP

View File

@ -1,7 +1,17 @@
.TH PRINTCBM "1" "11 April 2006"
.TH PRINTCBM "1" "DEPRECATED"
.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
.B printcbm

View File

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

View File

@ -1,4 +1,4 @@
.TH UNCPK "1" "11 April 2006"
.TH UNCPK "1" "18 November 2023"
.SH NAME
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
xa \- 6502/R65C02/65816 cross-assembler
@ -18,6 +18,9 @@ further in this manual page.
.SH OPTIONS
.TP
.B \-E
Do not stop after 20 errors, but show all errors.
.TP
.B \-v
Verbose output.
.TP
@ -45,11 +48,22 @@ use the special filename
.BR \-
to output to standard output.
.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
Set errorlog filename, default is none.
Set errorlog filename; default is none.
.TP
.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
.BR dxa (1)
to reconstruct source.
@ -58,12 +72,70 @@ to reconstruct source.
Add cross-reference list to labellist (requires
.BR \-l ).
.TP
.B \-Xcompatset
Enables compatibility settings to become more (not fully!) compatible with other 6502 assemblers 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
Allow colons to appear in comments; for MASM compatibility. This does
not affect colon interpretation elsewhere.
This option is deprecated and will be removed in a future version; use
.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
.B \-R
Start assembler in relocating mode.
Start assembler in relocating mode, i.e. use segments.
.TP
.B \-U
Do not allow undefined labels in relocating mode.
.TP
.B \-Llabel
Defines
@ -121,27 +193,12 @@ Characters may need to be quoted for your shell (example:
).
.TP
.B \-\-help
Show summary of options.
Show summary of options
.RB ( -?
is a synonym).
.TP
.B \-\-version
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
@ -177,9 +234,15 @@ decimal value
.TP
.B $234
hexadecimal value
.RB ( 0x234
accepted with
.BR -XC )
.TP
.B &123
octal
.RB ( 0123
accepted with
.BR -XC )
.TP
.B %010110
binary
@ -221,7 +284,14 @@ statements such as
.IP
.B * = $c000
.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
declare redefinition of a label, place a - (dash) before it, e.g.,
.IP
@ -251,6 +321,52 @@ as a linker; see
and
.BR LINKING .
.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
.B asl
and
@ -308,10 +424,14 @@ less than or equal to (7)
less than (7)
.TP
.B =
equal to (6)
equal to (6);
.B ==
also accepted
.TP
.B <> ><
does not equal (6)
does not equal (6);
.B !=
also accepted
.TP
.B &
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)
.TP
.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
command-line option).
.B This is required to specify any
.B 24-bit quantity!
command-line option, must not specify
.BR \-XCA65 )
.TP
.B `
force further optimization, even if the length of the instruction cannot
@ -422,8 +541,9 @@ comments, such that
.B ; a comment:lda #0
.LP
is understood as a comment followed by an opcode. To defeat this, use the
.B \-M
command line option to allow colons within comments. This does not apply to
.B \-XMASM
compatibility mode to allow colons within comments; this may become the
default in a future version. Colon statement separation does not apply to
.B /* */
and
.B //
@ -464,7 +584,7 @@ and
are synonymous, so you can mix things such as
.B .byt $43, 22, """a character string"""
and get the expected result. The string is subject to the current character
set, but the remaining bytes are inserted wtihout modification.
set, but the remaining bytes are inserted without modification.
.TP
.B .aasc """text1""","text2",...
Specifies a character string that is
@ -487,7 +607,8 @@ repetitions of
will be inserted into the assembled object. For example,
.B .dsb 5,$10
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
for how to use this pseudo-op to link multiple objects.
.TP
@ -496,8 +617,10 @@ Inlines a binary file without further interpretation specified by
.B filename
from offset
.B offset
to length
.BR length .
(relative to the beginning of the file)
for
.B length
bytes.
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
file's object. If
@ -518,10 +641,23 @@ a block, precede the label with
or precede it with
.B &
to declare it within the previous level only (or globally if you are only
one level deep). Sixteen levels of scoping are permitted.
one level deep). Sixteen levels of scoping are permitted.
.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
.B \&.)
Closes a block.
.B .bend
or
.B .endproc
are accepted as synonyms.
.TP
.B \.as \.al \.xs \.xl
Only relevant in 65816 mode (with the
@ -548,31 +684,98 @@ and
generate errors if
.B \-w
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
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
scope of this manpage, as it is currently a format in flux. Documentation
on the proposed v1.2 format is in
.B doc/fileformat.txt
within the
.B xa
installation directory.
scope of this manpage; see
.B http://www.6502.org/users/andre/o65/
for the most current specification.
.TP
.B .text .data .bss .zero
These pseudo-ops switch between the different segments, .text being the actual
code section, .data being the data segment, .bss being uninitialized label
space for allocation and .zero being uninitialized zero page space for
allocation. In .bss and .zero, only labels are evaluated. These pseudo-ops
are valid in relative and absolute modes.
These pseudo-ops switch between the different segments,
.B .text
being the actual code section,
.B .data
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
.B .align value
Aligns the current segment to a byte boundary (2, 4 or 256) as specified by
.B
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.
.TP
.B .fopt type,value1,value2,value3,...
.B .fopt type, value1, value2, value3, ...
Acts like
.B .byt/.asc
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
are interpreted as values to insert. Any number of values may be specified,
and may also be strings.
.TP
.B .import label1, label2, label3, ...
Defines the given labels as global labels which are imported and resolved during
the link stage, 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
@ -665,8 +879,19 @@ may interpret too early until the file actually gets to
.B xa
itself for processing.
.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
.B #include """filename"""
Inserts the contents of file
@ -691,6 +916,9 @@ Computes the value of expression
.B expression
and prints it into the errorlog file.
.TP
.B #error message
Displays the message as an error and terminates assembly.
.TP
.B #define DEFINE text
Equates macro
.B DEFINE
@ -724,12 +952,6 @@ satisfied, then the source code between the directive and its terminating
.B #endif
are expunged and not assembled. Up to fifteen levels of nesting are supported.
.TP
.B #endif
Closes a conditional block.
.TP
.B #else
Implements alternate path for a conditional block.
.TP
.B #ifdef DEFINE
True only if macro
.B DEFINE
@ -760,6 +982,12 @@ is defined
.I and
assigned with a value.
.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
Unclosed conditional blocks at the end of included files generate warnings;
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
instruction set to do so. Older versions of
.B xa
took a single 16-bit absolute value. Since 2.3.7, the standard syntax is
now accepted and the old syntax is deprecated (a warning will be generated).
took a single 16-bit absolute value. As of 2.4.0, this old syntax is
no longer accepted.
.LP
Forward-defined labels -- that is, labels that are defined after the current
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
use in addressing mode situations where no ambiguity exists, such as indirect
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"
.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,
Cameron Kaiser. The official maintainer is Cameron Kaiser.
.SH 30 YEARS OF XA
.SH OVER 30 YEARS OF XA
Yay us?
.SH WEBSITE

View File

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

View File

@ -48,6 +48,8 @@ int rompar = 0;
int romoff = 0;
int labels = 0;
int verbose = 0;
void usage(FILE *fp)
{
fprintf(fp,
@ -62,13 +64,14 @@ void usage(FILE *fp)
" 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"
" 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"
" --help display this help and exit\n");
}
int main(int argc, char *argv[]) {
int i = 1, n, mode, hlen;
int i, j, n, mode, hlen;
FILE *fp;
char *aligntxt[4]= {"[align 1]","[align 2]","[align 4]","[align 256]"};
if(argc<=1) {
@ -76,12 +79,14 @@ int main(int argc, char *argv[]) {
exit(1);
}
if (strstr(argv[1], "--help")) {
i = 1;
if (strstr(argv[i], "--help") || strstr(argv[i], "-?")) {
usage(stdout);
exit(0);
}
if (strstr(argv[1], "--version")) {
if (strstr(argv[i], "--version")) {
version(programname, progversion, author, copyright);
exit(0);
}
@ -90,11 +95,12 @@ int main(int argc, char *argv[]) {
if(argv[i][0]=='-') {
/* process options */
switch(argv[i][1]) {
case 'V':
labels = 1;
break;
case 'v':
printf("file65: Version 0.2\n");
j = 1;
while (argv[i][j] == 'v') {
verbose ++;
j++;
}
break;
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(" stack size $%04x bytes %s\n", hdr[25]*256+hdr[24],
(hdr[25]*256+hdr[24])==0?"(i.e. unknown)":"");
if(labels) {
if(verbose) {
read_options(fp);
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 c, l=0;
int c, d, l=0;
unsigned char tb[256];
c=fgetc(fp); l++;
while(c && c!=EOF) {
c&=255;
fread(tb, 1, c-1, fp);
d = fread(tb, 1, c-1, fp);
if(labels) print_option(tb, c);
l+=c;
c=fgetc(fp);
@ -247,11 +253,17 @@ int read_options(FILE *fp) {
int print_labels(FILE *fp, int offset) {
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);
*/
fseek(fp, offset, SEEK_CUR);
// -----------------------------------------------------------
// print undefined labels
nud = (fgetc(fp) & 0xff);
nud += ((fgetc(fp) << 8) & 0xff00);
@ -269,25 +281,59 @@ printf("print_labels:offset=%d\n",offset);
printf("\n");
}
// ---------------------------------------------------------
// skip relocation tables
// two tables, one for text one for data
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);
while(c && c!=EOF) {
c&= 0xff;
while(c == 255 && c!= EOF) {
offset += 254;
c=fgetc(fp);
if(c==EOF) break;
c&= 0xff;
}
if(c==EOF) break;
offset += c;
c=fgetc(fp);
if( (c & 0xe0) == 0x40 ) fgetc(fp);
if( (c & 0x07) == 0 ) { fgetc(fp); fgetc(fp); }
if( (c & 0xe0) == 0x40 ) {
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);
}
if (verbose > 1) {
printf("\n");
}
}
// ---------------------------------------------------------
// print global labels
nud = (fgetc(fp) & 0xff);
nud += ((fgetc(fp) << 8) & 0xff00);
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,
"Usage: %s [OPTION]... [FILE]...\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"
" --version output version information and exit\n"
" --help display this help and exit\n",
@ -62,7 +64,7 @@ int main(int argc, char *argv[])
exit(1);
}
if (strstr(argv[1], "--help")) {
if (strstr(argv[1], "--help") || strstr(argv[1], "-?")) {
usage(stdout);
exit(0);
}

View File

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

View File

@ -65,7 +65,7 @@ int main(int argc, char *argv[])
exit(1);
}
if (strstr(argv[1], "--help")) {
if (strstr(argv[1], "--help") || strstr(argv[1], "-?")) {
usage(stdout);
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=-g -std=c11 -D_GNU_SOURCE
#LD = ${CC}
#LDFLAGS = "-lc"

View File

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

View File

@ -45,6 +45,7 @@
#include "xar.h"
#include "xat.h"
#include "xacharset.h"
#include "xalisting.h"
#include "version.h"
@ -55,27 +56,34 @@
#define ANZWARN 13
#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 copyright "Copyright (C) 1989-2023 Andre Fachat, Jolse Maginnis, David Weinehall\nand Cameron Kaiser."
/* exported globals */
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 romable = 0;
int romaddr = 0;
int noglob = 0;
int showblk = 0;
int crossref = 0;
int undefok = 0; // -R only accepts -Llabels; with -U all undef'd labels are ok in -R mode
char altppchar;
/* local variables */
static char out[MAXLINE];
static time_t tim1, tim2;
static FILE *fpout, *fperr, *fplab;
static FILE *fpout, *fperr, *fplab, *fplist;
static int ner = 0;
static int ner_max = 20;
static int align = 1;
@ -86,12 +94,14 @@ static int x_init(void);
static int pass1(void);
static int pass2(void);
static int puttmp(int);
static int puttmpw(int);
static int puttmps(signed char *, int);
static void chrput(int);
static int xa_getline(char *);
static void lineout(void);
static long ga_p1(void);
static long gm_p1(void);
static int set_compat(char *compat_name);
/* text */
int memode,xmode;
@ -111,16 +121,18 @@ int main(int argc,char *argv[])
signed char *s=NULL;
char *tmpp;
char *listformat = NULL;
int mifiles = 5;
int nifiles = 0;
int verbose = 0;
int oldfile = 0;
int no_link = 0;
char **ifiles;
char *ofile;
char *efile;
char *lfile;
char *printfile; /* print listing to this file */
char *ofile; /* output file */
char *efile; /* error listing goes there */
char *lfile; /* labels go here */
char *ifile;
char old_e[MAXLINE];
@ -161,7 +173,7 @@ int main(int argc,char *argv[])
exit(1);
}
if (strstr(argv[1], "--help")) {
if (strstr(argv[1], "--help") || strstr(argv[1], "-?")) {
usage(w65816, stdout);
exit(0);
}
@ -174,6 +186,7 @@ int main(int argc,char *argv[])
ofile="a.o65";
efile=NULL;
lfile=NULL;
printfile=NULL;
if(pp_init()) {
logout("fatal: pp: no memory!");
@ -192,6 +205,9 @@ int main(int argc,char *argv[])
while(i<argc) {
if(argv[i][0]=='-') {
switch(argv[i][1]) {
case 'E':
ner_max = 0;
break;
case 'p':
/* intentionally not allowing an argument to follow with a
space to avoid - being seen as the alternate
@ -209,11 +225,21 @@ int main(int argc,char *argv[])
"warning: extra characters to -p ignored\n");
break;
case 'M':
fprintf(stderr, "Warning: -M is deprecated (use -XMASM) and will be removed in a future version\n");
masm = 1; /* MASM compatibility mode */
break;
case 'S':
ppinstr = 1; /* preprocessor substitution in strings ok */
fprintf(stderr, "Warning: -S is deprecated and will be removed in 2.4+!\n");
case 'X': /* compatibility across assemblers... */
{
char *name = NULL;
if (argv[i][2] == 0) {
name = argv[++i];
} else {
name = argv[i]+2;
}
if (set_compat(name) < 0) {
fprintf(stderr, "Compatibility set '%s' unknown - ignoring! (check case?)\n", name);
}
}
break;
case 'O': /* output charset */
{
@ -256,6 +282,9 @@ int main(int argc,char *argv[])
case 'R':
relmode = 1;
break;
case 'U':
undefok = 1;
break;
case 'D':
s = (signed char*)strstr(argv[i]+2,"=");
if(s) *s = ' ';
@ -280,10 +309,6 @@ int main(int argc,char *argv[])
case 'B':
showblk = 1;
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':
if(argv[i][2]==0) {
if (i + 1 < argc) reg_include(argv[++i]);
@ -295,6 +320,20 @@ int main(int argc,char *argv[])
reg_include(argv[i]+2);
}
break;
case 'P':
if(argv[i][2]==0) {
printfile=argv[++i];
} else {
printfile=argv[i]+2;
}
break;
case 'F':
if (argv[i][2]==0) {
listformat = argv[++i];
} else {
listformat = argv[i]+2;
}
break;
case 'o':
if(argv[i][2]==0) {
if (i + 1 < argc) ofile=argv[++i];
@ -377,17 +416,14 @@ int main(int argc,char *argv[])
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 (printfile!=NULL && !strcmp(printfile, "-")) {
printfile=NULL;
fplist = stdout;
} else {
fplist= printfile ? xfopen(printfile,"w") : NULL;
}
fplab= lfile ? xfopen(lfile,"w") : NULL;
fperr= efile ? xfopen(efile,"w") : NULL;
if(!strcmp(ofile,"-")) {
@ -401,6 +437,8 @@ int main(int argc,char *argv[])
exit(1);
}
if(verbose) fprintf(stderr, "%s\n",copyright);
if(1 /*!m_init()*/)
{
if(1 /*!b_init()*/)
@ -414,6 +452,8 @@ int main(int argc,char *argv[])
/* if(fperr) fprintf(fperr,"%s\n",copyright); */
if(verbose) logout(ctime(&tim1));
list_setfile(fplist);
/* Pass 1 */
pc[SEG_ABS]= 0; /* abs addressing */
@ -438,7 +478,7 @@ int main(int argc,char *argv[])
if(verbose) logout(out);
er=pp_open(ifile);
puttmp(0);
puttmpw(0);
puttmp(T_FILE);
puttmp(0);
puttmp(0);
@ -491,6 +531,8 @@ int main(int argc,char *argv[])
{
if(verbose) logout("xAss65: Pass 2:\n");
list_start(listformat);
seg_pass2();
if(relmode) {
@ -502,6 +544,8 @@ int main(int argc,char *argv[])
r_mode(RMODE_ABS);
}
er=pass2();
list_end();
}
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(fplist && fplist!=stdout) fclose(fplist);
if(fperr) fclose(fperr);
if(fplab) fclose(fplab);
if(fpout) fclose(fpout);
if(fpout && fpout!=stdout) fclose(fpout);
} else {
logout("fatal: x: no memory!\n");
@ -534,7 +579,12 @@ int main(int argc,char *argv[])
if(ner || er)
{
if (ner_max > 0) {
fprintf(stderr, "Break after %d error%c\n",ner,ner?'s':0);
} else {
/* ner_max==0, i.e. show all errors */
fprintf(stderr, "End after %d error%c\n",ner,ner?'s':0);
}
/*unlink();*/
if(ofile) {
unlink(ofile);
@ -649,39 +699,41 @@ static int pass2(void)
filep=&datei;
afile->mn.tmpe=0L;
while(ner<20 && afile->mn.tmpe<afile->mn.tmpz)
while((ner_max==0 || ner<ner_max) && afile->mn.tmpe<afile->mn.tmpz)
{
l=afile->mn.tmp[afile->mn.tmpe++];
// get the length of the entry (now two byte - need to handle the sign)
l = 255 & afile->mn.tmp[afile->mn.tmpe++];
l |= afile->mn.tmp[afile->mn.tmpe++] << 8;
ll=l;
//printf("%p: l=%d first=%02x\n", afile->mn.tmp+afile->mn.tmpe-1, l, 0xff & afile->mn.tmp[afile->mn.tmpe]);
if(!l)
{
if(afile->mn.tmp[afile->mn.tmpe]==T_LINE)
{
datei.fline=(afile->mn.tmp[afile->mn.tmpe+1]&255)+(afile->mn.tmp[afile->mn.tmpe+2]<<8);
afile->mn.tmpe+=3;
list_line(datei.fline); /* set line number of next listing output */
} else
if(afile->mn.tmp[afile->mn.tmpe]==T_FILE)
{
// copy the current line number from the current file descriptor
datei.fline=(afile->mn.tmp[afile->mn.tmpe+1]&255)+(afile->mn.tmp[afile->mn.tmpe+2]<<8);
// copy the pointer to the file name in the current file descriptor
// Note: the filename in the current file descriptor is separately malloc'd and
// thus save to store the pointer
memcpy(&datei.fname, afile->mn.tmp+afile->mn.tmpe+3, sizeof(datei.fname));
afile->mn.tmpe+=3+sizeof(datei.fname);
/*
datei.fname = malloc(strlen((char*) afile->mn.tmp+afile->mn.tmpe+3)+1);
if(!datei.fname) {
fprintf(stderr,"Oops, no more memory\n");
exit(1);
}
strcpy(datei.fname,(char*) afile->mn.tmp+afile->mn.tmpe+3);
afile->mn.tmpe+=3+strlen(datei.fname);
*/
list_filename(datei.fname); /* set file name of next listing output */
}
} else
{
/* do not attempt address mode optimization on pass 2 */
er=t_p2(afile->mn.tmp+afile->mn.tmpe,&ll,1,&al);
/* t_p2_l() includes the listing call to do_listing() */
er=t_p2_l(afile->mn.tmp+afile->mn.tmpe,&ll,&al);
if(er==E_NOLINE)
{
} else
@ -786,16 +838,14 @@ fprintf(stderr, "offset = %i length = %i fstart = %i flen = %i charo = %c\n",
static int pass1(void)
{
signed char o[MAXLINE];
int l,er,temp_er,al;
signed char o[2*MAXLINE]; /* doubled for token listing */
int l,er,al;
memode=0;
xmode=0;
tlen=0;
ner=0;
temp_er = 0;
/*FIXIT*/
while(!(er=xa_getline(s)))
{
@ -808,7 +858,7 @@ static int pass1(void)
case SEG_ZERO: zlen += al; break;
}
/*printf(": er= %d, l=%d, tmpz=%d\n",er,l,tmpz); */
//printf(": er= %d, l=%d\n",er,l);
if(l)
{
@ -816,14 +866,14 @@ static int pass1(void)
{
if(er==E_OKDEF)
{
if(!(er=puttmp(l)))
if(!(er=puttmpw(l)))
er=puttmps(o,l);
} else
if(er==E_NOLINE)
er=E_OK;
} else
{
if(!(er=puttmp(-l)))
if(!(er=puttmpw(-l)))
er=puttmps(o,l);
}
}
@ -860,6 +910,7 @@ static void usage(int default816, FILE *fp)
programname);
fprintf(fp,
" -v verbose output\n"
" -E do not break after 20 errors, but show all\n"
" -C no CMOS-opcodes\n"
" -W no 65816-opcodes%s\n"
" -w allow 65816-opcodes%s\n",
@ -873,11 +924,19 @@ static void usage(int default816, FILE *fp)
fprintf(fp,
" -e filename sets errorlog filename, default is none\n"
" -l filename sets labellist filename, default is none\n"
" -P filename sets filename for listing, default is none, '-' is stdout\n"
" -F format sets format for listing, default is plain, 'html' is current only other\n"
" supported format\n"
" -r adds crossreference list to labellist (if `-l' given)\n"
" -M allow ``:'' to appear in comments for MASM compatibility\n"
" -R start assembler in relocating mode\n");
" (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,
" -Llabel defines `label' as absolute, undefined label even when linking\n"
" -p<c> replace preprocessor char '#' with custom, e.g. '-p!' replaces it with '!'\n"
" -b? addr set segment base address to integer value addr\n"
" `?' stands for t(ext), d(ata), b(ss) and z(ero) segment\n"
" (address can be given more than once, last one is used)\n");
@ -893,104 +952,89 @@ static void usage(int default816, FILE *fp)
" -Idir add directory `dir' to include path (before XAINPUT)\n"
" --version output version information 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[] = {
"Syntax",
"Label already defined",
"Label not defined",
"Label table full",
"Label expected",
"Out of memory",
"Illegal opcode",
"Wrong addressing mode",
"Branch out of range",
"Overflow",
"Division by zero",
"Pseudo-opcode expected",
"Block stack overflow",
"File not found",
"End of file",
"Unmatched block close",
"NoBlk",
"NoKey",
"NoLine",
"OKDef",
"DSB",
"NewLine",
"NewFile",
"CMOS instruction used with -C",
"pp:Wrong parameter count",
"Illegal pointer arithmetic",
"Illegal segment",
"File header option too long",
"File option not at file start (when ROM-able)",
"Illegal align value",
"65816 mode used/required",
"Exceeded recursion limit for label evaluation",
"Unresolved preprocessor directive at end of file",
"Data underflow",
"Illegal quantity",
".bin",
"Syntax", // E_SYNTAX =-1
"Label already defined", // E_LABDEF =-2
"Label not defined", // E_NODEF =-3
"Label table full", // E_LABFULL =-4
"Label expected", // E_LABEXP =-5
"Out of memory", // E_NOMEM =-6
"Illegal opcode", // E_ILLCODE =-7
"Wrong addressing mode", // E_ADRESS =-8
"Branch out of range", // E_RANGE =-9
"Overflow", // E_OVERFLOW =-10
"Division by zero", // E_DIV =-11
"Pseudo-opcode expected", // E_PSOEXP =-12
"Block stack overflow", // E_BLKOVR =-13
"File not found", // E_FNF =-14
"End of file", // E_EOF =-15
"Unmatched block close", // E_BLOCK =-16
"NoBlk", // E_NOBLK =-17
"NoKey", // E_NOKEY =-18
"NoLine", // E_NOLINE =-19
"OKDef", // E_OKDEF =-20
"DSB", // E_DSB =-21
"NewLine", // E_NEWLINE =-22
"NewFile", // E_NEWFILE =-23
"CMOS instruction used with -C", // E_DMOS =-24
"pp:Wrong parameter count", // E_ANZPAR =-25
"Illegal pointer arithmetic (-26)", // E_ILLPOINTER =-26
"Illegal segment", // E_ILLSEGMENT =-27
"File header option too long", // E_OPTLEN =-28
"File option not at file start (when ROM-able)", // E_ROMOPT =-29
"Illegal align value", // E_ILLALIGN =-30
"65816 mode used/required", // E_65816 =-31
"Exceeded recursion limit for label evaluation", // E_ORECMAC =-32
"Unresolved preprocessor directive at end of file", // E_OPENPP =-33
"Data underflow", // E_OUTOFDATA =-34
"Illegal quantity", // E_ILLQUANT =-35
".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 */
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"", // -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 */
"Cutting word relocation in byte value",
"Byte relocation in word value",
"Illegal pointer arithmetic",
"Address access to low or high byte pointer",
"High byte access to low byte pointer",
"Low byte access to high byte pointer",
"Can't optimize forward-defined label; using absolute addressing",
"Open preprocessor directive at end of file (intentional?)",
"Included binary data exceeds 64KB",
"Included binary data exceeds 16MB",
"MVN/MVP $XXXX syntax is deprecated and will be removed",
"Cutting word relocation in byte value", // W_ADRRELOC =-65
"Byte relocation in word value", // W_BYTERELOC =-66
"Illegal pointer arithmetic (-66)", // E_WPOINTER =-67
"Address access to low or high byte pointer", // W_ADDRACC =-68
"High byte access to low byte pointer", // W_HIGHACC =-69
"Low byte access to high byte pointer", // W_LOWACC =-70
"Can't optimize forward-defined label; using absolute addressing", // W_FORLAB =-71
"Open preprocessor directive at end of file (intentional?)", // W_OPENPP =-72
"Included binary data exceeds 64KB", // W_OVER64K =-73
"Included binary data exceeds 16MB", // W_OVER16M =-74
"Subtracting pointer from constant not supported in -R mode", // W_SUBTRACT =-75
/* more placeholders */
"",
"",
"", // -76
"", // -77
};
@ -1013,7 +1057,9 @@ static int x_init(void)
static int puttmp(int c)
{
int er=E_NOMEM;
/*printf("puttmp: afile=%p, tmp=%p, tmpz=%d\n",afile, afile?afile->mn.tmp:0, afile?afile->mn.tmpz:0);*/
//printf("puttmp: %02x -> %p \n",0xff & c, afile->mn.tmp+afile->mn.tmpz);
if(afile->mn.tmpz<TMPMEM)
{
afile->mn.tmp[afile->mn.tmpz++]=c;
@ -1022,17 +1068,37 @@ static int puttmp(int c)
return(er);
}
static int puttmpw(int c)
{
int er=E_NOMEM;
//printf("puttmp: %02x -> %p \n",0xff & c, afile->mn.tmp+afile->mn.tmpz);
if(afile->mn.tmpz<TMPMEM-1)
{
afile->mn.tmp[afile->mn.tmpz++]= c & 0xff;
afile->mn.tmp[afile->mn.tmpz++]= (c >> 8) & 0xff;
er=E_OK;
}
return(er);
}
static int puttmps(signed char *s, int l)
{
int i=0,er=E_NOMEM;
// printf("puttmps %d bytes from %p to %p:", l, s, afile->mn.tmp+afile->mn.tmpz);
if(afile->mn.tmpz+l<TMPMEM)
{
while(i<l)
afile->mn.tmp[afile->mn.tmpz++]=s[i++];
while(i<l) {
//printf(" %02x", 0xff & s[i]);
afile->mn.tmp[afile->mn.tmpz++]=s[i++];
}
er=E_OK;
}
// printf("\n");
return(er);
}
@ -1062,25 +1128,19 @@ static int xa_getline(char *s)
if(ec==E_NEWLINE)
{
puttmp(0);
puttmpw(0);
puttmp(T_LINE);
puttmp((filep->fline)&255);
puttmp(((filep->fline)>>8)&255);
ec=E_OK;
puttmpw(filep->fline);
ec=E_OK;
}
else
if(ec==E_NEWFILE)
{
puttmp(0);
puttmpw(0);
puttmp(T_FILE);
puttmp((filep->fline)&255);
puttmp(((filep->fline)>>8)&255);
puttmpw(filep->fline);
puttmps((signed char*)&(filep->fname), sizeof(filep->fname));
/*
puttmps((signed char*)filep->fname,
1+(int)strlen(filep->fname));
*/
ec=E_OK;
}
} while(!ec && l[i]=='\0');
@ -1089,6 +1149,7 @@ static int xa_getline(char *s)
gl=0;
if(!ec || ec==E_EOF)
{
int startofline = 1;
do {
c=s[j]=l[i++];
@ -1096,21 +1157,42 @@ static int xa_getline(char *s)
hkfl^=1;
if (!comcom && !(hkfl&1) && c=='\'')
hkfl^=2;
if (c==';' && !hkfl)
if (c==';' && !hkfl) {
comcom = 1;
if (c=='\0')
break; /* hkfl = comcom = 0 */
if (c==':' && !hkfl && (!comcom || !masm)) {
gl=1;
break;
}
}
if (c=='\0') {
// end of line
break; /* hkfl = comcom = 0 */
}
if (c==':' && !hkfl) {
/* if the next char is a "=" - so that we have a ":=" - and we
we have ca65 compatibility, we ignore the colon */
// also check for ":+" and ":-"
if (((!startofline) && l[i]!='=' && l[i]!='+' && l[i]!='-') || !ca65 || comcom) {
/* but otherwise we check if it is in a comment and we have
MASM or CA65 compatibility, then we ignore the colon as well */
if(!comcom || !(masm || ca65)) {
/* we found a colon, so we keep the current line in memory
but return the part before the colon, and next time the part
after the colon, so we can parse C64 BASIC text assembler... */
gl=1;
break;
}
}
}
if (!isspace(c)) {
startofline = 0;
}
j++;
} while (c!='\0' && j<MAXLINE-1 && i<MAXLINE-1);
s[j]='\0';
} else
s[0]='\0';
#if 0
printf("got line: %s\n", s);
#endif
return(ec);
}
@ -1130,8 +1212,8 @@ static void lineout(void)
void errout(int er)
{
if (er<-ANZERR || er>-1) {
if(er>=-(ANZERR+ANZWARN) && er < -ANZERR) {
if (er<=-ANZERR || er>-1) {
if(er>=-(ANZERR+ANZWARN) && er <= -ANZERR) {
sprintf(out,"%s:line %d: %04x: Warning - %s\n",
filep->fname, filep->fline, pc[segment], ertxt[(-er)-1]);
} else {
@ -1167,3 +1249,37 @@ void logout(char *s)
fprintf(fperr,"%s",s);
}
/*****************************************************************/
typedef struct {
char *name;
int *flag;
} compat_set;
static compat_set compat_sets[] = {
{ "MASM", &masm },
{ "CA65", &ca65 },
{ "C", &ctypes },
{ "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 */
#define progmajor "2"
#define progminor "4"
#define progpatch "0"
#define progversion progmajor "." progminor "." progpatch
extern int ncmos, cmosfl, w65816, n65816;
extern int masm, nolink, ppinstr;
extern int masm, ca65, xa23, nolink, undefok;
extern int noglob;
extern int showblk;
extern int relmode;
extern int crossref;
extern int ctypes;
extern char altppchar;
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,
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 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);
*v=(*v>>8)&255;
}
else {
else
if(s[pp]!=T_END) {
er=ag_term(s,P_START,v,&afl, label);
bfl = afl & (A_MASK>>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);
}
if(afl) *pfl = A_ADR | ((afl<<8) & A_FMASK);
} else {
er = E_SYNTAX;
}
*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);
}
@ -98,15 +101,28 @@ static int ag_term(signed char *s, int p, int *v, int *nafl, int *label)
afl = 0;
/*
printf("ag_term(%02x %02x %02x %02x %02x %02x\n",s[0],s[1],s[2],s[3],s[4],s[5]);
*/
//fprintf(stderr, "ag_term(%02x %02x %02x %02x %02x %02x\n",s[0],s[1],s[2],s[3],s[4],s[5]);
while(s[pp]=='-')
{
pp++;
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]=='(')
{
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)
{
er=l_get(cval(s+pp+1),v, &afl);
/*
printf("label: er=%d, seg=%d, afl=%d, nolink=%d, fundef=%d\n",
er, segment, afl, nolink, fundef);
*/
if(er==E_NODEF && segment != SEG_ABS && fundef ) {
if( nolink || (afl==SEG_UNDEF)) {
if( nolink || ((afl==SEG_UNDEF) || (afl==SEG_UNDEFZP))) {
er = E_OK;
*v = 0;
afl = SEG_UNDEF;
if(afl!=SEG_UNDEFZP) {
afl = SEG_UNDEF;
}
*label = cval(s+pp+1);
}
}
pp+=3;
}
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);
pp+=4;
pp+=5;
/*
printf("value: v=%04x\n",*v);
*/
@ -149,7 +171,7 @@ printf("value: v=%04x\n",*v);
{
afl = s[pp+1];
*v=cval(s+pp+2);
pp+=4;
pp+=6;
/*
printf("pointer: v=%04x, afl=%04x\n",*v,afl);
*/
@ -160,15 +182,16 @@ printf("pointer: v=%04x, afl=%04x\n",*v,afl);
*v=pcc;
pp++;
afl = segment;
}
}
else {
er=E_SYNTAX;
}
*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);
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(afl || *nafl) { /* check pointer arithmetic */
if((afl == *nafl) && (afl!=SEG_UNDEF) && o==2) {
afl = 0; /* substract two pointers */
if((afl == *nafl) && (afl!=SEG_UNDEFZP) && (afl!=SEG_UNDEF) && o==2) {
afl = 0; /* subtract two pointers */
} else
if(((afl && !*nafl) || (*nafl && !afl)) && o==1) {
afl=(afl | *nafl); /* add constant to pointer */
} else
if((afl && !*nafl) && o==2) {
afl=(afl | *nafl); /* substract constant from pointer */
afl=(afl | *nafl); /* subtract constant from pointer */
} 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(!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;
}
}
@ -211,10 +240,18 @@ static int get_op(signed char *s, int *o)
*o=s[pp];
if(*o<1 || *o>17)
if(*o<1 || *o>17) {
/*
printf("*o=%d, pp=%d, s=%s\n", *o, pp, s);
for (int i=0; i< 10; i++) {
printf(" %02x", s[i]);
}
printf("\n");
*/
er=E_SYNTAX;
else
} else {
er=E_OK;
}
return(er);
}

View File

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

View File

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

View File

@ -48,46 +48,24 @@ static int b_fget(int*,int);
static int b_ltest(int,int);
static int b_get(int*);
static int b_test(int);
static int ll_def(char *s, int *n, int b);
static int ll_def(char *s, int *n, int b, xalabel_t ltype);
static int b_link(int);
/* local variables */
static int b_new(void);
/*
static int hashindex[256];
static Labtab *lt = NULL;
static int lti = 0;
static int ltm = 0;
*/
static void cll_init();
static int cll_get();
static void cll_clear();
static int cll_getcur();
/*
static char *ln;
static unsigned long lni;
static long sl;
*/
static Labtab *ltp;
int l_init(void)
{
cll_init();
//unn_init();
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)
@ -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 n, er;
er = ll_search(s,&n);
er = ll_search(s,&n, STD);
if(er==E_OK) {
fprintf(stderr,"Warning: global label doubly defined!\n");
} else {
if(!(er=ll_def(s,&n,0))) {
ltp=afile->la.lt+n;
ltp->fl=2;
ltp->afl=SEG_UNDEF;
}
if(!(er=ll_def(s,&n,0, STD))) {
return lg_import(n);
}
}
return er;
}
/**
* define a global label (from the .import pseudo opcode))
* "s" is a pointer to the first label character, end is at \0
* or at non-alphanumeric/_ char
*/
int lg_import(int n) {
int er=E_OK;
ltp=afile->la.lt+n;
ltp->fl=2;
ltp->afl=SEG_UNDEF;
return er;
}
/*
* 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 n,er,b,i=0;
xalabel_t cll_fl;
*f=0;
b=0;
n=0;
*f=0; /* flag (given as param) that the label is to be re-defined and the
"label defined error" is to be skipped */
b=0; /* block level on block stack, resp. block number */
n=0; /* flag, when set, b is absolute block number and not being translated */
cll_fl=STD; /* when 0, clear the cheap local label block */
if(s[0]==':') {
// ca65 unnamed label
i++;
//n++; /* block number b is absolute */
//b=unn_get(); /* current (possibly newly allocated) unnamed label block */
cll_fl = UNNAMED; // keep the cheap local label block
} else
if(s[0]=='-')
{
*f+=1;
*f+=1; /* label is being redefined */
i++;
} else
if(s[0]=='@')
{
i++;
n++; /* block number b is absolute */
b=cll_get(); /* current (possibly newly allocated) cheap label block */
cll_fl=CHEAP; /* do not clear the cll block again... */
} else
if(s[0]=='+')
{
i++;
n++;
b=0;
n++; /* block number b is absolute */
b=0; /* global block number */
}
while(s[i]=='&')
{
n=0;
if (n) b=0; /* reset block number */
n=0; /* block number is relative */
i++;
b++;
b++; /* one (more) level up the block stack */
}
if(!n)
if(!n) {
/* translate from block stack level to absolute block number */
b_fget(&b,b);
}
if(cll_fl == STD) {
/* clear cheap local labels */
cll_clear();
}
if(!isalpha(s[i]) && s[i]!='_')
if((!isalpha(s[i])) && (s[i]!='_') && !(ca65 && ((cll_fl == UNNAMED) || isdigit(s[i])) ) ) {
//printf("SYNTAX cll_fl=%d, i=%d, s[i]=%02x (%c)\n", cll_fl, i, s[i], s[i]);
er=E_SYNTAX;
else
} else
{
er=ll_search(s+i,&n);
er = E_NODEF;
if (cll_fl != UNNAMED) {
er=ll_search(s+i,&n, cll_fl);
}
if(er==E_OK)
{
//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;
if(*f)
{
/* redefinition of label */
*l=ltp->len+i;
} 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;
if(b_ltest(ltp->blk,b))
er=E_LABDEF;
else
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
er=E_LABDEF;
} else
if(er==E_NODEF)
{
if(!(er=ll_def(s+i,&n,b))) /* ll_def(...,*f) */
if(!(er=ll_def(s+i,&n,b, cll_fl) )) /* store the label in the table of labels */
{
ltp=afile->la.lt+n;
*l=ltp->len+i;
ltp->fl=0;
ltp->is_cll=cll_fl;
}
//printf("l_def NODEF: n=%d, s=%s\n", n, ltp->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 n,er,b;
xalabel_t cll_fl;
*afl=0;
er=ll_search(s,&n);
/*printf("l_search: lab=%s(l=%d), afl=%d, er=%d, n=%d\n",s,*l, *afl,er,n);*/
/* check cheap local label */
cll_fl=STD;
if (s[0]=='@') {
cll_fl=CHEAP;
s++;
} else
if (s[0]==':') {
cll_fl = UNNAMED_DEF;
s++;
}
er = E_NODEF;
if (cll_fl != UNNAMED_DEF) {
er=ll_search(s,&n, cll_fl);
}
//printf("l_search: lab=%s(afl=%d, er=%d, cll_fl=%d, cll_cur=%d)\n",s,*afl,er, cll_fl, cll_getcur());
if(er==E_OK)
{
ltp=afile->la.lt+n;
*l=ltp->len;
*l=ltp->len + ((cll_fl == STD) ? 0 : 1);
if(ltp->fl == 1)
{
l_get(n,v,afl);/* *v=lt[n].val;*/
@ -251,12 +380,22 @@ int l_search(char *s, int *l, int *x, int *v, int *afl)
}
else
{
b_get(&b);
er=ll_def(s,x,b); /* ll_def(...,*v); */
if(cll_fl == CHEAP) {
b=cll_get();
} else
if(cll_fl == UNNAMED_DEF) {
b_get(&b); // b=unn_get();
} else {
b_get(&b);
}
er=ll_def(s,x,b, cll_fl); /* ll_def(...,*v); */
ltp=afile->la.lt+(*x);
*l=ltp->len;
ltp->is_cll = cll_fl;
*l=ltp->len + ((cll_fl == STD) ? 0 : 1);
//*l=ltp->len + cll_fl;
if(!er)
{
@ -303,11 +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)
{
if(crossref) l_addocc(n,v,afl);
ltp=afile->la.lt+n;
ltp = afile->la.lt+n;
if (ltp->is_cll == UNNAMED_DEF) {
int tmp = resolve_unnamed();
if (tmp == -1) return E_NODEF;
// now ltp is set to the actual label
}
(*v)=ltp->val;
lz=ltp->n;
*afl = ltp->afl;
@ -321,7 +536,8 @@ void l_set(int n, int v, int afl)
ltp->val = v;
ltp->fl = 1;
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)
@ -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;
char *s2;
char *s2 = NULL;
/*printf("ll_def: s=%s\n",s); */
//printf("ll_def: s=%s, ltype=%d, no_name=%d\n",s, ltype, no_name);
// label table for the file ...
if(!afile->la.lt) {
// ... does not exist yet, so malloc it
afile->la.lti = 0;
afile->la.ltm = 1000;
afile->la.lt = malloc(afile->la.ltm * sizeof(Labtab));
}
if(afile->la.lti>=afile->la.ltm) {
// ... or is at its capacity limit, so realloc it
afile->la.ltm *= 1.5;
afile->la.lt = realloc(afile->la.lt, afile->la.ltm * sizeof(Labtab));
}
@ -355,54 +575,66 @@ static int ll_def(char *s, int *n, int b) /* definiert naechstes Label
fprintf(stderr, "Oops: no memory!\n");
exit(1);
}
#if 0
if((lti<ANZLAB) /*&&(lni<(long)(LABMEM-MAXLAB))*/)
{
#endif
ltp=afile->la.lt+afile->la.lti;
/*
s2=ltp->n=ln+lni;
while((j<MAXLAB-1) && (s[j]!='\0') && (isalnum(s[j]) || s[j]=='_'))
{
s2[j]=s[j];
j++;
}
*/
while((s[j]!='\0') && (isalnum(s[j]) || (s[j]=='_'))) j++;
s2 = malloc(j+1);
if(!s2) {
// current pointer in label table
ltp = afile->la.lt + afile->la.lti;
if (ltype != UNNAMED) {
// alloc space and copy over name
if (ltype == UNNAMED_DEF) {
// unnamed lables are like ":--" or ":+" with variable length
while((s[j]!='\0') && (s[j]=='+' || s[j]=='-')) j++;
} else {
// standard (and cheap) labels are normal text
while((s[j]!='\0') && (isalnum(s[j]) || (s[j]=='_'))) j++;
}
s2 = malloc(j+1);
if(!s2) {
fprintf(stderr,"Oops: no memory!\n");
exit(1);
}
strncpy(s2,s,j);
s2[j]=0;
}
strncpy(s2,s,j);
s2[j]=0;
/*
if(j<MAXLAB)
{
*/
// init new entry in label table
er=E_OK;
ltp->len=j;
ltp->n = s2;
ltp->blk=b;
ltp->len=j; // length of label
ltp->n = s2; // name of label (char*)
ltp->blk=b; // block number
ltp->fl=0;
ltp->afl=0;
ltp->occlist=NULL;
hash=hashcode(s,j);
ltp->nextindex=afile->la.hashindex[hash];
afile->la.hashindex[hash]=afile->la.lti;
*n=afile->la.lti;
afile->la.lti++;
/* lni+=j+1;*/
/* }
}
*/
/*printf("ll_def return: %d\n",er);*/
ltp->is_cll=ltype; // STD, CHEAP, or UNNAMED label
ltp->occlist=NULL;
hash=hashcode(s,j); // compute hashcode
ltp->nextindex=afile->la.hashindex[hash]; // and link in before last entry with same hashcode
afile->la.hashindex[hash]=afile->la.lti; // set as start of list for that hashcode
// TODO: does not work across files!
ltp->blknext = -1; // no next block
ltp->blkprev = b_link( afile->la.lti ); // previous block, linked within block
if (ltp->blkprev != -1) {
ltp = afile->la.lt + ltp->blkprev;
ltp->blknext = afile->la.lti;
}
*n=afile->la.lti; // return the list index for that file in the out parameter n
afile->la.lti++; // increase last index in lable table
return(er);
}
int ll_search(char *s, int *n) /* search Label in Tabelle ,nr->n */
/**
* search a label name in the label table. Return the label number
* in "n". Finds only labels that are in a block that is in the current
* set of blocks (in the block stack)
*
* If cll_fl is set, the label is also searched in the local cheap label scope
*
* Do not define the label (as is done in l_search()!)
*/
int ll_search(char *s, int *n, xalabel_t cll_fl) /* search Label in Tabelle ,nr->n */
{
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);
i=afile->la.hashindex[hash];
/*printf("search?\n");*/
if(i>=afile->la.ltm) return E_NODEF;
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++);
if((j==k)&&(!b_test(ltp->blk)))
{
er=E_OK;
break;
}
if (cll_fl == CHEAP) {
if (ltp->blk == cll_getcur()) {
er=E_OK;
break;
}
} else
if (cll_fl == UNNAMED) {
// TODO
} else {
//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)
@ -444,6 +689,8 @@ int ll_search(char *s, int *n) /* search Label in Tabelle ,nr->n */
getchar();
}
#endif
//printf("l_search(%s) returns er=%d, n=%d\n", s, er, *n);
return(er);
}
@ -451,7 +698,7 @@ int ll_pdef(char *t)
{
int n;
if(ll_search(t,&n)==E_OK)
if(ll_search(t,&n, STD)==E_OK)
{
ltp=afile->la.lt+n;
if(ltp->fl)
@ -460,6 +707,9 @@ int ll_pdef(char *t)
return(E_NODEF);
}
/*
* Write out the list of global labels in an o65 file
*/
int l_write(FILE *fp)
{
int i, afl, n=0;
@ -469,25 +719,39 @@ int l_write(FILE *fp)
fputc(0, fp);
return 0;
}
// calculate number of global labels
for (i=0;i<afile->la.lti;i++) {
ltp=afile->la.lt+i;
if((!ltp->blk) && (ltp->fl==1)) {
n++;
}
}
// write number of globals to file
fputc(n&255, fp);
fputc((n>>8)&255, fp);
// iterate over labels and write out label
for (i=0;i<afile->la.lti;i++)
{
ltp=afile->la.lt+i;
if((!ltp->blk) && (ltp->fl==1)) {
// write global name
fprintf(fp, "%s",ltp->n);
fputc(0,fp);
// segment byte
afl = ltp->afl;
/* 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( (afl & (A_FMASK>>8)) < SEG_TEXT) afl^=1;
// hack to switch undef and abs flag from internal to file format
// if asolute of undefined (< SEG_TEXT, i.e. 0 or 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);
// value
fputc(ltp->val&255, fp);
fputc((ltp->val>>8)&255, fp);
}
@ -496,19 +760,39 @@ int l_write(FILE *fp)
return 0;
}
static int bt[MAXBLK];
static int blk;
static int bi;
/*******************************************************************************************
* block management code. Here the ".(" and ".)" blocks are maintained.
*
* Blocks are numbered uniquely, every time a new block is opened, the "blk" variable
* is increased and its number used as block number.
*
* The currently open blocks are maintained in a stack (bt[]). The lowest entry is the outermost
* block number, adding block numbers as blocks are opened. When a block is closed,
* the block stack is shortened again (bi has the length of the block stack)
*
* Methods exist to open new blocks, close a block, and do some checks, e.g. whether
* a specific block number is contained in the current block stack.
*/
static int bt[MAXBLK]; /* block stack */
static int labind; /* last allocated label, -1 none yet alloc'd - used for linking to find unnamed labels */
static int bi; /* length of the block stack (minus 1, i.e. bi[bi] has the innermost block) */
static int blk; /* current block number for allocation */
int b_init(void)
{
blk =0;
bi =0;
bt[bi]=blk;
labind=-1;
return(E_OK);
}
int b_new(void)
{
return ++blk;
}
int b_depth(void)
{
return bi;
@ -519,19 +803,26 @@ int ga_blk(void)
return(blk);
}
/**
* open a new block scope
*/
int b_open(void)
{
int er=E_BLKOVR;
if(bi<MAXBLK-1)
{
bt[++bi]=++blk;
bi++;
bt[bi]=b_new();
er=E_OK;
}
return(er);
}
/**
* close a block scope
*/
int b_close(void)
{
@ -542,10 +833,14 @@ int b_close(void)
} else {
return E_BLOCK;
}
cll_clear();
//unn_clear();
return(E_OK);
}
/**
* get the block number of the current innermost block
*/
static int b_get(int *n)
{
*n=bt[bi];
@ -553,6 +848,9 @@ static int b_get(int *n)
return(E_OK);
}
/**
* returns the block number of the block "i" levels up in the current block stack
*/
static int b_fget(int *n, int i)
{
if((bi-i)>=0)
@ -562,6 +860,10 @@ static int b_fget(int *n, int i)
return(E_OK);
}
/**
* tests whether the given block number n is in the current stack of
* current block numbers bt[]
*/
static int b_test(int n)
{
int i=bi;
@ -572,6 +874,9 @@ static int b_test(int n)
return( i+1 ? E_OK : E_NOBLK );
}
/**
* tests whether the given block number "a" is in the
*/
static int b_ltest(int a, int b) /* testet ob bt^-1(b) in intervall [0,bt^-1(a)] */
{
int i=0,er=E_OK;
@ -593,3 +898,10 @@ static int b_ltest(int a, int b) /* testet ob bt^-1(b) in intervall [0,bt^-1(
return(er);
}
int b_link(int newlab) {
int tmp = labind;
//printf("b_link: old was %d, set to %d\n", tmp, newlab);
labind = newlab;
return tmp;
}

View File

@ -21,8 +21,13 @@
#include <stdio.h> /* for FILE */
/* nasty stuff - "lz" is exported from xal.c so xa.c can print the name
* of the label that was last searched for in the error message that the
* label was not found...
*/
extern char *lz;
int l_init(void);
int ga_lab(void);
int gm_lab(void);
@ -30,6 +35,10 @@ long gm_labm(void);
long ga_labm(void);
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_depth(void);
@ -40,9 +49,11 @@ int ga_blk(void);
int l_def(char *s, int* l, int *x, int *f);
int l_search(char *s, int *l, int *x, int *v, int *afl);
void l_set(int n, int v, int afl);
char* l_get_name(int n, xalabel_t *is_cll);
char* l_get_unique_name(int n);
int l_get(int n, int *v, int *afl);
int l_vget(int n, int *v, char **s);
int ll_search(char *s, int *n);
int ll_search(char *s, int *n, xalabel_t labeltype);
int ll_pdef(char *t);
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;
}
// copy to xname by replacing windows backslashes with the proper DIRCHAR
for(i=0;i<l+1;i++) {
xname[i]=((fn[i]=='\\')?DIRCHAR:fn[i]);
}
//printf("name=%s, xname=%s, mode=%s\n",fn,xname, mode);
if(mode[0]=='r')
{
if((file=fopen(fn,mode))==NULL
@ -68,7 +71,6 @@ FILE *xfopen(const char *fn,const char *mode)
strcpy(n2,n);
strcat(n2,xname);
strcat(n,fn);
/* printf("name=%s,n2=%s,mode=%s\n",n,n2,mode); */
file=fopen(n,mode);
if(!file) file=fopen(n2,mode);
}
@ -87,7 +89,6 @@ FILE *xfopen(const char *fn,const char *mode)
strcpy(n2,n);
strcat(n2,xname);
strcat(n,fn);
/* printf("name=%s,n2=%s,mode=%s\n",n,n2,mode); */
file=fopen(n,mode);
if(!file) file=fopen(n2,mode);
}

View File

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

View File

@ -40,7 +40,8 @@
#include "xap.h"
/* define this for recursive evaluation output */
/* #define DEBUG_RECMAC */
#undef DEBUG_RECMAC
#undef DEBUG_REPLACE
char s[MAXLINE];
Datei *filep;
@ -50,24 +51,27 @@ static int pp_replace(char*,char*,int,int);
static int searchdef(char*);
static int fgetline(char*,int len, int *rlen, FILE*);
static int icl_open(char*),pp_ifdef(char*),pp_ifndef(char*);
/*static int icl_open(char*);*/
static int pp_ifdef(char*),pp_ifndef(char*);
static int pp_else(char*),pp_endif(char*);
static int pp_echo(char*),pp_if(char*),pp_print(char*),pp_prdef(char*);
static int pp_ifldef(char*),pp_iflused(char*);
static int pp_undef(char*);
static int pp_error(char*);
#define ANZBEF 13
#define VALBEF 6
#define ANZBEF 14
#define VALBEF 7
static int quotebs = 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",
"ifldef","iflused","if" };
"ifldef","iflused","if" }; /* ANZBEF */
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_ifldef,pp_iflused,pp_if };
@ -131,7 +135,7 @@ int pp_ifldef(char *t)
int pp_iflused(char *t)
{
int n;
loopfl=(loopfl<<1)+( ll_search(t,&n) ? 1 : 0 );
loopfl=(loopfl<<1)+( ll_search(t,&n,STD) ? 1 : 0 );
return(0);
}
@ -177,21 +181,29 @@ int pp_print(char *t)
return(0);
}
int pp_error(char *t)
{
/* the offending line is printed for us */
return E_UERROR;
}
int pp_if(char *t)
{
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);
else
} else
{
dsb_len = 1;
f=b_term(s,&a,&l,pc[segment]);
dsb_len = 0;
if((!loopfl) && f)
if((!loopfl) && f) {
errout(f);
else
} else
loopfl=(loopfl<<1)+( a ? 0 : 1 );
}
return(0);
@ -362,7 +374,10 @@ int pp_define(char *k)
{
i++;
liste[rl].p_anz++;
for(j=0; t[i+j]!=')' && t[i+j]!=',' && t[i+j]!='\0';j++);
// skip whitespace before parameter name
while(isspace(t[i])) i++;
// find length
for(j=0; (!isspace(t[i+j])) && t[i+j]!=')' && t[i+j]!=',' && t[i+j]!='\0';j++);
if(j<memfre)
{
strncpy(mem,t+i,j);
@ -371,6 +386,8 @@ int pp_define(char *k)
memfre-=j+1;
}
i+=j;
// skip trailing whitespace after parameter name
while(isspace(t[i])) i++;
}
if(t[i]==')')
i++;
@ -379,7 +396,7 @@ int pp_define(char *k)
i++;
t+=i;
pp_replace(h,t,-1,0);
er = pp_replace(h,t,-1,rlist);
t=h;
@ -442,97 +459,107 @@ int tcompare(char s[],char *v[], int n)
return((i==n)? -1 : i);
}
int pp_replace(char *to, char *ti, int a,int b)
static int check_name(char *t, int n) {
int i=0;
{
char *x=liste[n].search;
while(t[i]==*x++ && t[i] && (isalnum(t[i]) || t[i]=='_'))
i++;
}
#ifdef DEBUG_RECMAC
printf("check name with n=%d, name='%s' ->i=%d, len=%d\n", n, liste[n].search,i, liste[n].s_len);
#endif
return i == liste[n].s_len;
}
/**
* this is a break out of the original pp_replace code, as this code
* was basically duplicated for initial and recursive calls.
*
* 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 i,l,n,sl,d,ld,er=E_OK,hkfl,klfl;
char fti[MAXLINE],fto[MAXLINE];
/*
int flag=!strncmp(ti,"TOUT",4);
if(flag) printf("flag=%d\n",flag);
*/
(void)strcpy(t,ti);
int er = E_OK;
int i, d;
char c;
if(rlist)
{
while(t[0]!='\0')
{
/* 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]!='\"');
}
// save mem, to restore it when we don't need the pseudo replacements anymore
// Note: in a real version, that should probably be a parameter, and not fiddling
// with global variables...
char *saved_mem = mem;
/* escape strings quoted with ' */
if (!ppinstr && t[0] == '\'') {
do {
t++;
ti++;
} while (t[0] && t[0]!='\'');
}
#ifdef DEBUG_RECMAC
printf("replace part: n=%d, sl=%d, rec=%d, %s\n", n, sl, recursive, t);
#endif
if(t[0]=='\0')
break; /*return(E_OK);*/
else
{
t++;
ti++;
}
}
for(l=0;isalnum(t[l])||t[l]=='_';l++);
ld=l;
/*
if(flag) printf("l=%d,a=%d,t=%s\n",l,a,t);
*/
if(a<0)
{
n=hashindex[hashcode(t,l)];
do
{
sl=liste[n].s_len;
if(sl && (sl==l))
{
i=0;
x=liste[n].search;
while(t[i]==*x++ && t[i])
i++;
// yes, mark replacement string
char *rs=liste[n].replace;
// does it have parameters?
if(i==sl)
{
rs=liste[n].replace;
if(liste[n].p_anz)
{
// yes, we have parameters, so we need to pp_replace them
// as well.
char fti[MAXLINE],fto[MAXLINE];
// copy replacement into temp buffer
(void)strcpy(fti,liste[n].replace);
if(rlist+liste[n].p_anz>=ANZDEF || memfre<MAXLINE*2)
// boundary checks ...
if(blist+liste[n].p_anz>=ANZDEF || memfre<MAXLINE*2)
er=E_NOMEM;
else
{
y=t+sl;
x=liste[n].search+sl+1;
if(*y!='(')
// ... passed
// y points to the char behind the input name (i.e. the '(')
char *y=t+sl;
// x points into the pp definition, with the parameter definition names
// following the definition name, separated by \0. Starts here behind the
// name - i.e. now points to the name of the first parameter
char *x=liste[n].search+sl+1;
// does the input actually have a '(' as parameter marker?
if(*y!='(') {
// no. Should probably get an own error (E_PARAMETER_EXPECTED)
er=E_SYNTAX;
}
else
{
mx=mem-1;
// 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++)
{
liste[rlist+i].search=x;
liste[rlist+i].s_len=(int)strlen(x);
char c;
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;
liste[rlist+i].p_anz=0;
liste[rlist+i].replace=mx+1;
// points to first char of the parameter name in the input
// copy over first char into text memory (note that the position
// is already stored in liste[].replace above)
c=*(++mx)=*(++y);
hkfl=klfl=0;
// copy over the other characters
while(c!='\0'
&& ((hkfl!=0
|| klfl!=0)
@ -551,69 +578,135 @@ int pp_replace(char *to, char *ti, int a,int b)
klfl--;
}
c=*(++mx)=*(++y);
}
}
// zero-terminate stored string
*mx='\0';
// if i is for the last parameter, then check if the
// last copied char was ')', otherwise it should be ','
// as separator for the next parameter
if(c!=((i==liste[n].p_anz-1) ? ')' : ','))
{
er=E_ANZPAR;
// note: this break only exits the innermost loop!
break;
}
}
}
// at this point we have "augmented" the pp definitions
// with a list of new definitions for the macro parameters
// so that when pp_replace'ing them recursively the macro parameters
// will automatically be replaced.
// if we ran into an error, report so
if (er != E_OK) {
return (er);
}
// let mx point to first free (and not last non-free) byte
mx++;
// before we use the parameter replacements, we need to
// recursively evaluate and replace them as well.
#ifdef DEBUG_RECMAC
printf("replace:\n");
printf("replace (er=%d):\n", er);
printf("%s=%s\n",liste[n].search,liste[n].replace);
#endif
// loop over all arguments
for(i=0;i<liste[n].p_anz;i++) {
/* recursively evaluate arguments */
char nfto[MAXLINE];
char nfwas[MAXLINE];
int j = 0;
int k;
//int j = 0;
//int k = 0;
(void)strcpy(nfwas, liste[rlist+i].replace);
if (!er)
er=pp_replace(nfto,nfwas,-1,rlist);
// copy over the replacement string into a buffer nfwas
(void)strcpy(nfwas, liste[blist+i].replace);
if (!er) {
// replace the tokens in the parameter, adding possible pseudo params
// on top of the liste[] into nfto
er=pp_replace(nfto,nfwas,-1,blist+liste[n].p_anz);
}
#ifdef DEBUG_RECMAC
printf("-%s=%s\n",liste[rlist+i].search,liste[rlist+i].replace);
printf("SUBB: -%s=%s\n", nfwas, nfto);
#endif
#if 0
// as long as the strings don't match, loop...
while ((k = strcmp(nfto, nfwas))) {
// copy original from nfwas back to nfto
(void)strcpy(nfto, nfwas);
if (!er)
if (!er) {
// save-guard our replacement strings in global memory for the
// recursive pp_replace call. Note: is cleaned up after return,
// so need to restore mem only at the end of this function.
mem = mx;
// replace tokens
er=pp_replace(nfto,nfwas,-1,rlist);
}
// and copy result into input buffer
(void)strcpy(nfwas, nfto);
#ifdef DEBUG_RECMAC
printf("SUBB2 (%i): -%s=%s\n", k, liste[rlist+i].replace, nfto);
#endif
if (++j>10)
if (++j>10) {
// we ran into 10 recursions deep - that does not look sound, bail out
errout(E_ORECMAC);
}
}
#endif
// catch an error situation
if (liste[rlist+i].replace == NULL) {
errout(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
printf("FINAL: -%s=%s\n",liste[rlist+i].search,liste[rlist+i].replace);
#endif
}
if(!er)
er=pp_replace(fto,fti,rlist,rlist+i);
if(!er) {
// safe-guard our memory allocations
mem = mx;
// only change (of two) from recursive: rlist is 0 there
#ifdef DEBUG_RECMAC
printf("replace macro: recursive=%d, blist=%d, -> b=%d\n", recursive, blist, blist+liste[n].p_anz);
printf(" from: %s\n", fti);
#endif
er=pp_replace(fto,fti,recursive ? 0 : blist,blist+liste[n].p_anz);
#ifdef DEBUG_RECMAC
printf(" to: %s\n", fto);
#endif
}
/* if(flag) printf("sl=%d,",sl);*/
sl=(int)((long)y+1L-(long)t);
/* if(flag) printf("sl=%d\n",sl);*/
rs=fto;
/* printf("->%s\n",fto);*/
#ifdef DEBUG_RECMAC
printf("->%s\n",fto);
#endif
}
}
if(er)
if(er) {
mem = saved_mem;
return(er);
}
}
} // end if(liste[n].p_anz), i.e. if it has parameters
d=(int)strlen(rs)-sl;
if(strlen(to)+d>=MAXLINE)
if(strlen(to)+d>=MAXLINE) {
mem = saved_mem;
return(E_NOMEM);
}
/*
if(d<0)
@ -628,129 +721,155 @@ int pp_replace(char *to, char *ti, int a,int b)
t[ll+d]=t[ll];
}
*/
if(d)
(void)strcpy(t+sl+d,ti+sl);
if(d) {
// d can be positive or negative, so strcpy cannot be used, use memmove instead
(void)memmove(t+sl+d,t+sl, strlen(t) - sl + 1);
}
i=0;
while((c=rs[i]))
while((c=rs[i])) {
t[i++]=c;
l=sl+d;/*=0;*/
break;
}
}
// other change from recursive. there sl is missing from add
//*l=(recursive ? 0 : sl) + d;/*=0;*/
*l=sl + d;/*=0;*/
mem = saved_mem;
return (er);
}
/**
* copy the input string pointed to by ti into
* an output string buffer pointed to by to, replacing all
* preprocessor definitions in the process.
*
* Note: this method is called recursively, with "a" being -1
* when called from the "outside" respectively in a new context
* (like macro parameters)
*
* The "b" parameter denotes the index in the list from which on
* pseudo replacement entries are being created for replacement
* parameters
*
*/
int pp_replace(char *to, char *ti, int a,int b)
{
char *t=to;
int l,n,sl,er=E_OK;
int ld; // length of name/token to analyse
/*
int flag=!strncmp(ti,"TOUT",4);
if(flag) printf("flag=%d\n",flag);
*/
// t points to to, so copy input to output 1:1
// then below work on the copy in-place
(void)strcpy(t,ti);
// if there are replacements in the list of replacements
if(rlist)
{
// loop over the whole input
while(t[0]!='\0' && t[0] != ';')
{
// skip over the whitespace
// comment handling is NASTY NASTY NASTY
// but I currently don't see another way, as comments and colons
// can (and do) appear in preprocessor replacements
char quotefl = 0;
char commentfl = 0;
while((t[0] != 0) && (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)
break;
// next index in linked list for given hash code
n=liste[n].nextindex;
} while(1);
} else
{
// called when in recursive call
// loop over all the replacement entries from the given b down to 0
// that allows to replace the parameters first (as they were added at
// the end of the list)
for(n=b-1;n>=a;n--)
{
sl=liste[n].s_len;
if(sl && (sl==l))
if(sl && (sl==l) && check_name(t, n))
{
i=0;
x=liste[n].search;
while(t[i]==*x++ && t[i])
i++;
if(i==sl)
{
rs=liste[n].replace;
if(liste[n].p_anz)
{
(void)strcpy(fti,liste[n].replace);
if(rlist+liste[n].p_anz>=ANZDEF || memfre<MAXLINE*2)
er=E_NOMEM;
else
{
y=t+sl;
x=liste[n].search+sl+1;
if(*y!='(')
er=E_SYNTAX;
else
{
mx=mem-1;
for(i=0;i<liste[n].p_anz;i++)
{
liste[rlist+i].search=x;
liste[rlist+i].s_len=strlen(x);
x+=strlen(x)+1;
liste[rlist+i].p_anz=0;
liste[rlist+i].replace=mx+1;
c=*(++mx)=*(++y);
hkfl=klfl=0;
while(c!='\0'
&& ((hkfl!=0
|| klfl!=0)
|| (c!=','
&& c!=')')
)
)
{
if(c=='\"')
hkfl=hkfl^1;
if(!hkfl)
{
if(c=='(')
klfl++;
if(c==')')
klfl--;
}
c=*(++mx)=*(++y);
}
*mx='\0';
if(c!=((i==liste[n].p_anz-1) ? ')' : ','))
{
er=E_ANZPAR;
break;
}
}
if(!er)
er=pp_replace(fto,fti,0,rlist+i);
sl=(int)((long)y+1L-(long)t);
rs=fto;
}
}
if(er)
return(er);
}
d=(int)strlen(rs)-sl;
if(strlen(to)+d>=MAXLINE)
return(E_NOMEM);
/*
if(d<0)
{
y=t+sl+d;
x=t+sl;
while(*y++=*x++);
}
if(d>0)
{
for(ll=strlen(t);ll>=sl;ll--)
t[ll+d]=t[ll];
}
*/
if(d)
(void)strcpy(t+sl+d,ti+sl);
i=0;
while((c=rs[i]))
t[i++]=c;
l+=d;/*0;*/
break;
}
er = pp_replace_part(to, t, n, sl, 1, &l, b);
break;
}
}
}
// advance input by length of name
ti+=ld;
// advance output by l
t+=l;
}
}
} /* end while(t[0] != 0) */
} /* end if(rlist) */
return(E_OK);
}
@ -774,6 +893,11 @@ int pp_init(void)
if(!er) {
liste=malloc((long)ANZDEF*sizeof(List));
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);
}
@ -781,17 +905,20 @@ int pp_init(void)
int pp_open(char *name)
{
FILE *fp;
int l;
fp=xfopen(name,"r");
l = strlen(name);
/* we have to alloc it dynamically to make the name survive another
pp_open - it's used in the cross-reference list */
flist[0].fname = malloc(strlen(name)+1);
flist[0].fname = malloc(l+1);
if(!flist[0].fname) {
fprintf(stderr,"Oops, no more memory!\n");
exit(1);
}
(void)strcpy(flist[0].fname,name);
(void)strncpy(flist[0].fname,name,l+1);
flist[0].fline=0;
flist[0].bdepth=b_depth();
flist[0].filep=fp;
@ -835,7 +962,8 @@ int icl_close(int *c)
int icl_open(char *tt)
{
FILE *fp2;
int j,i=0;
char *namep;
int len,j,i=0;
pp_replace(s,tt,-1,rlist);
@ -858,14 +986,17 @@ int icl_open(char *tt)
fsp++;
namep = s+i;
len = strlen(namep);
/* we have to alloc it dynamically to make the name survive another
pp_open - it's used in the cross-reference list */
flist[fsp].fname = malloc(strlen(s+i)+1);
flist[fsp].fname = malloc(len+1);
if(!flist[fsp].fname) {
fprintf(stderr,"Oops, no more memory!\n");
exit(1);
}
strcpy(flist[fsp].fname,s+i);
strncpy(flist[fsp].fname,namep, len+1);
flist[fsp].fline=0;
flist[fsp].bdepth=b_depth();
flist[fsp].flinep=NULL;
@ -875,6 +1006,7 @@ int icl_open(char *tt)
return(0);
}
int pgetline(char *t)
{
int c,er=E_OK;
@ -887,32 +1019,43 @@ int pgetline(char *t)
filep =flist+fsp;
do {
c=fgetline(in_line, MAXLINE, &rlen, flist[fsp].filep);
/* continuation lines */
tlen = rlen;
while(c=='\n' && tlen && in_line[tlen-1]=='\\') {
c=fgetline(in_line + tlen-1, MAXLINE-tlen, &rlen, flist[fsp].filep);
tlen += rlen-1;
int is_continuation = 0;
tlen = 0; // start of current line in in_line[]
do {
c=fgetline(in_line + tlen, MAXLINE - tlen, &rlen, flist[fsp].filep);
//fprintf(stderr, "fgetline -> c=%02x, rlen->%d, t->%s\n", c, rlen, in_line+tlen);
/* 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
handle this right */
er=pp_cpp(in_line+1);
} else {
if((er=pp_comand(in_line+1)))
{
if(er!=1)
{
logout(in_line);
logout("\n");
}
}
if((er=pp_comand(in_line+1)))
{
if(er!=1)
{
logout(in_line);
logout("\n");
}
}
}
} else
} else {
er=1;
}
if(c==EOF) {
if(c==EOF) {
if (loopfl && fsp) {
char bletch[MAXLINE];
sprintf(bletch,
@ -936,8 +1079,15 @@ int pgetline(char *t)
er= (er==1) ? E_OK : er ;
if(!er)
if(!er) {
#ifdef DEBUG_REPLACE
// printf("<<<: %s\n", in_line);
#endif
er=pp_replace(t,in_line,-1,rlist);
#ifdef DEBUG_REPLACE
printf(">>>: %s\n", t);
#endif
}
if(!er && nff)
er=E_NEWFILE;
@ -947,7 +1097,8 @@ int pgetline(char *t)
filep=flist+fsp;
filep->flinep=in_line;
//fprintf(stderr, "pgetline -> er=%d, t=%s\n", er, t);
return(er);
}
@ -988,8 +1139,9 @@ int rgetc(FILE *fp)
nlf=1;
}
/* check for start of comment anyway, to allow for nestesd comments */
if(!inquote && c=='/')
/* check for start of comment anyway, to allow for nested comments */
/* only allow this with 2.3 compatibility */
if(!inquote && c=='/' && (xa23 || !incomment))
{
d = getc(fp);
@ -998,6 +1150,10 @@ int rgetc(FILE *fp)
do {
c = getc(fp);
} while (c != '\n' && c != EOF);
if (c == '\n') {
flist[fsp].fline++;
nlf=1;
}
} else
if (d == '*') {
/* start block comment */
@ -1037,19 +1193,15 @@ int rgetc(FILE *fp)
inquote ^= 1;
}
#if(0)
/* implement backslashed quotes for 2.4 */
if(c=='\\') quotebs=1; else quotebs=0;
#endif
/* implement backslashed quotes for 2.4 */
if(!xa23 && c=='\\') quotebs=1; else quotebs=0;
} else {
/* in comment */
/* check for end of comment */
/* note: incomment only set true if not quoted, and quote not changed in comment */
if((!inquote) && (c=='*'))
/* note: for xa2.3, incomment only set true if not quoted, and quote not changed in comment */
if((!inquote || !xa23) && (c=='*'))
{
if((d=getc(fp))!='/') {
d_isvalid = 1;
@ -1075,6 +1227,11 @@ int rgetc(FILE *fp)
return(c-'\t'?c:' ');
}
/**
* Note that the line returned is always zero-terminated,
* the rlen out parameter is just convenience, so that
* a further strlen() can be saved
*/
int fgetline(char *t, int len, int *rlen, FILE *fp)
{
static int c,i;

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,11 @@
extern int dsb_len;
int t_p1(signed char *s, signed char *t, int *ll, int *al);
int t_p2(signed char *t, int *ll, int fl, int *al);
int t_p2_l(signed char *t, int *ll, int *al);
int b_term(char *s, int *v, int *l, int pc);
extern char *kt[]; // table of key words, needed for listing
extern char *arith_ops[]; // table of arithmetic operators, needed for listing
extern int number_of_valid_tokens; // as it says, in the "kt" table
#endif /* __XA65_XAT_H__ */

View File

@ -1,6 +1,6 @@
/* 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)
*
@ -27,15 +27,13 @@
#include "xah.h"
#include "xal.h"
/*
static int *ulist = NULL;
static int un = 0;
static int um = 0;
*/
#undef DEBUG_UNDEF
int u_label(int labnr) {
int i;
/*printf("u_label: %d\n",labnr);*/
#ifdef DEBUG_UNDEF
printf("u_label: %d\n",labnr);
#endif
if(!afile->ud.ulist) {
afile->ud.ulist = malloc(200*sizeof(int));
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
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
unless 'make test' fails. If you do, use harness:
You can run specific tests from the main source directory with
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,...
If -tests is omitted, all tests are run.
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
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
chppch/ Changing preprocessor characters (-p)
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)
dos51/ Regression test, label scoping, "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)
branch/ Branch range test
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)
pparity/ Tests of preprocessor macro arity (with Emil Johansson's 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

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 "^"" ; ^ is escape character
.asc '^''
.asc "\"" ; \ is escape character
.asc '\''
.asc "'"
.asc '"'
.asc "^n"
.asc "\n"

View File

@ -1,10 +1,10 @@
default:
../../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
../../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
clean:
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
$make ||= "make";
$cc ||= "cc";
$make ||= "make";
$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{'MAKE'} = $make;
$ENV{'CFLAGS'} = $cflags;
$ENV{'MFLAGS'} = $makeflags;
$ENV{'MAKEFLAGS'} = $makeflags;
$|++;
$ntests = 0;
@ -16,8 +26,7 @@ print <<"EOF";
CC = $cc
CFLAGS = $cflags
MAKE = $make
tests to run: $dtests
MAKEFLAGS = $makeflags
EOF
# 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).
opendir(D, ".") || die("test harness failed: $!\n");
W: while($x = readdir(D)) {
next W if ($x =~ /^\./);
next W if (length($tests) && ($tests !~ /$x/));
while($x = readdir(D)) {
next if ($x =~ /^\./ || $x =~ /\s/);
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));
$x = substr($x . " " . ("." x 79), 0, 50);
print STDOUT "$x > ";
@ -58,7 +84,6 @@ W: while($x = readdir(D)) {
}
chdir("..");
}
closedir(D);
print STDOUT "=" x 79, "\n";
if ($ntests) { # ntestacy is a terrible thing
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
all: t
all: t1 t2 t10 t11 t20 t21 t30 t31 t40 t41 t50 t51 t60 t61 t62
1.o65: 1.s
../../xa -R -c -o 1.o65 1.s
../hextool 1.o65 > 1.o65.hex
# BSD only has suffix rules
2.o65: 2.s
../../xa -R -c -o 2.o65 2.s
../hextool 2.o65 > 2.o65.hex
.SUFFIXES: .o65 .hex
#%.o65: %.s
.s.o65:
../../xa -R -c -o $@ $<
#%.hex: %.o65
.o65.hex:
../hextool $< > $@
linked.o65: 1.o65 2.o65
../../ldo65 -o linked.o65 1.o65 2.o65
../hextool linked.o65 > linked.o65.hex
../../ldo65 -o $@ 1.o65 2.o65
t: linked.o65
../../reloc65 -bt 32768 -xt -o t linked.o65
../hextool t > t.hex
../hextool -cmp=t < t.ok
linked2.o65: 1.o65 2.o65
../../ldo65 -o $@ 2.o65 1.o65
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:
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