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:
marcobaye 2017-10-29 23:29:07 +00:00
parent e1683b1e28
commit 7cb100c480
25 changed files with 370 additions and 175 deletions

View File

@ -107,6 +107,23 @@ Examples: !be32 $7fffffff, symbol, -$80000000, 14, $46a4f35
!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]
Purpose: Fill amount of memory with value.
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
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]
Purpose: Fill memory until a matching address is reached. ACME
outputs FILLVALUE until "program counter AND ANDVALUE"

View File

@ -12,6 +12,25 @@ platform used. There should be another help file in this archive
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
----------------------------------------------------------------------

View File

@ -41,12 +41,14 @@ Assembling buggy JMP($xxff) instruction
Note that this warning is only given for CPU types 6502 and 6510,
because 65c02 and 65816 have been fixed in this respect.
Assembling unstable ANE #NONZERO instruction
Assembling unstable LXA #NONZERO instruction
This warning is only ever given for CPU type 6510. LXA is one of
the undocumented ("illegal") opcodes of this CPU (opcode 0xab),
and it only works reliably if its argument is zero. Therefore ACME
issues this warning if you are about to generate this instruction
with a non-zero argument.
These warnings are only ever given for CPU type 6510. ANE and LXA
are undocumented ("illegal") opcodes of this CPU, and they only
work reliably if the argument is zero or the accumulator contains
0xff.
Therefore ACME issues these warnings if it is about to generate
these instructions with a non-zero argument.
Bug in ACME, code follows
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
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.
If warnings and/or errors are output during a macro call, messages
with this text are added to display the call stack (because you

View File

@ -187,23 +187,35 @@ Available options are:
This is more or less useless, because the help is also shown
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
Output file name and format can also be given using the "!to"
pseudo opcode. If the format is not specified, "!to" defaults
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
This can also be given using the "!symbollist"/"!sl" pseudo
opcode. The switch was called "--labeldump" in older versions,
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
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
opcode. Defaults to 6502.
Use this with a bogus cpu type to get a list of all supported
ones.
--initmem NUMBER define 'empty' memory
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
If not given, defaults to 10.
--maxdepth NUMBER set recursion depth for macro calls and the
"!source" pseudo opcode. If not given, defaults to 64.
--maxdepth NUMBER set recursion depth for macro calls and !src
The default value for this is 64.
-vDIGIT set verbosity level
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
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.
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),
chosen using the "!ct" pseudo opcode.
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,
"*" gives the value of the "Pseudo PC". Just to
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
"Z", "0" to "9", the underscore character "_" and all characters with
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
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).
it can be '.' or '@', making the symbol a local one.
Local symbols beginning with '.' are only valid inside the current
zone (marked using the "!zone" pseudo opcode) or the current macro.
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:
An assembler opcode

View File

@ -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
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

View File

@ -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
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

View File

@ -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
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

View File

@ -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
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

View File

@ -1,5 +1,5 @@
// 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
// 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_MSVC "msvc"
#define OPTION_COLOR "color"
#define OPTION_FULLSTOP "fullstop"
// options for "-W"
#define OPTIONWNO_LABEL_INDENT "no-label-indent"
#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:
//" -W show warning level options\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_COLOR " enable colored error output using ANSI escape codes\n"
" --" OPTION_MSVC " output errors in MS VS format\n"
" --" OPTION_COLOR " uses ANSI color codes for error output\n"
" --" OPTION_FULLSTOP " use '.' as pseudo opcode prefix\n"
PLATFORM_OPTION_HELP
" -V, --" OPTION_VERSION " show version and exit\n");
exit(EXIT_SUCCESS);
@ -274,7 +276,7 @@ static int do_actual_work(void)
report = &global_report; // let global pointer point to something
report_init(report); // we must init struct before doing passes
if (Process_verbosity > 1)
if (config.process_verbosity > 1)
puts("First pass.");
pass_count = 0;
undefined_curr = perform_pass(); // First pass
@ -285,7 +287,7 @@ static int do_actual_work(void)
while (undefined_curr && (undefined_curr < undefined_prev)) {
++pass_count;
undefined_prev = undefined_curr;
if (Process_verbosity > 1)
if (config.process_verbosity > 1)
puts("Further 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,
// do another pass to generate listing report
if (report_filename) {
if (Process_verbosity > 1)
if (config.process_verbosity > 1)
puts("Extra pass to generate listing report.");
if (report_open(report, report_filename) == 0) {
++pass_count;
@ -306,7 +308,7 @@ static int do_actual_work(void)
}
// There are still errors (unsolvable by doing further passes),
// 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.");
// activate error output
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)
set_mem_contents();
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)
macro_recursions_left = (source_recursions_left = string_to_number(cliargs_safe_get_next("recursion depth")));
// 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)
msg_stream = stdout;
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
else if (strcmp(string, OPTION_COLOR) == 0)
format_color = TRUE;
config.format_color = TRUE;
else if (strcmp(string, OPTION_VERSION) == 0)
show_version(TRUE);
else
@ -499,9 +503,9 @@ static char short_option(const char *argument)
report_filename = cliargs_safe_get_next(arg_reportfile);
break;
case 'v': // "-v" changes verbosity
++Process_verbosity;
++config.process_verbosity;
if ((argument[1] >= '0') && (argument[1] <= '9'))
Process_verbosity = *(++argument) - '0';
config.process_verbosity = *(++argument) - '0';
break;
// platform specific switches are inserted here
PLATFORM_SHORTOPTION_CODE
@ -510,13 +514,13 @@ static char short_option(const char *argument)
break;
case 'W': // "-W" tunes warning level
if (strcmp(argument + 1, OPTIONWNO_LABEL_INDENT) == 0) {
warn_on_indented_labels = FALSE;
config.warn_on_indented_labels = FALSE;
goto done;
} else if (strcmp(argument + 1, OPTIONWNO_OLD_FOR) == 0) {
warn_on_old_for = FALSE;
config.warn_on_old_for = FALSE;
goto done;
} else if (strcmp(argument + 1, OPTIONWTYPE_MISMATCH) == 0) {
warn_on_type_mismatch = TRUE;
config.warn_on_type_mismatch = TRUE;
goto done;
} else {
fprintf(stderr, "%sUnknown warning level.\n", cliargs_error);
@ -536,6 +540,7 @@ done:
// guess what
int main(int argc, const char *argv[])
{
config_default(&config);
// if called without any arguments, show usage info (not full help)
if (argc == 1)
show_help_and_exit();

View File

@ -1,5 +1,5 @@
// 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
//
// 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
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) {
DYNABUF_CLEAR(undefsym_dyna_buf);
if (prefix) {
DynaBuf_append(undefsym_dyna_buf, LOCAL_PREFIX);
if (optional_prefix_char) {
DynaBuf_append(undefsym_dyna_buf, optional_prefix_char);
length++;
}
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.
// This function is not allowed to change DynaBuf because that's where the
// 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;
// if the symbol gets created now, mark it as unsure
symbol = symbol_find(scope, MVALUE_UNSURE);
// 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
if (pass_count == 0)
symbol->usage++;
@ -374,7 +374,7 @@ static void parse_quoted_character(char closing_quote)
// on empty string, complain
if (GotByte == closing_quote) {
Throw_error(exception_missing_string);
Input_skip_remainder();
alu_state = STATE_ERROR;
return;
}
@ -387,7 +387,7 @@ static void parse_quoted_character(char closing_quote)
if (GotByte) {
// if longer 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);
@ -593,10 +593,12 @@ static void parse_function_call(void)
// make lower case version of name in local dynamic buffer
DynaBuf_to_lower(function_dyna_buf, GlobalDynaBuf);
// 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);
else
} else {
Throw_error("Unknown function.");
alu_state = STATE_ERROR;
}
}
@ -617,7 +619,7 @@ static void expect_operand_or_monadic_operator(void)
while (GetByte() == '+');
ugly_length_kluge = GlobalDynaBuf->size; // FIXME - get rid of this!
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;
case '-': // NEGATION operator or anonymous backward label
@ -631,7 +633,7 @@ static void expect_operand_or_monadic_operator(void)
SKIPSPACE();
if (BYTEFLAGS(GotByte) & FOLLOWS_ANON) {
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;
}
@ -704,10 +706,23 @@ static void expect_operand_or_monadic_operator(void)
if (Input_read_keyword()) {
// 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;
}
// 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;
break;
// decimal values and global symbols
@ -772,7 +787,9 @@ get_byte_and_push_monadic:
break;
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;
}
}
@ -1051,7 +1068,8 @@ static void try_to_reduce_stacks(int *open_parentheses)
break;
case OPHANDLE_CLOSING:
Throw_error("Too many ')'.");
goto remove_next_to_last_operator;
alu_state = STATE_ERROR;
return;
// functions
case OPHANDLE_ADDR:
@ -1471,8 +1489,16 @@ static int parse_expression(struct result *result)
result->flags |= MVALUE_ISBYTE;
}
} else {
// State is STATE_ERROR. But actually, nobody cares.
// ...errors have already been reported anyway. :)
// State is STATE_ERROR. Errors have already been reported,
// 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 open_parentheses;

View File

@ -1,5 +1,5 @@
// 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
//
// 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)
{
// be verbose
if (Process_verbosity > 2)
if (config.process_verbosity > 2)
printf("Parsing source file '%s'\n", filename);
// set up new input
Input_new_file(filename, fd);

View File

@ -1,5 +1,5 @@
// 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
//
// Global stuff - things that are needed by several modules
@ -109,19 +109,27 @@ const char Byte_flags[256] = {
// variables
int pass_count; // number of current pass (starts 0)
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
int pass_undefined_count; // "NeedValue" type errors
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
int format_msvc = FALSE; // actually bool, enabled by --msvc
int format_color = FALSE; // actually bool, enabled by --color
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
@ -184,14 +192,14 @@ static void parse_mnemo_or_global_symbol_def(int *statement_flags)
}
// parse local symbol definition
static void parse_local_symbol_def(int *statement_flags)
// parse (cheap) local symbol definition
static void parse_local_symbol_def(int *statement_flags, scope_t scope)
{
if (!first_label_of_statement(statement_flags))
return;
GetByte(); // start after '.'
GetByte(); // start after '.'/'@'
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, '-');
while (GetByte() == '-');
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
DynaBuf_append(GlobalDynaBuf, '\0');
//printf("[%d, %s]\n", section_now->scope, GlobalDynaBuf->buffer);
symbol_set_label(section_now->scope, *statement_flags, 0, FALSE);
//printf("[%d, %s]\n", section_now->local_scope, GlobalDynaBuf->buffer);
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);
// Parse until end of statement. Only loops if statement
// 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 {
switch (GotByte) {
case CHAR_EOS: // end of statement
// Ignore now, act later
// (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:
// check for pseudo opcodes was moved out of switch,
// because prefix character is now configurable.
if (GotByte == config.pseudoop_prefix) {
pseudoopcode_parse();
break;
case '*':
parse_pc_def();
break;
case LOCAL_PREFIX:
parse_local_symbol_def(&statement_flags);
break;
default:
if (BYTEFLAGS(GotByte) & STARTS_KEYWORD) {
parse_mnemo_or_global_symbol_def(&statement_flags);
} else {
Throw_error(exception_syntax);
Input_skip_remainder();
} else {
switch (GotByte) {
case CHAR_EOS: // end of statement
// Ignore now, act later
// (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) // 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
@ -322,10 +336,11 @@ int Throw_get_counter(void)
// This function will do the actual output for warnings, errors and serious
// errors. It shows the given message string, as well as the current
// 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)
{
++throw_counter;
if (format_msvc)
if (config.format_msvc)
fprintf(msg_stream, "%s(%d) : %s (%s %s): %s\n",
Input_now->original_filename, Input_now->line_number,
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)
{
PLATFORM_WARNING(message);
if (format_color)
if (config.format_color)
throw_message(message, "\033[33mWarning\033[0m");
else
throw_message(message, "Warning");
@ -364,12 +379,12 @@ void Throw_first_pass_warning(const char *message)
void Throw_error(const char *message)
{
PLATFORM_ERROR(message);
if (format_color)
if (config.format_color)
throw_message(message, "\033[31mError\033[0m");
else
throw_message(message, "Error");
++pass_real_errors;
if (pass_real_errors >= max_errors)
if (pass_real_errors >= config.max_errors)
exit(ACME_finalize(EXIT_FAILURE));
}
@ -381,7 +396,7 @@ void Throw_error(const char *message)
void Throw_serious_error(const char *message)
{
PLATFORM_SERIOUS(message);
if (format_color)
if (config.format_color)
throw_message(message, "\033[1m\033[31mSerious error\033[0m");
else
throw_message(message, "Serious error");

View File

@ -1,5 +1,5 @@
// 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
//
// Global stuff - things that are needed by several modules
@ -14,8 +14,8 @@
#include <string.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 CHEAP_PREFIX '@' // prefix character for cheap locals
// Constants
@ -60,20 +60,24 @@ extern const char Byte_flags[];
#define FOLLOWS_ANON (1u << 3) // preceding '-' are backward label
// 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 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)
// global counters
extern int pass_undefined_count; // "NeedValue" type errors in current pass
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 int format_msvc; // actually bool, enabled by --msvc
extern int format_color; // actually bool, enabled by --color
// configuration
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
#define REPORT_ASCBUFSIZE 1024
@ -104,6 +108,8 @@ do { \
// Prototypes
// set configuration to default values
extern void config_default(struct config *conf);
// allocate memory and die if not available
extern void *safe_malloc(size_t);
// Parse block, beginning with next byte.

View File

@ -1,5 +1,5 @@
// 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
//
// Input stuff
@ -421,19 +421,20 @@ int Input_append_keyword_to_global_dynabuf(void)
return length;
}
// Check whether GotByte is LOCAL_PREFIX (default '.').
// If not, store global scope value.
// If yes, store current local scope value and read next byte.
// Check GotByte.
// If LOCAL_PREFIX ('.'), 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.
int Input_read_scope_and_keyword(scope_t *scope)
{
SKIPSPACE();
if (GotByte == LOCAL_PREFIX) {
GetByte();
*scope = section_now->scope;
/* TODO } else if (GotByte == CHEAP_PREFIX) {
*scope = section_now->local_scope;
} else if (GotByte == CHEAP_PREFIX) {
GetByte();
*scope = symbol_cheap_scope; */
*scope = section_now->cheap_scope;
} else {
*scope = SCOPE_GLOBAL;
}

View File

@ -1,5 +1,5 @@
// 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
//
// Input stuff
@ -83,9 +83,10 @@ extern void Input_until_terminator(char terminator);
// Append to GlobalDynaBuf while characters are legal for keywords.
// Throws "missing string" error if none. Returns number of characters added.
extern int Input_append_keyword_to_global_dynabuf(void);
// Check whether GotByte is a dot.
// If not, store global scope value.
// If yes, store current scope value and read next byte.
// Check GotByte.
// If LOCAL_PREFIX ('.'), 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.
extern int Input_read_scope_and_keyword(scope_t *scope);
// Clear dynamic buffer, then append to it until an illegal (for a keyword)

View File

@ -1,5 +1,5 @@
// 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
//
// Macro stuff
@ -88,8 +88,10 @@ static scope_t get_scope_and_title(void)
// copy macro title to private dynabuf and add separator character
DYNABUF_CLEAR(user_macro_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_add_string(user_macro_name, GLOBALDYNABUF_CURRENT);
DynaBuf_add_string(internal_name, GLOBALDYNABUF_CURRENT);
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:
// .LOCAL_LABEL_BY_VALUE
// ~.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_REFERENCE but not forbidden
// now GotByte = non-space
@ -187,9 +191,10 @@ void Macro_parse_definition(void) // Now GotByte = illegal char after "!macro"
DynaBuf_append(GlobalDynaBuf, REFERENCE_CHAR);
GetByte();
}
// handle prefix for local symbols (LOCAL_PREFIX, normally '.')
if (GotByte == LOCAL_PREFIX) {
DynaBuf_append(GlobalDynaBuf, LOCAL_PREFIX);
// handle prefix for (cheap) local symbols ('.'/'@')
if ((GotByte == LOCAL_PREFIX)
|| (GotByte == CHEAP_PREFIX)) {
DynaBuf_append(GlobalDynaBuf, GotByte);
GetByte();
}
// 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)
// FALSE = title mustn't be freed
section_new(&new_section, "Macro", actual_macro->original_name, FALSE);
section_new_cheap_scope(&new_section);
GetByte(); // fetch first byte of parameter list
// assign arguments
if (GotByte != CHAR_EOS) { // any at all?

View File

@ -827,6 +827,15 @@ static unsigned int imm_ops(int *force_bit, unsigned char opcode, int immediate_
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)
// plus PEI.
static void group_main(int index, int immediate_mode)
@ -859,18 +868,23 @@ static void group_main(int index, int immediate_mode)
break;
case INDIRECT_ADDRESSING: // ($ff)
make_command(force_bit, &result, accu_ind8[index]);
check_zp_wraparound(&result, 0);
break;
case INDIRECT_Y_INDEXED_ADDRESSING: // ($ff),y
make_command(force_bit, &result, accu_indy8[index]);
check_zp_wraparound(&result, 0);
break;
case INDIRECT_Z_INDEXED_ADDRESSING: // ($ff),z
make_command(force_bit, &result, accu_indz8[index]);
check_zp_wraparound(&result, 0);
break;
case LONG_INDIRECT_ADDRESSING: // [$ff]
make_command(force_bit, &result, accu_lind8[index]);
check_zp_wraparound(&result, 1);
break;
case LONG_INDIRECT_Y_INDEXED_ADDRESSING: // [$ff],y
make_command(force_bit, &result, accu_lindy8[index]);
check_zp_wraparound(&result, 1);
break;
case STACK_INDEXED_INDIRECT_Y_INDEXED_ADDRESSING: // ($ff,s),y
make_command(force_bit, &result, accu_sindy8[index]);

View File

@ -1,5 +1,5 @@
// 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
//
// Output stuff
@ -380,7 +380,7 @@ void Output_save_file(FILE *fd)
start = out->lowest_written;
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",
amount, amount, start, start + amount);
// output file header according to file format
@ -514,7 +514,7 @@ void Output_end_segment(void)
// link to segment list
link_segment(out->segment.start, amount);
// announce
if (Process_verbosity > 1)
if (config.process_verbosity > 1)
printf("Segment size is %ld (0x%lx) bytes (0x%lx - 0x%lx exclusive).\n",
amount, amount, out->segment.start, out->write_idx);
}

View File

@ -1,5 +1,5 @@
// 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
//
// 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)
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)
@ -433,7 +431,7 @@ static enum eos po_binary(void)
}
fclose(fd);
// 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();
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" pseudo opcode)
// skip over some bytes in output without starting 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)
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);
return ENSURE_EOS;
}
#endif
// 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;
if (Input_accept_comma()) {
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.");
loop.counter.first = intresult.val.intval; // use first argument
ALU_defined_int(&intresult); // read second argument
loop.counter.last = intresult.val.intval; // use second argument
// 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)) {
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;
} else {
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.");
if (intresult.val.intval < 0)
Throw_serious_error("Loop count is negative.");
@ -1019,12 +1015,19 @@ static enum eos throw_string(const char prefix[], void (*fn)(const char *))
}
////
//static enum eos po_debug(void)
//static enum eos po_info(void)
//{
// return throw_string();
//}
#if 0
// show debug data given in source code
static enum eos po_debug(void)
{
// 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
@ -1077,6 +1080,8 @@ static struct ronode pseudo_opcode_list[] = {
PREDEFNODE("32", po_32),
PREDEFNODE("be32", po_be32),
PREDEFNODE("le32", po_le32),
PREDEFNODE("h", po_hex),
PREDEFNODE("hex", po_hex),
PREDEFNODE(s_cbm, obsolete_po_cbm),
PREDEFNODE("ct", po_convtab),
PREDEFNODE("convtab", po_convtab),
@ -1090,6 +1095,7 @@ static struct ronode pseudo_opcode_list[] = {
PREDEFNODE("binary", po_binary),
PREDEFNODE("fi", po_fill),
PREDEFNODE("fill", po_fill),
PREDEFNODE("skip", po_skip),
PREDEFNODE("align", po_align),
PREDEFNODE("pseudopc", po_pseudopc),
PREDEFNODE("realpc", obsolete_po_realpc),
@ -1100,6 +1106,7 @@ static struct ronode pseudo_opcode_list[] = {
PREDEFNODE("rs", po_rs),
PREDEFNODE("addr", po_address),
PREDEFNODE("address", po_address),
// PREDEFNODE("enum", po_enum),
PREDEFNODE("set", po_set),
PREDEFNODE(s_sl, po_symbollist),
PREDEFNODE("symbollist", po_symbollist),
@ -1114,6 +1121,7 @@ static struct ronode pseudo_opcode_list[] = {
PREDEFNODE("ifndef", po_ifndef),
PREDEFNODE("for", po_for),
PREDEFNODE("do", po_do),
// PREDEFNODE("while", po_while),
PREDEFNODE("macro", po_macro),
// PREDEFNODE("debug", po_debug),
// PREDEFNODE("info", po_info),

View File

@ -1,5 +1,5 @@
// 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
//
// section stuff (move to symbol.h?)
@ -12,9 +12,12 @@
#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)
static struct section initial_section = {
0, // scope value
0, // local scope value
1, // cheap scope value
"during", // "type" => normally "zone Title" or
"init", // "title" => "macro test", now "during init"
FALSE, // no, title was not malloc'd
@ -24,21 +27,37 @@ static struct section initial_section = {
// variables
struct section *section_now = &initial_section; // current section
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
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->title = title;
section->allocated = allocated;
// activate new 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.
// Warning - the state of the component "Allocd" may have
// 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);
}
// setup outermost section
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);
cheap_scope_max = -1; // will be incremented by 2 by next line
section_new_cheap_scope(&outer_section);
}

View File

@ -1,5 +1,5 @@
// 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
//
// section stuff
@ -12,7 +12,8 @@
// "section" structure type definition
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"
char *title; // zone title, subzone title or macro title
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
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
extern void section_passinit(void);
// tidy up: if necessary, release section title.

View File

@ -1,5 +1,5 @@
// 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
//
// symbol stuff
@ -31,7 +31,7 @@ static void dump_one_symbol(struct rwnode *node, FILE *fd)
struct symbol *symbol = node->body;
// output name
if (warn_on_type_mismatch
if (config.warn_on_type_mismatch
&& symbol->result.addr_refs == 1)
fprintf(fd, "!addr");
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);
// 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.");
vcpu_read_pc(&pc);
result.flags = pc.flags & MVALUE_DEFINED;
result.val.intval = pc.val.intval;
result.addr_refs = pc.addr_refs;
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
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
if (counter_symbol->pass != pass_count) {
counter_symbol->pass = pass_count;

View File

@ -1,5 +1,5 @@
// 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
//
// symbol stuff
@ -21,7 +21,6 @@ struct symbol {
// Constants
// TODO: add cheap locals (so there's SCOPE_GLOBAL, scope_zone and scope_cheap)
#define SCOPE_GLOBAL 0 // number of "global zone"

View File

@ -1,5 +1,5 @@
// 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
//
// type system stuff
@ -35,7 +35,7 @@ void typesystem_force_address_statement(int value)
void typesystem_want_imm(struct result *result)
{
if (!warn_on_type_mismatch)
if (!config.warn_on_type_mismatch)
return;
if (!(result->flags & MVALUE_DEFINED))
return;
@ -46,7 +46,7 @@ void typesystem_want_imm(struct result *result)
}
void typesystem_want_addr(struct result *result)
{
if (!warn_on_type_mismatch)
if (!config.warn_on_type_mismatch)
return;
if (!(result->flags & MVALUE_DEFINED))
return;

View File

@ -7,11 +7,11 @@
#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 CHANGE_DATE "21 Oct" // update before release
#define CHANGE_DATE "30 Oct" // update before release FIXME
#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