mirror of
https://github.com/uffejakobsen/acme.git
synced 2024-10-06 13:59:41 +00:00
ACME release 0.96.3: Added "!hex" and "!skip" pseudoops. Added cheap locals.
Added CLI switch to change pseudoop prefix to '.' Fixed a bug in expression parser and added a warning. git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@94 4df02467-bbd4-4a76-a152-e7ce94205b78
This commit is contained in:
parent
e1683b1e28
commit
7cb100c480
@ -107,6 +107,23 @@ Examples: !be32 $7fffffff, symbol, -$80000000, 14, $46a4f35
|
|||||||
!be32 300000 - 4, a AND a2, 2 ^ tz, (3+4)*70, l1 & .j2
|
!be32 300000 - 4, a AND a2, 2 ^ tz, (3+4)*70, l1 & .j2
|
||||||
|
|
||||||
|
|
||||||
|
Call: !hex PAIRS_OF_HEX_DIGITS
|
||||||
|
Purpose: Insert byte values with a minimum of additional syntax.
|
||||||
|
This pseudo opcode was added for easier writing of external
|
||||||
|
source code generator tools.
|
||||||
|
Parameters: PAIRS_OF_HEX_DIGITS: Just hexadecimal digits, without any
|
||||||
|
"0x" or "$" prefix. Spaces and TABs are allowed, but not
|
||||||
|
needed to separate the byte values.
|
||||||
|
Aliases: "!h"
|
||||||
|
Examples: !h f0 f1 f2 f3 f4 f5 f6 f7 ; insert values 0xf0..0xf7
|
||||||
|
!h f0f1f2f3 f4f5f6f7 ; insert values 0xf0..0xf7
|
||||||
|
!h f0f1f2f3f4f5f6f7 ; insert values 0xf0..0xf7
|
||||||
|
!h f0f 1f2 ; ERROR: space inside pair!
|
||||||
|
!h 0x00, $00 ; ERROR: "0x", "," and "$" are forbidden!
|
||||||
|
!h SOME_SYMBOL ; ERROR: symbols are forbidden!
|
||||||
|
!h ABCD ; insert value 0xAB, then 0xCD (CAUTION, big-endian)
|
||||||
|
|
||||||
|
|
||||||
Call: !fill AMOUNT [, VALUE]
|
Call: !fill AMOUNT [, VALUE]
|
||||||
Purpose: Fill amount of memory with value.
|
Purpose: Fill amount of memory with value.
|
||||||
Parameters: AMOUNT: Any formula the value parser accepts, but it
|
Parameters: AMOUNT: Any formula the value parser accepts, but it
|
||||||
@ -118,6 +135,16 @@ Examples: !fi 256, $ff ; reserve 256 bytes
|
|||||||
!fill 2 ; reserve two bytes
|
!fill 2 ; reserve two bytes
|
||||||
|
|
||||||
|
|
||||||
|
Call: !skip AMOUNT
|
||||||
|
Purpose: Advance in output buffer without starting a new segment.
|
||||||
|
Parameters: AMOUNT: Any formula the value parser accepts, but it
|
||||||
|
must be solvable even in the first pass (this limitation
|
||||||
|
will hopefully be lifted in a future release).
|
||||||
|
Aliases: None
|
||||||
|
Examples: !skip BUFSIZE ; reserve some bytes
|
||||||
|
!skip 5 ; reserve five bytes
|
||||||
|
|
||||||
|
|
||||||
Call: !align ANDVALUE, EQUALVALUE [, FILLVALUE]
|
Call: !align ANDVALUE, EQUALVALUE [, FILLVALUE]
|
||||||
Purpose: Fill memory until a matching address is reached. ACME
|
Purpose: Fill memory until a matching address is reached. ACME
|
||||||
outputs FILLVALUE until "program counter AND ANDVALUE"
|
outputs FILLVALUE until "program counter AND ANDVALUE"
|
||||||
|
@ -12,6 +12,25 @@ platform used. There should be another help file in this archive
|
|||||||
outlining the platform specific changes.
|
outlining the platform specific changes.
|
||||||
|
|
||||||
|
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
Section: New in release 0.96.3
|
||||||
|
----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Added "!h"/"!hex" pseudo opcode: Now external source code generator
|
||||||
|
tools can easily put data in sources with minimal syntax overhead.
|
||||||
|
Added "!skip" pseudo opcode: "!skip N" works like "*=*+N" without
|
||||||
|
starting a new segment.
|
||||||
|
Added "cheap locals": Labels with '@' prefix have automatic scoping,
|
||||||
|
bounded by the preceding and the following global labels.
|
||||||
|
Added "--fullstop" CLI switch to change pseudo opcode prefix from '!'
|
||||||
|
to '.' (so other assemblers' sources need less conversion work)
|
||||||
|
Fixed a bug where expressions like "1)+1" crashed ACME. Thanks to
|
||||||
|
Bitbreaker for reporting this.
|
||||||
|
Added warning when using zp-indirect addressing modes where argument
|
||||||
|
is $ff because pointer wraps around to $00. Thanks to Gerrit for
|
||||||
|
the suggestion.
|
||||||
|
|
||||||
|
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
Section: New in release 0.96.2
|
Section: New in release 0.96.2
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
|
@ -41,12 +41,14 @@ Assembling buggy JMP($xxff) instruction
|
|||||||
Note that this warning is only given for CPU types 6502 and 6510,
|
Note that this warning is only given for CPU types 6502 and 6510,
|
||||||
because 65c02 and 65816 have been fixed in this respect.
|
because 65c02 and 65816 have been fixed in this respect.
|
||||||
|
|
||||||
|
Assembling unstable ANE #NONZERO instruction
|
||||||
Assembling unstable LXA #NONZERO instruction
|
Assembling unstable LXA #NONZERO instruction
|
||||||
This warning is only ever given for CPU type 6510. LXA is one of
|
These warnings are only ever given for CPU type 6510. ANE and LXA
|
||||||
the undocumented ("illegal") opcodes of this CPU (opcode 0xab),
|
are undocumented ("illegal") opcodes of this CPU, and they only
|
||||||
and it only works reliably if its argument is zero. Therefore ACME
|
work reliably if the argument is zero or the accumulator contains
|
||||||
issues this warning if you are about to generate this instruction
|
0xff.
|
||||||
with a non-zero argument.
|
Therefore ACME issues these warnings if it is about to generate
|
||||||
|
these instructions with a non-zero argument.
|
||||||
|
|
||||||
Bug in ACME, code follows
|
Bug in ACME, code follows
|
||||||
A situation has been encountered implying there is a bug in ACME.
|
A situation has been encountered implying there is a bug in ACME.
|
||||||
@ -155,6 +157,13 @@ Wrong type for loop's END value - must match type of START value.
|
|||||||
In "!for" loops, START and END must have the same type, which then
|
In "!for" loops, START and END must have the same type, which then
|
||||||
gets used for the loop counter.
|
gets used for the loop counter.
|
||||||
|
|
||||||
|
Zeropage pointer wraps around from $ff to $00
|
||||||
|
A zeropage-indirect addressing mode uses $ff as the argument. The
|
||||||
|
6502 will then fetch the second pointer byte from $00 instead of
|
||||||
|
$0100, therefore this warning is issued.
|
||||||
|
With the 65816's three-byte pointers, this warning is also given
|
||||||
|
for $fe arguments.
|
||||||
|
|
||||||
...called from here.
|
...called from here.
|
||||||
If warnings and/or errors are output during a macro call, messages
|
If warnings and/or errors are output during a macro call, messages
|
||||||
with this text are added to display the call stack (because you
|
with this text are added to display the call stack (because you
|
||||||
|
@ -187,23 +187,35 @@ Available options are:
|
|||||||
This is more or less useless, because the help is also shown
|
This is more or less useless, because the help is also shown
|
||||||
if ACME is run without any arguments at all.
|
if ACME is run without any arguments at all.
|
||||||
|
|
||||||
-f, --format FORMAT set output file format ("plain", "cbm" or "apple")
|
-f, --format FORMAT set output file format
|
||||||
|
Use this with a bogus format type to get a list of all
|
||||||
|
supported ones (as of writing: "plain", "cbm" and "apple")
|
||||||
-o, --outfile FILE set output file name
|
-o, --outfile FILE set output file name
|
||||||
Output file name and format can also be given using the "!to"
|
Output file name and format can also be given using the "!to"
|
||||||
pseudo opcode. If the format is not specified, "!to" defaults
|
pseudo opcode. If the format is not specified, "!to" defaults
|
||||||
to "cbm", while the command line option defaults to "plain".
|
to "cbm", while the command line option defaults to "plain".
|
||||||
|
|
||||||
|
-r, --report set report file name
|
||||||
|
This creates a text listing containing the original line
|
||||||
|
number, the resulting memory address, the byte value(s) put
|
||||||
|
there and the original text line from the source file.
|
||||||
|
|
||||||
-l, --symbollist FILE set symbol list file name
|
-l, --symbollist FILE set symbol list file name
|
||||||
This can also be given using the "!symbollist"/"!sl" pseudo
|
This can also be given using the "!symbollist"/"!sl" pseudo
|
||||||
opcode. The switch was called "--labeldump" in older versions,
|
opcode. The switch was called "--labeldump" in older versions,
|
||||||
that name still works, too.
|
that name still works, too.
|
||||||
|
|
||||||
|
--vicelabels FILE set file name for label dump in VICE format
|
||||||
|
The resulting file uses a format suited for the VICE emulator.
|
||||||
|
|
||||||
--setpc NUMBER set program counter
|
--setpc NUMBER set program counter
|
||||||
This can also be given in the source code using "* = NUMBER".
|
This can also be given in the source code using "* = NUMBER".
|
||||||
|
|
||||||
--cpu CPU_TYPE set processor type
|
--cpu CPU_TYPE set target processor
|
||||||
This can be changed in the source code using the "!cpu" pseudo
|
This can be changed in the source code using the "!cpu" pseudo
|
||||||
opcode. Defaults to 6502.
|
opcode. Defaults to 6502.
|
||||||
|
Use this with a bogus cpu type to get a list of all supported
|
||||||
|
ones.
|
||||||
|
|
||||||
--initmem NUMBER define 'empty' memory
|
--initmem NUMBER define 'empty' memory
|
||||||
This can also be given using the "!initmem" pseudo opcode.
|
This can also be given using the "!initmem" pseudo opcode.
|
||||||
@ -212,8 +224,8 @@ Available options are:
|
|||||||
--maxerrors NUMBER set number of errors before exiting
|
--maxerrors NUMBER set number of errors before exiting
|
||||||
If not given, defaults to 10.
|
If not given, defaults to 10.
|
||||||
|
|
||||||
--maxdepth NUMBER set recursion depth for macro calls and the
|
--maxdepth NUMBER set recursion depth for macro calls and !src
|
||||||
"!source" pseudo opcode. If not given, defaults to 64.
|
The default value for this is 64.
|
||||||
|
|
||||||
-vDIGIT set verbosity level
|
-vDIGIT set verbosity level
|
||||||
Sets how much additional informational output is generated.
|
Sets how much additional informational output is generated.
|
||||||
@ -253,6 +265,19 @@ Available options are:
|
|||||||
With this option, errors are written to the standard output
|
With this option, errors are written to the standard output
|
||||||
stream instead of to the standard error stream.
|
stream instead of to the standard error stream.
|
||||||
|
|
||||||
|
--msvc output errors in MS VS format
|
||||||
|
This changes the format of the error output to that used by
|
||||||
|
a certain commercial IDE.
|
||||||
|
|
||||||
|
--color uses ANSI color codes for error output
|
||||||
|
If your terminal emulation supports ANSI escape codes, use
|
||||||
|
this option to have warnings and errors displayed in color.
|
||||||
|
|
||||||
|
--fullstop use '.' as pseudo opcode prefix
|
||||||
|
This changes the prefix character used to mark pseudo opcodes
|
||||||
|
from '!' to '.' (so sources intended for other assemblers can
|
||||||
|
be converted with less effort).
|
||||||
|
|
||||||
-V, --version show version and exit.
|
-V, --version show version and exit.
|
||||||
|
|
||||||
Platform-specific versions of ACME might offer more options.
|
Platform-specific versions of ACME might offer more options.
|
||||||
@ -353,7 +378,8 @@ $d011 hexadecimal values are indicated by either a
|
|||||||
current conversion table (none/petscii/screen),
|
current conversion table (none/petscii/screen),
|
||||||
chosen using the "!ct" pseudo opcode.
|
chosen using the "!ct" pseudo opcode.
|
||||||
poll_joy2 a global symbol
|
poll_joy2 a global symbol
|
||||||
.fail a local symbol, indicated by leading dot
|
.fail a local symbol, indicated by leading "."
|
||||||
|
@loop a "cheap local", indicated by leading "@"
|
||||||
* the current program counter. During offset assembly,
|
* the current program counter. During offset assembly,
|
||||||
"*" gives the value of the "Pseudo PC". Just to
|
"*" gives the value of the "Pseudo PC". Just to
|
||||||
make sure: The value of the program counter is
|
make sure: The value of the program counter is
|
||||||
@ -386,10 +412,14 @@ issued (to spot typing errors - see Errors.txt for more info).
|
|||||||
Every symbol name consists of these characters: "a" to "z", "A" to
|
Every symbol name consists of these characters: "a" to "z", "A" to
|
||||||
"Z", "0" to "9", the underscore character "_" and all characters with
|
"Z", "0" to "9", the underscore character "_" and all characters with
|
||||||
values beyond 127. The first character must not be a digit though. But
|
values beyond 127. The first character must not be a digit though. But
|
||||||
it can be a dot ("."), making the symbol a local one. Two other
|
it can be '.' or '@', making the symbol a local one.
|
||||||
possibilities for label names are "all-characters-are-minus" (then it
|
Local symbols beginning with '.' are only valid inside the current
|
||||||
is an anonymous backward label) and "all-characters-are-plus" (then it
|
zone (marked using the "!zone" pseudo opcode) or the current macro.
|
||||||
is an anonymous forward label).
|
Local symbols beginning with '@' are only valid between the enclosing
|
||||||
|
global labels (or inside the current macro).
|
||||||
|
Two other possibilities for label names are "all-characters-are-minus"
|
||||||
|
(then it is an anonymous backward label) and "all-characters-are-plus"
|
||||||
|
(then it is an anonymous forward label).
|
||||||
|
|
||||||
Every command is one of the following:
|
Every command is one of the following:
|
||||||
An assembler opcode
|
An assembler opcode
|
||||||
|
@ -43,7 +43,7 @@ output.o: config.h acme.h alu.h cpu.h dynabuf.h global.h input.h tree.h output.h
|
|||||||
|
|
||||||
platform.o: config.h platform.h platform.c
|
platform.o: config.h platform.h platform.c
|
||||||
|
|
||||||
pseudoopcodes.o: acme.h alu.h input.h macro.h output.h pseudoopcodes.h pseudoopcodes.c
|
pseudoopcodes.o: acme.h alu.h global.h input.h macro.h output.h pseudoopcodes.h pseudoopcodes.c
|
||||||
|
|
||||||
section.o: config.h dynabuf.h global.h symbol.h tree.h section.h section.c
|
section.o: config.h dynabuf.h global.h symbol.h tree.h section.h section.c
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ output.o: config.h acme.h alu.h cpu.h dynabuf.h global.h input.h tree.h output.h
|
|||||||
|
|
||||||
platform.o: config.h platform.h platform.c
|
platform.o: config.h platform.h platform.c
|
||||||
|
|
||||||
pseudoopcodes.o: acme.h alu.h input.h macro.h output.h pseudoopcodes.h pseudoopcodes.c
|
pseudoopcodes.o: acme.h alu.h global.h input.h macro.h output.h pseudoopcodes.h pseudoopcodes.c
|
||||||
|
|
||||||
section.o: config.h dynabuf.h global.h symbol.h tree.h section.h section.c
|
section.o: config.h dynabuf.h global.h symbol.h tree.h section.h section.c
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ output.o: config.h acme.h alu.h cpu.h dynabuf.h global.h input.h tree.h output.h
|
|||||||
|
|
||||||
platform.o: config.h platform.h platform.c
|
platform.o: config.h platform.h platform.c
|
||||||
|
|
||||||
pseudoopcodes.o: acme.h alu.h input.h macro.h output.h pseudoopcodes.h pseudoopcodes.c
|
pseudoopcodes.o: acme.h alu.h global.h input.h macro.h output.h pseudoopcodes.h pseudoopcodes.c
|
||||||
|
|
||||||
section.o: config.h dynabuf.h global.h symbol.h tree.h section.h section.c
|
section.o: config.h dynabuf.h global.h symbol.h tree.h section.h section.c
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ output.o: config.h acme.h alu.h cpu.h dynabuf.h global.h input.h tree.h output.h
|
|||||||
|
|
||||||
platform.o: config.h platform.h platform.c
|
platform.o: config.h platform.h platform.c
|
||||||
|
|
||||||
pseudoopcodes.o: acme.h alu.h input.h macro.h output.h pseudoopcodes.h pseudoopcodes.c
|
pseudoopcodes.o: acme.h alu.h global.h input.h macro.h output.h pseudoopcodes.h pseudoopcodes.c
|
||||||
|
|
||||||
section.o: config.h dynabuf.h global.h symbol.h tree.h section.h section.c
|
section.o: config.h dynabuf.h global.h symbol.h tree.h section.h section.c
|
||||||
|
|
||||||
|
35
src/acme.c
35
src/acme.c
@ -1,5 +1,5 @@
|
|||||||
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
||||||
// Copyright (C) 1998-2016 Marco Baye
|
// Copyright (C) 1998-2017 Marco Baye
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or modify
|
// 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
|
// it under the terms of the GNU General Public License as published by
|
||||||
@ -62,6 +62,7 @@ static const char arg_vicelabels[] = "VICE labels filename";
|
|||||||
#define OPTION_VERSION "version"
|
#define OPTION_VERSION "version"
|
||||||
#define OPTION_MSVC "msvc"
|
#define OPTION_MSVC "msvc"
|
||||||
#define OPTION_COLOR "color"
|
#define OPTION_COLOR "color"
|
||||||
|
#define OPTION_FULLSTOP "fullstop"
|
||||||
// options for "-W"
|
// options for "-W"
|
||||||
#define OPTIONWNO_LABEL_INDENT "no-label-indent"
|
#define OPTIONWNO_LABEL_INDENT "no-label-indent"
|
||||||
#define OPTIONWNO_OLD_FOR "no-old-for"
|
#define OPTIONWNO_OLD_FOR "no-old-for"
|
||||||
@ -138,8 +139,9 @@ static void show_help_and_exit(void)
|
|||||||
// when there are more, use next line and add a separate function:
|
// when there are more, use next line and add a separate function:
|
||||||
//" -W show warning level options\n"
|
//" -W show warning level options\n"
|
||||||
" --" OPTION_USE_STDOUT " fix for 'Relaunch64' IDE (see docs)\n"
|
" --" OPTION_USE_STDOUT " fix for 'Relaunch64' IDE (see docs)\n"
|
||||||
" --" OPTION_MSVC " set output error message format to that of MS Visual Studio\n"
|
" --" OPTION_MSVC " output errors in MS VS format\n"
|
||||||
" --" OPTION_COLOR " enable colored error output using ANSI escape codes\n"
|
" --" OPTION_COLOR " uses ANSI color codes for error output\n"
|
||||||
|
" --" OPTION_FULLSTOP " use '.' as pseudo opcode prefix\n"
|
||||||
PLATFORM_OPTION_HELP
|
PLATFORM_OPTION_HELP
|
||||||
" -V, --" OPTION_VERSION " show version and exit\n");
|
" -V, --" OPTION_VERSION " show version and exit\n");
|
||||||
exit(EXIT_SUCCESS);
|
exit(EXIT_SUCCESS);
|
||||||
@ -274,7 +276,7 @@ static int do_actual_work(void)
|
|||||||
|
|
||||||
report = &global_report; // let global pointer point to something
|
report = &global_report; // let global pointer point to something
|
||||||
report_init(report); // we must init struct before doing passes
|
report_init(report); // we must init struct before doing passes
|
||||||
if (Process_verbosity > 1)
|
if (config.process_verbosity > 1)
|
||||||
puts("First pass.");
|
puts("First pass.");
|
||||||
pass_count = 0;
|
pass_count = 0;
|
||||||
undefined_curr = perform_pass(); // First pass
|
undefined_curr = perform_pass(); // First pass
|
||||||
@ -285,7 +287,7 @@ static int do_actual_work(void)
|
|||||||
while (undefined_curr && (undefined_curr < undefined_prev)) {
|
while (undefined_curr && (undefined_curr < undefined_prev)) {
|
||||||
++pass_count;
|
++pass_count;
|
||||||
undefined_prev = undefined_curr;
|
undefined_prev = undefined_curr;
|
||||||
if (Process_verbosity > 1)
|
if (config.process_verbosity > 1)
|
||||||
puts("Further pass.");
|
puts("Further pass.");
|
||||||
undefined_curr = perform_pass();
|
undefined_curr = perform_pass();
|
||||||
}
|
}
|
||||||
@ -294,7 +296,7 @@ static int do_actual_work(void)
|
|||||||
// if listing report is wanted and there were no errors,
|
// if listing report is wanted and there were no errors,
|
||||||
// do another pass to generate listing report
|
// do another pass to generate listing report
|
||||||
if (report_filename) {
|
if (report_filename) {
|
||||||
if (Process_verbosity > 1)
|
if (config.process_verbosity > 1)
|
||||||
puts("Extra pass to generate listing report.");
|
puts("Extra pass to generate listing report.");
|
||||||
if (report_open(report, report_filename) == 0) {
|
if (report_open(report, report_filename) == 0) {
|
||||||
++pass_count;
|
++pass_count;
|
||||||
@ -306,7 +308,7 @@ static int do_actual_work(void)
|
|||||||
}
|
}
|
||||||
// There are still errors (unsolvable by doing further passes),
|
// There are still errors (unsolvable by doing further passes),
|
||||||
// so perform additional pass to find and show them.
|
// so perform additional pass to find and show them.
|
||||||
if (Process_verbosity > 1)
|
if (config.process_verbosity > 1)
|
||||||
puts("Extra pass needed to find error.");
|
puts("Extra pass needed to find error.");
|
||||||
// activate error output
|
// activate error output
|
||||||
ALU_optional_notdef_handler = Throw_error;
|
ALU_optional_notdef_handler = Throw_error;
|
||||||
@ -456,7 +458,7 @@ static const char *long_option(const char *string)
|
|||||||
else if (strcmp(string, OPTION_INITMEM) == 0)
|
else if (strcmp(string, OPTION_INITMEM) == 0)
|
||||||
set_mem_contents();
|
set_mem_contents();
|
||||||
else if (strcmp(string, OPTION_MAXERRORS) == 0)
|
else if (strcmp(string, OPTION_MAXERRORS) == 0)
|
||||||
max_errors = string_to_number(cliargs_safe_get_next("maximum error count"));
|
config.max_errors = string_to_number(cliargs_safe_get_next("maximum error count"));
|
||||||
else if (strcmp(string, OPTION_MAXDEPTH) == 0)
|
else if (strcmp(string, OPTION_MAXDEPTH) == 0)
|
||||||
macro_recursions_left = (source_recursions_left = string_to_number(cliargs_safe_get_next("recursion depth")));
|
macro_recursions_left = (source_recursions_left = string_to_number(cliargs_safe_get_next("recursion depth")));
|
||||||
// else if (strcmp(string, "strictsyntax") == 0)
|
// else if (strcmp(string, "strictsyntax") == 0)
|
||||||
@ -464,10 +466,12 @@ static const char *long_option(const char *string)
|
|||||||
else if (strcmp(string, OPTION_USE_STDOUT) == 0)
|
else if (strcmp(string, OPTION_USE_STDOUT) == 0)
|
||||||
msg_stream = stdout;
|
msg_stream = stdout;
|
||||||
else if (strcmp(string, OPTION_MSVC) == 0)
|
else if (strcmp(string, OPTION_MSVC) == 0)
|
||||||
format_msvc = TRUE;
|
config.format_msvc = TRUE;
|
||||||
|
else if (strcmp(string, OPTION_FULLSTOP) == 0)
|
||||||
|
config.pseudoop_prefix = '.';
|
||||||
PLATFORM_LONGOPTION_CODE
|
PLATFORM_LONGOPTION_CODE
|
||||||
else if (strcmp(string, OPTION_COLOR) == 0)
|
else if (strcmp(string, OPTION_COLOR) == 0)
|
||||||
format_color = TRUE;
|
config.format_color = TRUE;
|
||||||
else if (strcmp(string, OPTION_VERSION) == 0)
|
else if (strcmp(string, OPTION_VERSION) == 0)
|
||||||
show_version(TRUE);
|
show_version(TRUE);
|
||||||
else
|
else
|
||||||
@ -499,9 +503,9 @@ static char short_option(const char *argument)
|
|||||||
report_filename = cliargs_safe_get_next(arg_reportfile);
|
report_filename = cliargs_safe_get_next(arg_reportfile);
|
||||||
break;
|
break;
|
||||||
case 'v': // "-v" changes verbosity
|
case 'v': // "-v" changes verbosity
|
||||||
++Process_verbosity;
|
++config.process_verbosity;
|
||||||
if ((argument[1] >= '0') && (argument[1] <= '9'))
|
if ((argument[1] >= '0') && (argument[1] <= '9'))
|
||||||
Process_verbosity = *(++argument) - '0';
|
config.process_verbosity = *(++argument) - '0';
|
||||||
break;
|
break;
|
||||||
// platform specific switches are inserted here
|
// platform specific switches are inserted here
|
||||||
PLATFORM_SHORTOPTION_CODE
|
PLATFORM_SHORTOPTION_CODE
|
||||||
@ -510,13 +514,13 @@ static char short_option(const char *argument)
|
|||||||
break;
|
break;
|
||||||
case 'W': // "-W" tunes warning level
|
case 'W': // "-W" tunes warning level
|
||||||
if (strcmp(argument + 1, OPTIONWNO_LABEL_INDENT) == 0) {
|
if (strcmp(argument + 1, OPTIONWNO_LABEL_INDENT) == 0) {
|
||||||
warn_on_indented_labels = FALSE;
|
config.warn_on_indented_labels = FALSE;
|
||||||
goto done;
|
goto done;
|
||||||
} else if (strcmp(argument + 1, OPTIONWNO_OLD_FOR) == 0) {
|
} else if (strcmp(argument + 1, OPTIONWNO_OLD_FOR) == 0) {
|
||||||
warn_on_old_for = FALSE;
|
config.warn_on_old_for = FALSE;
|
||||||
goto done;
|
goto done;
|
||||||
} else if (strcmp(argument + 1, OPTIONWTYPE_MISMATCH) == 0) {
|
} else if (strcmp(argument + 1, OPTIONWTYPE_MISMATCH) == 0) {
|
||||||
warn_on_type_mismatch = TRUE;
|
config.warn_on_type_mismatch = TRUE;
|
||||||
goto done;
|
goto done;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "%sUnknown warning level.\n", cliargs_error);
|
fprintf(stderr, "%sUnknown warning level.\n", cliargs_error);
|
||||||
@ -536,6 +540,7 @@ done:
|
|||||||
// guess what
|
// guess what
|
||||||
int main(int argc, const char *argv[])
|
int main(int argc, const char *argv[])
|
||||||
{
|
{
|
||||||
|
config_default(&config);
|
||||||
// if called without any arguments, show usage info (not full help)
|
// if called without any arguments, show usage info (not full help)
|
||||||
if (argc == 1)
|
if (argc == 1)
|
||||||
show_help_and_exit();
|
show_help_and_exit();
|
||||||
|
60
src/alu.c
60
src/alu.c
@ -1,5 +1,5 @@
|
|||||||
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
||||||
// Copyright (C) 1998-2016 Marco Baye
|
// Copyright (C) 1998-2017 Marco Baye
|
||||||
// Have a look at "acme.c" for further info
|
// Have a look at "acme.c" for further info
|
||||||
//
|
//
|
||||||
// Arithmetic/logic unit
|
// Arithmetic/logic unit
|
||||||
@ -320,12 +320,12 @@ static intval_t my_asr(intval_t left, intval_t right)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if undefined, remember name for error output
|
// if undefined, remember name for error output
|
||||||
static void check_for_def(int flags, int prefix, char *name, size_t length)
|
static void check_for_def(int flags, char optional_prefix_char, char *name, size_t length)
|
||||||
{
|
{
|
||||||
if ((flags & MVALUE_DEFINED) == 0) {
|
if ((flags & MVALUE_DEFINED) == 0) {
|
||||||
DYNABUF_CLEAR(undefsym_dyna_buf);
|
DYNABUF_CLEAR(undefsym_dyna_buf);
|
||||||
if (prefix) {
|
if (optional_prefix_char) {
|
||||||
DynaBuf_append(undefsym_dyna_buf, LOCAL_PREFIX);
|
DynaBuf_append(undefsym_dyna_buf, optional_prefix_char);
|
||||||
length++;
|
length++;
|
||||||
}
|
}
|
||||||
DynaBuf_add_string(undefsym_dyna_buf, name);
|
DynaBuf_add_string(undefsym_dyna_buf, name);
|
||||||
@ -344,14 +344,14 @@ static void check_for_def(int flags, int prefix, char *name, size_t length)
|
|||||||
// their internal name is different (longer) than their displayed name.
|
// their internal name is different (longer) than their displayed name.
|
||||||
// This function is not allowed to change DynaBuf because that's where the
|
// This function is not allowed to change DynaBuf because that's where the
|
||||||
// symbol name is stored!
|
// symbol name is stored!
|
||||||
static void get_symbol_value(scope_t scope, int prefix, size_t name_length)
|
static void get_symbol_value(scope_t scope, char optional_prefix_char, size_t name_length)
|
||||||
{
|
{
|
||||||
struct symbol *symbol;
|
struct symbol *symbol;
|
||||||
|
|
||||||
// if the symbol gets created now, mark it as unsure
|
// if the symbol gets created now, mark it as unsure
|
||||||
symbol = symbol_find(scope, MVALUE_UNSURE);
|
symbol = symbol_find(scope, MVALUE_UNSURE);
|
||||||
// if needed, remember name for "undefined" error output
|
// if needed, remember name for "undefined" error output
|
||||||
check_for_def(symbol->result.flags, prefix, GLOBALDYNABUF_CURRENT, name_length);
|
check_for_def(symbol->result.flags, optional_prefix_char, GLOBALDYNABUF_CURRENT, name_length);
|
||||||
// in first pass, count usage
|
// in first pass, count usage
|
||||||
if (pass_count == 0)
|
if (pass_count == 0)
|
||||||
symbol->usage++;
|
symbol->usage++;
|
||||||
@ -374,7 +374,7 @@ static void parse_quoted_character(char closing_quote)
|
|||||||
// on empty string, complain
|
// on empty string, complain
|
||||||
if (GotByte == closing_quote) {
|
if (GotByte == closing_quote) {
|
||||||
Throw_error(exception_missing_string);
|
Throw_error(exception_missing_string);
|
||||||
Input_skip_remainder();
|
alu_state = STATE_ERROR;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -387,7 +387,7 @@ static void parse_quoted_character(char closing_quote)
|
|||||||
if (GotByte) {
|
if (GotByte) {
|
||||||
// if longer than one character
|
// if longer than one character
|
||||||
Throw_error("There's more than one character.");
|
Throw_error("There's more than one character.");
|
||||||
Input_skip_remainder();
|
alu_state = STATE_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PUSH_INTOPERAND(value, MVALUE_GIVEN | MVALUE_ISBYTE, 0);
|
PUSH_INTOPERAND(value, MVALUE_GIVEN | MVALUE_ISBYTE, 0);
|
||||||
@ -593,10 +593,12 @@ static void parse_function_call(void)
|
|||||||
// make lower case version of name in local dynamic buffer
|
// make lower case version of name in local dynamic buffer
|
||||||
DynaBuf_to_lower(function_dyna_buf, GlobalDynaBuf);
|
DynaBuf_to_lower(function_dyna_buf, GlobalDynaBuf);
|
||||||
// search for tree item
|
// search for tree item
|
||||||
if (Tree_easy_scan(function_tree, &node_body, function_dyna_buf))
|
if (Tree_easy_scan(function_tree, &node_body, function_dyna_buf)) {
|
||||||
PUSH_OPERATOR((struct operator *) node_body);
|
PUSH_OPERATOR((struct operator *) node_body);
|
||||||
else
|
} else {
|
||||||
Throw_error("Unknown function.");
|
Throw_error("Unknown function.");
|
||||||
|
alu_state = STATE_ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -617,7 +619,7 @@ static void expect_operand_or_monadic_operator(void)
|
|||||||
while (GetByte() == '+');
|
while (GetByte() == '+');
|
||||||
ugly_length_kluge = GlobalDynaBuf->size; // FIXME - get rid of this!
|
ugly_length_kluge = GlobalDynaBuf->size; // FIXME - get rid of this!
|
||||||
symbol_fix_forward_anon_name(FALSE); // FALSE: do not increment counter
|
symbol_fix_forward_anon_name(FALSE); // FALSE: do not increment counter
|
||||||
get_symbol_value(section_now->scope, 0, ugly_length_kluge);
|
get_symbol_value(section_now->local_scope, 0, ugly_length_kluge);
|
||||||
goto now_expect_dyadic;
|
goto now_expect_dyadic;
|
||||||
|
|
||||||
case '-': // NEGATION operator or anonymous backward label
|
case '-': // NEGATION operator or anonymous backward label
|
||||||
@ -631,7 +633,7 @@ static void expect_operand_or_monadic_operator(void)
|
|||||||
SKIPSPACE();
|
SKIPSPACE();
|
||||||
if (BYTEFLAGS(GotByte) & FOLLOWS_ANON) {
|
if (BYTEFLAGS(GotByte) & FOLLOWS_ANON) {
|
||||||
DynaBuf_append(GlobalDynaBuf, '\0');
|
DynaBuf_append(GlobalDynaBuf, '\0');
|
||||||
get_symbol_value(section_now->scope, 0, GlobalDynaBuf->size - 1); // -1 to not count terminator
|
get_symbol_value(section_now->local_scope, 0, GlobalDynaBuf->size - 1); // -1 to not count terminator
|
||||||
goto now_expect_dyadic;
|
goto now_expect_dyadic;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -704,10 +706,23 @@ static void expect_operand_or_monadic_operator(void)
|
|||||||
|
|
||||||
if (Input_read_keyword()) {
|
if (Input_read_keyword()) {
|
||||||
// Now GotByte = illegal char
|
// Now GotByte = illegal char
|
||||||
get_symbol_value(section_now->scope, 1, GlobalDynaBuf->size - 1); // -1 to not count terminator
|
get_symbol_value(section_now->local_scope, LOCAL_PREFIX, GlobalDynaBuf->size - 1); // -1 to not count terminator
|
||||||
goto now_expect_dyadic;
|
goto now_expect_dyadic;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we're here, Input_read_keyword() will have thrown an error (like "no string given"):
|
||||||
|
alu_state = STATE_ERROR;
|
||||||
|
break;
|
||||||
|
case CHEAP_PREFIX: // cheap local symbol
|
||||||
|
//printf("looking in cheap scope %d\n", section_now->cheap_scope);
|
||||||
|
GetByte(); // start after '@'
|
||||||
|
if (Input_read_keyword()) {
|
||||||
|
// Now GotByte = illegal char
|
||||||
|
get_symbol_value(section_now->cheap_scope, CHEAP_PREFIX, GlobalDynaBuf->size - 1); // -1 to not count terminator
|
||||||
|
goto now_expect_dyadic;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we're here, Input_read_keyword() will have thrown an error (like "no string given"):
|
||||||
alu_state = STATE_ERROR;
|
alu_state = STATE_ERROR;
|
||||||
break;
|
break;
|
||||||
// decimal values and global symbols
|
// decimal values and global symbols
|
||||||
@ -772,7 +787,9 @@ get_byte_and_push_monadic:
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
now_expect_dyadic:
|
now_expect_dyadic:
|
||||||
alu_state = STATE_EXPECT_DYADIC_OPERATOR;
|
// bugfix: if in error state, do not change state back to valid one
|
||||||
|
if (alu_state < STATE_MAX_GO_ON)
|
||||||
|
alu_state = STATE_EXPECT_DYADIC_OPERATOR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1051,7 +1068,8 @@ static void try_to_reduce_stacks(int *open_parentheses)
|
|||||||
break;
|
break;
|
||||||
case OPHANDLE_CLOSING:
|
case OPHANDLE_CLOSING:
|
||||||
Throw_error("Too many ')'.");
|
Throw_error("Too many ')'.");
|
||||||
goto remove_next_to_last_operator;
|
alu_state = STATE_ERROR;
|
||||||
|
return;
|
||||||
|
|
||||||
// functions
|
// functions
|
||||||
case OPHANDLE_ADDR:
|
case OPHANDLE_ADDR:
|
||||||
@ -1471,8 +1489,16 @@ static int parse_expression(struct result *result)
|
|||||||
result->flags |= MVALUE_ISBYTE;
|
result->flags |= MVALUE_ISBYTE;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// State is STATE_ERROR. But actually, nobody cares.
|
// State is STATE_ERROR. Errors have already been reported,
|
||||||
// ...errors have already been reported anyway. :)
|
// but we must make sure not to pass bogus data to caller.
|
||||||
|
result->flags = 0; // maybe set DEFINED flag to suppress follow-up errors?
|
||||||
|
result->val.intval = 0;
|
||||||
|
result->addr_refs = 0;
|
||||||
|
// make sure no additional (spurious) errors are reported:
|
||||||
|
Input_skip_remainder();
|
||||||
|
// FIXME - remove this when new function interface gets used:
|
||||||
|
// callers must decide for themselves what to do when expression parser returns error
|
||||||
|
// (currently LDA'' results in both "no string given" AND "illegal combination of command and addressing mode"!)
|
||||||
}
|
}
|
||||||
// return number of open (unmatched) parentheses
|
// return number of open (unmatched) parentheses
|
||||||
return open_parentheses;
|
return open_parentheses;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
||||||
// Copyright (C) 1998-2016 Marco Baye
|
// Copyright (C) 1998-2017 Marco Baye
|
||||||
// Have a look at "acme.c" for further info
|
// Have a look at "acme.c" for further info
|
||||||
//
|
//
|
||||||
// Flow control stuff (loops, conditional assembly etc.)
|
// Flow control stuff (loops, conditional assembly etc.)
|
||||||
@ -225,7 +225,7 @@ void flow_parse_block_else_block(int parse_first)
|
|||||||
void flow_parse_and_close_file(FILE *fd, const char *filename)
|
void flow_parse_and_close_file(FILE *fd, const char *filename)
|
||||||
{
|
{
|
||||||
// be verbose
|
// be verbose
|
||||||
if (Process_verbosity > 2)
|
if (config.process_verbosity > 2)
|
||||||
printf("Parsing source file '%s'\n", filename);
|
printf("Parsing source file '%s'\n", filename);
|
||||||
// set up new input
|
// set up new input
|
||||||
Input_new_file(filename, fd);
|
Input_new_file(filename, fd);
|
||||||
|
129
src/global.c
129
src/global.c
@ -1,5 +1,5 @@
|
|||||||
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
||||||
// Copyright (C) 1998-2016 Marco Baye
|
// Copyright (C) 1998-2017 Marco Baye
|
||||||
// Have a look at "acme.c" for further info
|
// Have a look at "acme.c" for further info
|
||||||
//
|
//
|
||||||
// Global stuff - things that are needed by several modules
|
// Global stuff - things that are needed by several modules
|
||||||
@ -109,19 +109,27 @@ const char Byte_flags[256] = {
|
|||||||
// variables
|
// variables
|
||||||
int pass_count; // number of current pass (starts 0)
|
int pass_count; // number of current pass (starts 0)
|
||||||
char GotByte; // Last byte read (processed)
|
char GotByte; // Last byte read (processed)
|
||||||
int Process_verbosity = 0; // Level of additional output
|
|
||||||
int warn_on_indented_labels = TRUE; // warn if indented label is encountered
|
|
||||||
int warn_on_old_for = TRUE; // warn if "!for" with old syntax is found
|
|
||||||
int warn_on_type_mismatch = FALSE; // use type-checking system
|
|
||||||
// global counters
|
// global counters
|
||||||
int pass_undefined_count; // "NeedValue" type errors
|
int pass_undefined_count; // "NeedValue" type errors
|
||||||
int pass_real_errors; // Errors yet
|
int pass_real_errors; // Errors yet
|
||||||
signed long max_errors = MAXERRORS; // errors before giving up
|
|
||||||
FILE *msg_stream = NULL; // set to stdout by --use-stdout
|
FILE *msg_stream = NULL; // set to stdout by --use-stdout
|
||||||
int format_msvc = FALSE; // actually bool, enabled by --msvc
|
|
||||||
int format_color = FALSE; // actually bool, enabled by --color
|
|
||||||
struct report *report = NULL;
|
struct report *report = NULL;
|
||||||
|
|
||||||
|
// configuration
|
||||||
|
struct config config;
|
||||||
|
|
||||||
|
// set configuration to default values
|
||||||
|
void config_default(struct config *conf)
|
||||||
|
{
|
||||||
|
conf->pseudoop_prefix = '!'; // can be changed to '.' by CLI switch
|
||||||
|
conf->process_verbosity = 0; // level of additional output
|
||||||
|
conf->warn_on_indented_labels = TRUE; // warn if indented label is encountered
|
||||||
|
conf->warn_on_old_for = TRUE; // warn if "!for" with old syntax is found
|
||||||
|
conf->warn_on_type_mismatch = FALSE; // use type-checking system
|
||||||
|
conf->max_errors = MAXERRORS; // errors before giving up
|
||||||
|
conf->format_msvc = FALSE; // actually bool, enabled by --msvc
|
||||||
|
conf->format_color = FALSE; // actually bool, enabled by --color
|
||||||
|
}
|
||||||
|
|
||||||
// memory allocation stuff
|
// memory allocation stuff
|
||||||
|
|
||||||
@ -184,14 +192,14 @@ static void parse_mnemo_or_global_symbol_def(int *statement_flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// parse local symbol definition
|
// parse (cheap) local symbol definition
|
||||||
static void parse_local_symbol_def(int *statement_flags)
|
static void parse_local_symbol_def(int *statement_flags, scope_t scope)
|
||||||
{
|
{
|
||||||
if (!first_label_of_statement(statement_flags))
|
if (!first_label_of_statement(statement_flags))
|
||||||
return;
|
return;
|
||||||
GetByte(); // start after '.'
|
GetByte(); // start after '.'/'@'
|
||||||
if (Input_read_keyword())
|
if (Input_read_keyword())
|
||||||
symbol_parse_definition(section_now->scope, *statement_flags);
|
symbol_parse_definition(scope, *statement_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -205,7 +213,7 @@ static void parse_backward_anon_def(int *statement_flags)
|
|||||||
DYNABUF_APPEND(GlobalDynaBuf, '-');
|
DYNABUF_APPEND(GlobalDynaBuf, '-');
|
||||||
while (GetByte() == '-');
|
while (GetByte() == '-');
|
||||||
DynaBuf_append(GlobalDynaBuf, '\0');
|
DynaBuf_append(GlobalDynaBuf, '\0');
|
||||||
symbol_set_label(section_now->scope, *statement_flags, 0, TRUE); // this "TRUE" is the whole secret
|
symbol_set_label(section_now->local_scope, *statement_flags, 0, TRUE); // this "TRUE" is the whole secret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -222,8 +230,8 @@ static void parse_forward_anon_def(int *statement_flags)
|
|||||||
}
|
}
|
||||||
symbol_fix_forward_anon_name(TRUE); // TRUE: increment counter
|
symbol_fix_forward_anon_name(TRUE); // TRUE: increment counter
|
||||||
DynaBuf_append(GlobalDynaBuf, '\0');
|
DynaBuf_append(GlobalDynaBuf, '\0');
|
||||||
//printf("[%d, %s]\n", section_now->scope, GlobalDynaBuf->buffer);
|
//printf("[%d, %s]\n", section_now->local_scope, GlobalDynaBuf->buffer);
|
||||||
symbol_set_label(section_now->scope, *statement_flags, 0, FALSE);
|
symbol_set_label(section_now->local_scope, *statement_flags, 0, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -245,45 +253,51 @@ void Parse_until_eob_or_eof(void)
|
|||||||
typesystem_force_address_statement(FALSE);
|
typesystem_force_address_statement(FALSE);
|
||||||
// Parse until end of statement. Only loops if statement
|
// Parse until end of statement. Only loops if statement
|
||||||
// contains "label = pc" definition and something else; or
|
// contains "label = pc" definition and something else; or
|
||||||
// if "!ifdef" is true, or if "!addr" is used without block.
|
// if "!ifdef/ifndef" is true/false, or if "!addr" is used without block.
|
||||||
do {
|
do {
|
||||||
switch (GotByte) {
|
// check for pseudo opcodes was moved out of switch,
|
||||||
case CHAR_EOS: // end of statement
|
// because prefix character is now configurable.
|
||||||
// Ignore now, act later
|
if (GotByte == config.pseudoop_prefix) {
|
||||||
// (stops from being "default")
|
|
||||||
break;
|
|
||||||
case ' ': // space
|
|
||||||
statement_flags |= SF_FOUND_BLANK;
|
|
||||||
/*FALLTHROUGH*/
|
|
||||||
case CHAR_SOL: // start of line
|
|
||||||
GetByte(); // skip
|
|
||||||
break;
|
|
||||||
case '-':
|
|
||||||
parse_backward_anon_def(&statement_flags);
|
|
||||||
break;
|
|
||||||
case '+':
|
|
||||||
GetByte();
|
|
||||||
if ((GotByte == LOCAL_PREFIX)
|
|
||||||
|| (BYTEFLAGS(GotByte) & CONTS_KEYWORD))
|
|
||||||
Macro_parse_call();
|
|
||||||
else
|
|
||||||
parse_forward_anon_def(&statement_flags);
|
|
||||||
break;
|
|
||||||
case PSEUDO_OPCODE_PREFIX:
|
|
||||||
pseudoopcode_parse();
|
pseudoopcode_parse();
|
||||||
break;
|
} else {
|
||||||
case '*':
|
switch (GotByte) {
|
||||||
parse_pc_def();
|
case CHAR_EOS: // end of statement
|
||||||
break;
|
// Ignore now, act later
|
||||||
case LOCAL_PREFIX:
|
// (stops from being "default")
|
||||||
parse_local_symbol_def(&statement_flags);
|
break;
|
||||||
break;
|
case ' ': // space
|
||||||
default:
|
statement_flags |= SF_FOUND_BLANK;
|
||||||
if (BYTEFLAGS(GotByte) & STARTS_KEYWORD) {
|
/*FALLTHROUGH*/
|
||||||
parse_mnemo_or_global_symbol_def(&statement_flags);
|
case CHAR_SOL: // start of line
|
||||||
} else {
|
GetByte(); // skip
|
||||||
Throw_error(exception_syntax);
|
break;
|
||||||
Input_skip_remainder();
|
case '-':
|
||||||
|
parse_backward_anon_def(&statement_flags);
|
||||||
|
break;
|
||||||
|
case '+':
|
||||||
|
GetByte();
|
||||||
|
if ((GotByte == LOCAL_PREFIX) // TODO - allow "cheap macros"?!
|
||||||
|
|| (BYTEFLAGS(GotByte) & CONTS_KEYWORD))
|
||||||
|
Macro_parse_call();
|
||||||
|
else
|
||||||
|
parse_forward_anon_def(&statement_flags);
|
||||||
|
break;
|
||||||
|
case '*':
|
||||||
|
parse_pc_def();
|
||||||
|
break;
|
||||||
|
case LOCAL_PREFIX:
|
||||||
|
parse_local_symbol_def(&statement_flags, section_now->local_scope);
|
||||||
|
break;
|
||||||
|
case CHEAP_PREFIX:
|
||||||
|
parse_local_symbol_def(&statement_flags, section_now->cheap_scope);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (BYTEFLAGS(GotByte) & STARTS_KEYWORD) {
|
||||||
|
parse_mnemo_or_global_symbol_def(&statement_flags);
|
||||||
|
} else {
|
||||||
|
Throw_error(exception_syntax);
|
||||||
|
Input_skip_remainder();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} while (GotByte != CHAR_EOS); // until end-of-statement
|
} while (GotByte != CHAR_EOS); // until end-of-statement
|
||||||
@ -322,10 +336,11 @@ int Throw_get_counter(void)
|
|||||||
// This function will do the actual output for warnings, errors and serious
|
// This function will do the actual output for warnings, errors and serious
|
||||||
// errors. It shows the given message string, as well as the current
|
// errors. It shows the given message string, as well as the current
|
||||||
// context: file name, line number, source type and source title.
|
// context: file name, line number, source type and source title.
|
||||||
|
// TODO: make un-static so !info and !debug can use this.
|
||||||
static void throw_message(const char *message, const char *type)
|
static void throw_message(const char *message, const char *type)
|
||||||
{
|
{
|
||||||
++throw_counter;
|
++throw_counter;
|
||||||
if (format_msvc)
|
if (config.format_msvc)
|
||||||
fprintf(msg_stream, "%s(%d) : %s (%s %s): %s\n",
|
fprintf(msg_stream, "%s(%d) : %s (%s %s): %s\n",
|
||||||
Input_now->original_filename, Input_now->line_number,
|
Input_now->original_filename, Input_now->line_number,
|
||||||
type, section_now->type, section_now->title, message);
|
type, section_now->type, section_now->title, message);
|
||||||
@ -343,7 +358,7 @@ static void throw_message(const char *message, const char *type)
|
|||||||
void Throw_warning(const char *message)
|
void Throw_warning(const char *message)
|
||||||
{
|
{
|
||||||
PLATFORM_WARNING(message);
|
PLATFORM_WARNING(message);
|
||||||
if (format_color)
|
if (config.format_color)
|
||||||
throw_message(message, "\033[33mWarning\033[0m");
|
throw_message(message, "\033[33mWarning\033[0m");
|
||||||
else
|
else
|
||||||
throw_message(message, "Warning");
|
throw_message(message, "Warning");
|
||||||
@ -364,12 +379,12 @@ void Throw_first_pass_warning(const char *message)
|
|||||||
void Throw_error(const char *message)
|
void Throw_error(const char *message)
|
||||||
{
|
{
|
||||||
PLATFORM_ERROR(message);
|
PLATFORM_ERROR(message);
|
||||||
if (format_color)
|
if (config.format_color)
|
||||||
throw_message(message, "\033[31mError\033[0m");
|
throw_message(message, "\033[31mError\033[0m");
|
||||||
else
|
else
|
||||||
throw_message(message, "Error");
|
throw_message(message, "Error");
|
||||||
++pass_real_errors;
|
++pass_real_errors;
|
||||||
if (pass_real_errors >= max_errors)
|
if (pass_real_errors >= config.max_errors)
|
||||||
exit(ACME_finalize(EXIT_FAILURE));
|
exit(ACME_finalize(EXIT_FAILURE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,7 +396,7 @@ void Throw_error(const char *message)
|
|||||||
void Throw_serious_error(const char *message)
|
void Throw_serious_error(const char *message)
|
||||||
{
|
{
|
||||||
PLATFORM_SERIOUS(message);
|
PLATFORM_SERIOUS(message);
|
||||||
if (format_color)
|
if (config.format_color)
|
||||||
throw_message(message, "\033[1m\033[31mSerious error\033[0m");
|
throw_message(message, "\033[1m\033[31mSerious error\033[0m");
|
||||||
else
|
else
|
||||||
throw_message(message, "Serious error");
|
throw_message(message, "Serious error");
|
||||||
|
28
src/global.h
28
src/global.h
@ -1,5 +1,5 @@
|
|||||||
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
||||||
// Copyright (C) 1998-2016 Marco Baye
|
// Copyright (C) 1998-2017 Marco Baye
|
||||||
// Have a look at "acme.c" for further info
|
// Have a look at "acme.c" for further info
|
||||||
//
|
//
|
||||||
// Global stuff - things that are needed by several modules
|
// Global stuff - things that are needed by several modules
|
||||||
@ -14,8 +14,8 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#define PSEUDO_OPCODE_PREFIX '!' // FIXME - this is not yet used consistently!
|
|
||||||
#define LOCAL_PREFIX '.' // FIXME - this is not yet used consistently!
|
#define LOCAL_PREFIX '.' // FIXME - this is not yet used consistently!
|
||||||
|
#define CHEAP_PREFIX '@' // prefix character for cheap locals
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
|
|
||||||
@ -60,20 +60,24 @@ extern const char Byte_flags[];
|
|||||||
#define FOLLOWS_ANON (1u << 3) // preceding '-' are backward label
|
#define FOLLOWS_ANON (1u << 3) // preceding '-' are backward label
|
||||||
// bits 2, 1 and 0 are currently unused
|
// bits 2, 1 and 0 are currently unused
|
||||||
|
|
||||||
// TODO - put in config/runtime structs:
|
// TODO - put in runtime struct:
|
||||||
extern int pass_count;
|
extern int pass_count;
|
||||||
extern int Process_verbosity; // Level of additional output
|
|
||||||
extern int warn_on_indented_labels; // warn if indented label is encountered
|
|
||||||
extern int warn_on_old_for; // warn if "!for" with old syntax is found
|
|
||||||
extern int warn_on_type_mismatch; // use type-checking system
|
|
||||||
extern char GotByte; // Last byte read (processed)
|
extern char GotByte; // Last byte read (processed)
|
||||||
// global counters
|
|
||||||
extern int pass_undefined_count; // "NeedValue" type errors in current pass
|
extern int pass_undefined_count; // "NeedValue" type errors in current pass
|
||||||
extern int pass_real_errors; // Errors yet
|
extern int pass_real_errors; // Errors yet
|
||||||
extern signed long max_errors; // errors before giving up
|
|
||||||
extern FILE *msg_stream; // set to stdout by --errors_to_stdout
|
extern FILE *msg_stream; // set to stdout by --errors_to_stdout
|
||||||
extern int format_msvc; // actually bool, enabled by --msvc
|
// configuration
|
||||||
extern int format_color; // actually bool, enabled by --color
|
struct config {
|
||||||
|
char pseudoop_prefix; // '!' or '.'
|
||||||
|
int process_verbosity; // level of additional output
|
||||||
|
int warn_on_indented_labels; // warn if indented label is encountered
|
||||||
|
int warn_on_old_for; // warn if "!for" with old syntax is found
|
||||||
|
int warn_on_type_mismatch; // use type-checking system
|
||||||
|
signed long max_errors; // errors before giving up
|
||||||
|
int format_msvc; // actually bool, enabled by --msvc
|
||||||
|
int format_color; // actually bool, enabled by --color
|
||||||
|
};
|
||||||
|
extern struct config config;
|
||||||
|
|
||||||
// report stuff
|
// report stuff
|
||||||
#define REPORT_ASCBUFSIZE 1024
|
#define REPORT_ASCBUFSIZE 1024
|
||||||
@ -104,6 +108,8 @@ do { \
|
|||||||
|
|
||||||
// Prototypes
|
// Prototypes
|
||||||
|
|
||||||
|
// set configuration to default values
|
||||||
|
extern void config_default(struct config *conf);
|
||||||
// allocate memory and die if not available
|
// allocate memory and die if not available
|
||||||
extern void *safe_malloc(size_t);
|
extern void *safe_malloc(size_t);
|
||||||
// Parse block, beginning with next byte.
|
// Parse block, beginning with next byte.
|
||||||
|
15
src/input.c
15
src/input.c
@ -1,5 +1,5 @@
|
|||||||
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
||||||
// Copyright (C) 1998-2016 Marco Baye
|
// Copyright (C) 1998-2017 Marco Baye
|
||||||
// Have a look at "acme.c" for further info
|
// Have a look at "acme.c" for further info
|
||||||
//
|
//
|
||||||
// Input stuff
|
// Input stuff
|
||||||
@ -421,19 +421,20 @@ int Input_append_keyword_to_global_dynabuf(void)
|
|||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether GotByte is LOCAL_PREFIX (default '.').
|
// Check GotByte.
|
||||||
// If not, store global scope value.
|
// If LOCAL_PREFIX ('.'), store current local scope value and read next byte.
|
||||||
// If yes, store current local scope value and read next byte.
|
// If CHEAP_PREFIX ('@'), store current cheap scope value and read next byte.
|
||||||
|
// Otherwise, store global scope value.
|
||||||
// Then jump to Input_read_keyword(), which returns length of keyword.
|
// Then jump to Input_read_keyword(), which returns length of keyword.
|
||||||
int Input_read_scope_and_keyword(scope_t *scope)
|
int Input_read_scope_and_keyword(scope_t *scope)
|
||||||
{
|
{
|
||||||
SKIPSPACE();
|
SKIPSPACE();
|
||||||
if (GotByte == LOCAL_PREFIX) {
|
if (GotByte == LOCAL_PREFIX) {
|
||||||
GetByte();
|
GetByte();
|
||||||
*scope = section_now->scope;
|
*scope = section_now->local_scope;
|
||||||
/* TODO } else if (GotByte == CHEAP_PREFIX) {
|
} else if (GotByte == CHEAP_PREFIX) {
|
||||||
GetByte();
|
GetByte();
|
||||||
*scope = symbol_cheap_scope; */
|
*scope = section_now->cheap_scope;
|
||||||
} else {
|
} else {
|
||||||
*scope = SCOPE_GLOBAL;
|
*scope = SCOPE_GLOBAL;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
||||||
// Copyright (C) 1998-2016 Marco Baye
|
// Copyright (C) 1998-2017 Marco Baye
|
||||||
// Have a look at "acme.c" for further info
|
// Have a look at "acme.c" for further info
|
||||||
//
|
//
|
||||||
// Input stuff
|
// Input stuff
|
||||||
@ -83,9 +83,10 @@ extern void Input_until_terminator(char terminator);
|
|||||||
// Append to GlobalDynaBuf while characters are legal for keywords.
|
// Append to GlobalDynaBuf while characters are legal for keywords.
|
||||||
// Throws "missing string" error if none. Returns number of characters added.
|
// Throws "missing string" error if none. Returns number of characters added.
|
||||||
extern int Input_append_keyword_to_global_dynabuf(void);
|
extern int Input_append_keyword_to_global_dynabuf(void);
|
||||||
// Check whether GotByte is a dot.
|
// Check GotByte.
|
||||||
// If not, store global scope value.
|
// If LOCAL_PREFIX ('.'), store current local scope value and read next byte.
|
||||||
// If yes, store current scope value and read next byte.
|
// If CHEAP_PREFIX ('@'), store current cheap scope value and read next byte.
|
||||||
|
// Otherwise, store global scope value.
|
||||||
// Then jump to Input_read_keyword(), which returns length of keyword.
|
// Then jump to Input_read_keyword(), which returns length of keyword.
|
||||||
extern int Input_read_scope_and_keyword(scope_t *scope);
|
extern int Input_read_scope_and_keyword(scope_t *scope);
|
||||||
// Clear dynamic buffer, then append to it until an illegal (for a keyword)
|
// Clear dynamic buffer, then append to it until an illegal (for a keyword)
|
||||||
|
16
src/macro.c
16
src/macro.c
@ -1,5 +1,5 @@
|
|||||||
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
||||||
// Copyright (C) 1998-2016 Marco Baye
|
// Copyright (C) 1998-2017 Marco Baye
|
||||||
// Have a look at "acme.c" for further info
|
// Have a look at "acme.c" for further info
|
||||||
//
|
//
|
||||||
// Macro stuff
|
// Macro stuff
|
||||||
@ -88,8 +88,10 @@ static scope_t get_scope_and_title(void)
|
|||||||
// copy macro title to private dynabuf and add separator character
|
// copy macro title to private dynabuf and add separator character
|
||||||
DYNABUF_CLEAR(user_macro_name);
|
DYNABUF_CLEAR(user_macro_name);
|
||||||
DYNABUF_CLEAR(internal_name);
|
DYNABUF_CLEAR(internal_name);
|
||||||
if (macro_scope != SCOPE_GLOBAL)
|
if (macro_scope != SCOPE_GLOBAL) {
|
||||||
|
// TODO - allow "cheap macros"?!
|
||||||
DynaBuf_append(user_macro_name, LOCAL_PREFIX);
|
DynaBuf_append(user_macro_name, LOCAL_PREFIX);
|
||||||
|
}
|
||||||
DynaBuf_add_string(user_macro_name, GLOBALDYNABUF_CURRENT);
|
DynaBuf_add_string(user_macro_name, GLOBALDYNABUF_CURRENT);
|
||||||
DynaBuf_add_string(internal_name, GLOBALDYNABUF_CURRENT);
|
DynaBuf_add_string(internal_name, GLOBALDYNABUF_CURRENT);
|
||||||
DynaBuf_append(user_macro_name, '\0');
|
DynaBuf_append(user_macro_name, '\0');
|
||||||
@ -174,6 +176,8 @@ void Macro_parse_definition(void) // Now GotByte = illegal char after "!macro"
|
|||||||
// Valid argument formats are:
|
// Valid argument formats are:
|
||||||
// .LOCAL_LABEL_BY_VALUE
|
// .LOCAL_LABEL_BY_VALUE
|
||||||
// ~.LOCAL_LABEL_BY_REFERENCE
|
// ~.LOCAL_LABEL_BY_REFERENCE
|
||||||
|
// @CHEAP_LOCAL_LABEL_BY_VALUE
|
||||||
|
// ~@CHEAP_LOCAL_LABEL_BY_REFERENCE
|
||||||
// GLOBAL_LABEL_BY_VALUE global args are very uncommon,
|
// GLOBAL_LABEL_BY_VALUE global args are very uncommon,
|
||||||
// ~GLOBAL_LABEL_BY_REFERENCE but not forbidden
|
// ~GLOBAL_LABEL_BY_REFERENCE but not forbidden
|
||||||
// now GotByte = non-space
|
// now GotByte = non-space
|
||||||
@ -187,9 +191,10 @@ void Macro_parse_definition(void) // Now GotByte = illegal char after "!macro"
|
|||||||
DynaBuf_append(GlobalDynaBuf, REFERENCE_CHAR);
|
DynaBuf_append(GlobalDynaBuf, REFERENCE_CHAR);
|
||||||
GetByte();
|
GetByte();
|
||||||
}
|
}
|
||||||
// handle prefix for local symbols (LOCAL_PREFIX, normally '.')
|
// handle prefix for (cheap) local symbols ('.'/'@')
|
||||||
if (GotByte == LOCAL_PREFIX) {
|
if ((GotByte == LOCAL_PREFIX)
|
||||||
DynaBuf_append(GlobalDynaBuf, LOCAL_PREFIX);
|
|| (GotByte == CHEAP_PREFIX)) {
|
||||||
|
DynaBuf_append(GlobalDynaBuf, GotByte);
|
||||||
GetByte();
|
GetByte();
|
||||||
}
|
}
|
||||||
// handle symbol name
|
// handle symbol name
|
||||||
@ -304,6 +309,7 @@ void Macro_parse_call(void) // Now GotByte = dot or first char of macro name
|
|||||||
// start new section (with new scope)
|
// start new section (with new scope)
|
||||||
// FALSE = title mustn't be freed
|
// FALSE = title mustn't be freed
|
||||||
section_new(&new_section, "Macro", actual_macro->original_name, FALSE);
|
section_new(&new_section, "Macro", actual_macro->original_name, FALSE);
|
||||||
|
section_new_cheap_scope(&new_section);
|
||||||
GetByte(); // fetch first byte of parameter list
|
GetByte(); // fetch first byte of parameter list
|
||||||
// assign arguments
|
// assign arguments
|
||||||
if (GotByte != CHAR_EOS) { // any at all?
|
if (GotByte != CHAR_EOS) { // any at all?
|
||||||
|
14
src/mnemo.c
14
src/mnemo.c
@ -827,6 +827,15 @@ static unsigned int imm_ops(int *force_bit, unsigned char opcode, int immediate_
|
|||||||
return (((unsigned int) opcode) << 8) | opcode;
|
return (((unsigned int) opcode) << 8) | opcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// helper function to warn if zp pointer wraps around
|
||||||
|
// call with bits=0 for 2-byte pointers and bits=1 for 3-byte pointers
|
||||||
|
static void check_zp_wraparound(struct result *result, int bits)
|
||||||
|
{
|
||||||
|
if (((result->val.intval | bits) == 0xff)
|
||||||
|
&& (result->flags & MVALUE_DEFINED))
|
||||||
|
Throw_warning("Zeropage pointer wraps around from $ff to $00");
|
||||||
|
}
|
||||||
|
|
||||||
// The main accumulator stuff (ADC, AND, CMP, EOR, LDA, ORA, SBC, STA)
|
// The main accumulator stuff (ADC, AND, CMP, EOR, LDA, ORA, SBC, STA)
|
||||||
// plus PEI.
|
// plus PEI.
|
||||||
static void group_main(int index, int immediate_mode)
|
static void group_main(int index, int immediate_mode)
|
||||||
@ -859,18 +868,23 @@ static void group_main(int index, int immediate_mode)
|
|||||||
break;
|
break;
|
||||||
case INDIRECT_ADDRESSING: // ($ff)
|
case INDIRECT_ADDRESSING: // ($ff)
|
||||||
make_command(force_bit, &result, accu_ind8[index]);
|
make_command(force_bit, &result, accu_ind8[index]);
|
||||||
|
check_zp_wraparound(&result, 0);
|
||||||
break;
|
break;
|
||||||
case INDIRECT_Y_INDEXED_ADDRESSING: // ($ff),y
|
case INDIRECT_Y_INDEXED_ADDRESSING: // ($ff),y
|
||||||
make_command(force_bit, &result, accu_indy8[index]);
|
make_command(force_bit, &result, accu_indy8[index]);
|
||||||
|
check_zp_wraparound(&result, 0);
|
||||||
break;
|
break;
|
||||||
case INDIRECT_Z_INDEXED_ADDRESSING: // ($ff),z
|
case INDIRECT_Z_INDEXED_ADDRESSING: // ($ff),z
|
||||||
make_command(force_bit, &result, accu_indz8[index]);
|
make_command(force_bit, &result, accu_indz8[index]);
|
||||||
|
check_zp_wraparound(&result, 0);
|
||||||
break;
|
break;
|
||||||
case LONG_INDIRECT_ADDRESSING: // [$ff]
|
case LONG_INDIRECT_ADDRESSING: // [$ff]
|
||||||
make_command(force_bit, &result, accu_lind8[index]);
|
make_command(force_bit, &result, accu_lind8[index]);
|
||||||
|
check_zp_wraparound(&result, 1);
|
||||||
break;
|
break;
|
||||||
case LONG_INDIRECT_Y_INDEXED_ADDRESSING: // [$ff],y
|
case LONG_INDIRECT_Y_INDEXED_ADDRESSING: // [$ff],y
|
||||||
make_command(force_bit, &result, accu_lindy8[index]);
|
make_command(force_bit, &result, accu_lindy8[index]);
|
||||||
|
check_zp_wraparound(&result, 1);
|
||||||
break;
|
break;
|
||||||
case STACK_INDEXED_INDIRECT_Y_INDEXED_ADDRESSING: // ($ff,s),y
|
case STACK_INDEXED_INDIRECT_Y_INDEXED_ADDRESSING: // ($ff,s),y
|
||||||
make_command(force_bit, &result, accu_sindy8[index]);
|
make_command(force_bit, &result, accu_sindy8[index]);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
||||||
// Copyright (C) 1998-2016 Marco Baye
|
// Copyright (C) 1998-2017 Marco Baye
|
||||||
// Have a look at "acme.c" for further info
|
// Have a look at "acme.c" for further info
|
||||||
//
|
//
|
||||||
// Output stuff
|
// Output stuff
|
||||||
@ -380,7 +380,7 @@ void Output_save_file(FILE *fd)
|
|||||||
start = out->lowest_written;
|
start = out->lowest_written;
|
||||||
amount = out->highest_written - start + 1;
|
amount = out->highest_written - start + 1;
|
||||||
}
|
}
|
||||||
if (Process_verbosity)
|
if (config.process_verbosity)
|
||||||
printf("Saving %ld (0x%lx) bytes (0x%lx - 0x%lx exclusive).\n",
|
printf("Saving %ld (0x%lx) bytes (0x%lx - 0x%lx exclusive).\n",
|
||||||
amount, amount, start, start + amount);
|
amount, amount, start, start + amount);
|
||||||
// output file header according to file format
|
// output file header according to file format
|
||||||
@ -514,7 +514,7 @@ void Output_end_segment(void)
|
|||||||
// link to segment list
|
// link to segment list
|
||||||
link_segment(out->segment.start, amount);
|
link_segment(out->segment.start, amount);
|
||||||
// announce
|
// announce
|
||||||
if (Process_verbosity > 1)
|
if (config.process_verbosity > 1)
|
||||||
printf("Segment size is %ld (0x%lx) bytes (0x%lx - 0x%lx exclusive).\n",
|
printf("Segment size is %ld (0x%lx) bytes (0x%lx - 0x%lx exclusive).\n",
|
||||||
amount, amount, out->segment.start, out->write_idx);
|
amount, amount, out->segment.start, out->write_idx);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
||||||
// Copyright (C) 1998-2016 Marco Baye
|
// Copyright (C) 1998-2017 Marco Baye
|
||||||
// Have a look at "acme.c" for further info
|
// Have a look at "acme.c" for further info
|
||||||
//
|
//
|
||||||
// pseudo opcode stuff
|
// pseudo opcode stuff
|
||||||
@ -201,7 +201,6 @@ static enum eos po_le32(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
// Insert bytes given as pairs of hex digits (helper for source code generators)
|
// Insert bytes given as pairs of hex digits (helper for source code generators)
|
||||||
static enum eos po_hex(void) // now GotByte = illegal char
|
static enum eos po_hex(void) // now GotByte = illegal char
|
||||||
{
|
{
|
||||||
@ -251,7 +250,6 @@ static enum eos po_hex(void) // now GotByte = illegal char
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// "!cbm" pseudo opcode (now obsolete)
|
// "!cbm" pseudo opcode (now obsolete)
|
||||||
@ -433,7 +431,7 @@ static enum eos po_binary(void)
|
|||||||
}
|
}
|
||||||
fclose(fd);
|
fclose(fd);
|
||||||
// if verbose, produce some output
|
// if verbose, produce some output
|
||||||
if ((pass_count == 0) && (Process_verbosity > 1)) {
|
if ((pass_count == 0) && (config.process_verbosity > 1)) {
|
||||||
int amount = vcpu_get_statement_size();
|
int amount = vcpu_get_statement_size();
|
||||||
|
|
||||||
printf("Loaded %d (0x%04x) bytes from file offset %ld (0x%04lx).\n",
|
printf("Loaded %d (0x%04x) bytes from file offset %ld (0x%04lx).\n",
|
||||||
@ -458,8 +456,7 @@ static enum eos po_fill(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
// skip over some bytes in output without starting a new segment.
|
||||||
// skip over some bytes in output without starting a new segment ("!skip" pseudo opcode)
|
|
||||||
// in contrast to "*=*+AMOUNT", "!skip AMOUNT" does not start a new segment.
|
// in contrast to "*=*+AMOUNT", "!skip AMOUNT" does not start a new segment.
|
||||||
// (...and it will be needed in future for assemble-to-end-address)
|
// (...and it will be needed in future for assemble-to-end-address)
|
||||||
static enum eos po_skip(void) // now GotByte = illegal char
|
static enum eos po_skip(void) // now GotByte = illegal char
|
||||||
@ -473,7 +470,6 @@ static enum eos po_skip(void) // now GotByte = illegal char
|
|||||||
output_skip(amount.val.intval);
|
output_skip(amount.val.intval);
|
||||||
return ENSURE_EOS;
|
return ENSURE_EOS;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// insert byte until PC fits condition
|
// insert byte until PC fits condition
|
||||||
@ -858,20 +854,20 @@ static enum eos po_for(void) // now GotByte = illegal char
|
|||||||
loop.counter.addr_refs = intresult.addr_refs;
|
loop.counter.addr_refs = intresult.addr_refs;
|
||||||
if (Input_accept_comma()) {
|
if (Input_accept_comma()) {
|
||||||
loop.old_algo = FALSE; // new format - yay!
|
loop.old_algo = FALSE; // new format - yay!
|
||||||
if (!warn_on_old_for)
|
if (!config.warn_on_old_for)
|
||||||
Throw_first_pass_warning("Found new \"!for\" syntax.");
|
Throw_first_pass_warning("Found new \"!for\" syntax.");
|
||||||
loop.counter.first = intresult.val.intval; // use first argument
|
loop.counter.first = intresult.val.intval; // use first argument
|
||||||
ALU_defined_int(&intresult); // read second argument
|
ALU_defined_int(&intresult); // read second argument
|
||||||
loop.counter.last = intresult.val.intval; // use second argument
|
loop.counter.last = intresult.val.intval; // use second argument
|
||||||
// compare addr_ref counts and complain if not equal!
|
// compare addr_ref counts and complain if not equal!
|
||||||
if (warn_on_type_mismatch
|
if (config.warn_on_type_mismatch
|
||||||
&& (intresult.addr_refs != loop.counter.addr_refs)) {
|
&& (intresult.addr_refs != loop.counter.addr_refs)) {
|
||||||
Throw_first_pass_warning("Wrong type for loop's END value - must match type of START value.");
|
Throw_first_pass_warning("Wrong type for loop's END value - must match type of START value.");
|
||||||
}
|
}
|
||||||
loop.counter.increment = (loop.counter.last < loop.counter.first) ? -1 : 1;
|
loop.counter.increment = (loop.counter.last < loop.counter.first) ? -1 : 1;
|
||||||
} else {
|
} else {
|
||||||
loop.old_algo = TRUE; // old format - booo!
|
loop.old_algo = TRUE; // old format - booo!
|
||||||
if (warn_on_old_for)
|
if (config.warn_on_old_for)
|
||||||
Throw_first_pass_warning("Found old \"!for\" syntax.");
|
Throw_first_pass_warning("Found old \"!for\" syntax.");
|
||||||
if (intresult.val.intval < 0)
|
if (intresult.val.intval < 0)
|
||||||
Throw_serious_error("Loop count is negative.");
|
Throw_serious_error("Loop count is negative.");
|
||||||
@ -1019,12 +1015,19 @@ static enum eos throw_string(const char prefix[], void (*fn)(const char *))
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
////
|
#if 0
|
||||||
//static enum eos po_debug(void)
|
// show debug data given in source code
|
||||||
//static enum eos po_info(void)
|
static enum eos po_debug(void)
|
||||||
//{
|
{
|
||||||
// return throw_string();
|
// FIXME - make debug output depend on some cli switch
|
||||||
//}
|
return throw_string("!debug: ", throw_message);
|
||||||
|
}
|
||||||
|
// show info given in source code
|
||||||
|
static enum eos po_info(void)
|
||||||
|
{
|
||||||
|
return throw_string("!info: ", throw_message);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// throw warning as given in source code
|
// throw warning as given in source code
|
||||||
@ -1077,6 +1080,8 @@ static struct ronode pseudo_opcode_list[] = {
|
|||||||
PREDEFNODE("32", po_32),
|
PREDEFNODE("32", po_32),
|
||||||
PREDEFNODE("be32", po_be32),
|
PREDEFNODE("be32", po_be32),
|
||||||
PREDEFNODE("le32", po_le32),
|
PREDEFNODE("le32", po_le32),
|
||||||
|
PREDEFNODE("h", po_hex),
|
||||||
|
PREDEFNODE("hex", po_hex),
|
||||||
PREDEFNODE(s_cbm, obsolete_po_cbm),
|
PREDEFNODE(s_cbm, obsolete_po_cbm),
|
||||||
PREDEFNODE("ct", po_convtab),
|
PREDEFNODE("ct", po_convtab),
|
||||||
PREDEFNODE("convtab", po_convtab),
|
PREDEFNODE("convtab", po_convtab),
|
||||||
@ -1090,6 +1095,7 @@ static struct ronode pseudo_opcode_list[] = {
|
|||||||
PREDEFNODE("binary", po_binary),
|
PREDEFNODE("binary", po_binary),
|
||||||
PREDEFNODE("fi", po_fill),
|
PREDEFNODE("fi", po_fill),
|
||||||
PREDEFNODE("fill", po_fill),
|
PREDEFNODE("fill", po_fill),
|
||||||
|
PREDEFNODE("skip", po_skip),
|
||||||
PREDEFNODE("align", po_align),
|
PREDEFNODE("align", po_align),
|
||||||
PREDEFNODE("pseudopc", po_pseudopc),
|
PREDEFNODE("pseudopc", po_pseudopc),
|
||||||
PREDEFNODE("realpc", obsolete_po_realpc),
|
PREDEFNODE("realpc", obsolete_po_realpc),
|
||||||
@ -1100,6 +1106,7 @@ static struct ronode pseudo_opcode_list[] = {
|
|||||||
PREDEFNODE("rs", po_rs),
|
PREDEFNODE("rs", po_rs),
|
||||||
PREDEFNODE("addr", po_address),
|
PREDEFNODE("addr", po_address),
|
||||||
PREDEFNODE("address", po_address),
|
PREDEFNODE("address", po_address),
|
||||||
|
// PREDEFNODE("enum", po_enum),
|
||||||
PREDEFNODE("set", po_set),
|
PREDEFNODE("set", po_set),
|
||||||
PREDEFNODE(s_sl, po_symbollist),
|
PREDEFNODE(s_sl, po_symbollist),
|
||||||
PREDEFNODE("symbollist", po_symbollist),
|
PREDEFNODE("symbollist", po_symbollist),
|
||||||
@ -1114,6 +1121,7 @@ static struct ronode pseudo_opcode_list[] = {
|
|||||||
PREDEFNODE("ifndef", po_ifndef),
|
PREDEFNODE("ifndef", po_ifndef),
|
||||||
PREDEFNODE("for", po_for),
|
PREDEFNODE("for", po_for),
|
||||||
PREDEFNODE("do", po_do),
|
PREDEFNODE("do", po_do),
|
||||||
|
// PREDEFNODE("while", po_while),
|
||||||
PREDEFNODE("macro", po_macro),
|
PREDEFNODE("macro", po_macro),
|
||||||
// PREDEFNODE("debug", po_debug),
|
// PREDEFNODE("debug", po_debug),
|
||||||
// PREDEFNODE("info", po_info),
|
// PREDEFNODE("info", po_info),
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
||||||
// Copyright (C) 1998-2016 Marco Baye
|
// Copyright (C) 1998-2017 Marco Baye
|
||||||
// Have a look at "acme.c" for further info
|
// Have a look at "acme.c" for further info
|
||||||
//
|
//
|
||||||
// section stuff (move to symbol.h?)
|
// section stuff (move to symbol.h?)
|
||||||
@ -12,9 +12,12 @@
|
|||||||
#include "tree.h"
|
#include "tree.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define SCOPE_INCREMENT 2 // inc by 2 so locals are even and cheaps are odd
|
||||||
|
|
||||||
// fake section structure (for error msgs before any real section is in use)
|
// fake section structure (for error msgs before any real section is in use)
|
||||||
static struct section initial_section = {
|
static struct section initial_section = {
|
||||||
0, // scope value
|
0, // local scope value
|
||||||
|
1, // cheap scope value
|
||||||
"during", // "type" => normally "zone Title" or
|
"during", // "type" => normally "zone Title" or
|
||||||
"init", // "title" => "macro test", now "during init"
|
"init", // "title" => "macro test", now "during init"
|
||||||
FALSE, // no, title was not malloc'd
|
FALSE, // no, title was not malloc'd
|
||||||
@ -24,21 +27,37 @@ static struct section initial_section = {
|
|||||||
// variables
|
// variables
|
||||||
struct section *section_now = &initial_section; // current section
|
struct section *section_now = &initial_section; // current section
|
||||||
static struct section outer_section; // outermost section struct
|
static struct section outer_section; // outermost section struct
|
||||||
static scope_t scope_localcount; // highest scope number yet
|
static scope_t local_scope_max; // highest scope number yet
|
||||||
|
static scope_t cheap_scope_max; // highest scope number yet
|
||||||
|
|
||||||
|
|
||||||
// write given info into given structure and activate it
|
// write given info into given structure and activate it
|
||||||
void section_new(struct section *section, const char *type, char *title, int allocated)
|
void section_new(struct section *section, const char *type, char *title, int allocated)
|
||||||
{
|
{
|
||||||
section->scope = ++scope_localcount;
|
// new scope for locals
|
||||||
|
local_scope_max += SCOPE_INCREMENT;
|
||||||
|
section->local_scope = local_scope_max;
|
||||||
|
// keep scope for cheap locals
|
||||||
|
section->cheap_scope = section_now->cheap_scope;
|
||||||
|
// copy other data
|
||||||
section->type = type;
|
section->type = type;
|
||||||
section->title = title;
|
section->title = title;
|
||||||
section->allocated = allocated;
|
section->allocated = allocated;
|
||||||
// activate new section
|
// activate new section
|
||||||
section_now = section;
|
section_now = section;
|
||||||
//printf("[new zone %d: %s, %s]\n", section->scope, section->type, section->title);
|
//printf("[new section %d: %s, %s]\n", section->local_scope, section->type, section->title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// change scope of cheap locals in given section
|
||||||
|
void section_new_cheap_scope(struct section *section)
|
||||||
|
{
|
||||||
|
// new scope for cheap locals
|
||||||
|
cheap_scope_max += SCOPE_INCREMENT;
|
||||||
|
section->cheap_scope = cheap_scope_max;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Tidy up: If necessary, release section title.
|
// Tidy up: If necessary, release section title.
|
||||||
// Warning - the state of the component "Allocd" may have
|
// Warning - the state of the component "Allocd" may have
|
||||||
// changed in the meantime, so don't rely on a local variable.
|
// changed in the meantime, so don't rely on a local variable.
|
||||||
@ -48,9 +67,13 @@ void section_finalize(struct section *section)
|
|||||||
free(section->title);
|
free(section->title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// setup outermost section
|
// setup outermost section
|
||||||
void section_passinit(void)
|
void section_passinit(void)
|
||||||
{
|
{
|
||||||
scope_localcount = SCOPE_GLOBAL; // will be incremented by next line
|
//printf("[old maxima: locals=%d, cheap=%d]\n", local_scope_max, cheap_scope_max);
|
||||||
|
local_scope_max = 0; // will be incremented by 2 by next line
|
||||||
section_new(&outer_section, s_Zone, s_untitled, FALSE);
|
section_new(&outer_section, s_Zone, s_untitled, FALSE);
|
||||||
|
cheap_scope_max = -1; // will be incremented by 2 by next line
|
||||||
|
section_new_cheap_scope(&outer_section);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
||||||
// Copyright (C) 1998-2016 Marco Baye
|
// Copyright (C) 1998-2017 Marco Baye
|
||||||
// Have a look at "acme.c" for further info
|
// Have a look at "acme.c" for further info
|
||||||
//
|
//
|
||||||
// section stuff
|
// section stuff
|
||||||
@ -12,7 +12,8 @@
|
|||||||
|
|
||||||
// "section" structure type definition
|
// "section" structure type definition
|
||||||
struct section {
|
struct section {
|
||||||
scope_t scope; // section's scope
|
scope_t local_scope; // section's scope for local symbols
|
||||||
|
scope_t cheap_scope; // section's scope for cheap locals
|
||||||
const char *type; // "Zone", "Subzone" or "Macro"
|
const char *type; // "Zone", "Subzone" or "Macro"
|
||||||
char *title; // zone title, subzone title or macro title
|
char *title; // zone title, subzone title or macro title
|
||||||
int allocated; // whether title was malloc()'d
|
int allocated; // whether title was malloc()'d
|
||||||
@ -25,6 +26,8 @@ extern struct section *section_now;
|
|||||||
|
|
||||||
// write given info into given structure and activate it
|
// write given info into given structure and activate it
|
||||||
extern void section_new(struct section *section, const char *type, char *title, int allocated);
|
extern void section_new(struct section *section, const char *type, char *title, int allocated);
|
||||||
|
// change scope of cheap locals in given section
|
||||||
|
extern void section_new_cheap_scope(struct section *section);
|
||||||
// setup outermost section
|
// setup outermost section
|
||||||
extern void section_passinit(void);
|
extern void section_passinit(void);
|
||||||
// tidy up: if necessary, release section title.
|
// tidy up: if necessary, release section title.
|
||||||
|
11
src/symbol.c
11
src/symbol.c
@ -1,5 +1,5 @@
|
|||||||
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
||||||
// Copyright (C) 1998-2016 Marco Baye
|
// Copyright (C) 1998-2017 Marco Baye
|
||||||
// Have a look at "acme.c" for further info
|
// Have a look at "acme.c" for further info
|
||||||
//
|
//
|
||||||
// symbol stuff
|
// symbol stuff
|
||||||
@ -31,7 +31,7 @@ static void dump_one_symbol(struct rwnode *node, FILE *fd)
|
|||||||
struct symbol *symbol = node->body;
|
struct symbol *symbol = node->body;
|
||||||
|
|
||||||
// output name
|
// output name
|
||||||
if (warn_on_type_mismatch
|
if (config.warn_on_type_mismatch
|
||||||
&& symbol->result.addr_refs == 1)
|
&& symbol->result.addr_refs == 1)
|
||||||
fprintf(fd, "!addr");
|
fprintf(fd, "!addr");
|
||||||
fprintf(fd, "\t%s", node->id_string);
|
fprintf(fd, "\t%s", node->id_string);
|
||||||
@ -176,13 +176,16 @@ void symbol_set_label(scope_t scope, int stat_flags, int force_bit, int change_a
|
|||||||
|
|
||||||
symbol = symbol_find(scope, force_bit);
|
symbol = symbol_find(scope, force_bit);
|
||||||
// label definition
|
// label definition
|
||||||
if ((stat_flags & SF_FOUND_BLANK) && warn_on_indented_labels)
|
if ((stat_flags & SF_FOUND_BLANK) && config.warn_on_indented_labels)
|
||||||
Throw_first_pass_warning("Label name not in leftmost column.");
|
Throw_first_pass_warning("Label name not in leftmost column.");
|
||||||
vcpu_read_pc(&pc);
|
vcpu_read_pc(&pc);
|
||||||
result.flags = pc.flags & MVALUE_DEFINED;
|
result.flags = pc.flags & MVALUE_DEFINED;
|
||||||
result.val.intval = pc.val.intval;
|
result.val.intval = pc.val.intval;
|
||||||
result.addr_refs = pc.addr_refs;
|
result.addr_refs = pc.addr_refs;
|
||||||
symbol_set_value(symbol, &result, change_allowed);
|
symbol_set_value(symbol, &result, change_allowed);
|
||||||
|
// global labels must open new scope for cheap locals
|
||||||
|
if (scope == SCOPE_GLOBAL)
|
||||||
|
section_new_cheap_scope(section_now);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -259,7 +262,7 @@ void symbol_fix_forward_anon_name(int increment)
|
|||||||
|
|
||||||
// terminate name, find "counter" symbol and read value
|
// terminate name, find "counter" symbol and read value
|
||||||
DynaBuf_append(GlobalDynaBuf, '\0');
|
DynaBuf_append(GlobalDynaBuf, '\0');
|
||||||
counter_symbol = symbol_find(section_now->scope, 0);
|
counter_symbol = symbol_find(section_now->local_scope, 0);
|
||||||
// make sure it gets reset to zero in each new pass
|
// make sure it gets reset to zero in each new pass
|
||||||
if (counter_symbol->pass != pass_count) {
|
if (counter_symbol->pass != pass_count) {
|
||||||
counter_symbol->pass = pass_count;
|
counter_symbol->pass = pass_count;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
||||||
// Copyright (C) 1998-2016 Marco Baye
|
// Copyright (C) 1998-2017 Marco Baye
|
||||||
// Have a look at "acme.c" for further info
|
// Have a look at "acme.c" for further info
|
||||||
//
|
//
|
||||||
// symbol stuff
|
// symbol stuff
|
||||||
@ -21,7 +21,6 @@ struct symbol {
|
|||||||
|
|
||||||
|
|
||||||
// Constants
|
// Constants
|
||||||
// TODO: add cheap locals (so there's SCOPE_GLOBAL, scope_zone and scope_cheap)
|
|
||||||
#define SCOPE_GLOBAL 0 // number of "global zone"
|
#define SCOPE_GLOBAL 0 // number of "global zone"
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
||||||
// Copyright (C) 1998-2016 Marco Baye
|
// Copyright (C) 1998-2017 Marco Baye
|
||||||
// Have a look at "acme.c" for further info
|
// Have a look at "acme.c" for further info
|
||||||
//
|
//
|
||||||
// type system stuff
|
// type system stuff
|
||||||
@ -35,7 +35,7 @@ void typesystem_force_address_statement(int value)
|
|||||||
|
|
||||||
void typesystem_want_imm(struct result *result)
|
void typesystem_want_imm(struct result *result)
|
||||||
{
|
{
|
||||||
if (!warn_on_type_mismatch)
|
if (!config.warn_on_type_mismatch)
|
||||||
return;
|
return;
|
||||||
if (!(result->flags & MVALUE_DEFINED))
|
if (!(result->flags & MVALUE_DEFINED))
|
||||||
return;
|
return;
|
||||||
@ -46,7 +46,7 @@ void typesystem_want_imm(struct result *result)
|
|||||||
}
|
}
|
||||||
void typesystem_want_addr(struct result *result)
|
void typesystem_want_addr(struct result *result)
|
||||||
{
|
{
|
||||||
if (!warn_on_type_mismatch)
|
if (!config.warn_on_type_mismatch)
|
||||||
return;
|
return;
|
||||||
if (!(result->flags & MVALUE_DEFINED))
|
if (!(result->flags & MVALUE_DEFINED))
|
||||||
return;
|
return;
|
||||||
|
@ -7,11 +7,11 @@
|
|||||||
#define version_H
|
#define version_H
|
||||||
|
|
||||||
|
|
||||||
#define RELEASE "0.96.2" // update before release (FIXME)
|
#define RELEASE "0.96.3" // update before release FIXME
|
||||||
#define CODENAME "Fenchurch" // update before release
|
#define CODENAME "Fenchurch" // update before release
|
||||||
#define CHANGE_DATE "21 Oct" // update before release
|
#define CHANGE_DATE "30 Oct" // update before release FIXME
|
||||||
#define CHANGE_YEAR "2017" // update before release
|
#define CHANGE_YEAR "2017" // update before release
|
||||||
//#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/" // FIXME
|
//#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/"
|
||||||
#define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME
|
#define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user