Release 0.95.6 (intermediate release): Removed ANC from DTV2 mode, "Value not defined"

message now includes symbol name, fixed bug in type system (!for loop counters), added
address() as alternative to addr(), fixed bug in report listing generator (CR in input
caused additional blank lines in output).


git-svn-id: https://svn.code.sf.net/p/acme-crossass/code-0/trunk@63 4df02467-bbd4-4a76-a152-e7ce94205b78
This commit is contained in:
marcobaye 2015-06-14 23:16:23 +00:00
parent 9c3d91adfa
commit 8d2719db8a
17 changed files with 278 additions and 157 deletions

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.95.6
----------------------------------------------------------------------
Fixed a bug: The "C64 DTV2" does not support the undocumented
("illegal") opcodes 0x0b and 0x2b, therefore the "ANC #8"
mnemonic was removed from the "!cpu c64dtv2" mode. Thanks to
peiselulli for testing and reporting this.
"Value not defined" error message now includes the name of the
undefined symbol. Thanks to Thomas Woinke for suggesting this
improvement.
Fixed a bug in type system: "!for" loop counters were not correctly
flagged as "address" or "non-address".
The "addr()" function can now also be written as "address()".
Fixed a bug in report listing generator: CR characters in input caused
additional blank lines in output. Thanks to Johann Klasek for
submitting this patch.
----------------------------------------------------------------------
Section: New in release 0.95.5
----------------------------------------------------------------------

View File

@ -142,9 +142,12 @@ Using oversized addressing mode.
Wrong type - expected address.
Wrong type - expected integer.
Wrong type for loop's END value - must match type of START value.
These warnings are only given when type checking has been enabled
using the "-Wtype-mismatch" switch. Make sure the argument type
matches the instruction's addressing mode.
In "!for" loops, START and END must have the same type, which then
gets used for the loop counter.
----------------------------------------------------------------------
@ -297,7 +300,7 @@ Unknown pseudo opcode.
Unknown "* =" segment modifier.
You used a modifier keyword ACME does not know.
Value not yet defined.
Value not defined (SYMBOL NAME).
A value could not be worked out. Maybe you mistyped a symbol name.
Whether this is given as a "normal" or as a serious error depends
on the currently parsed pseudo opcode.

View File

@ -14,6 +14,7 @@ In release 0.94.8, another one was added (lxa).
In release 0.95.3, C64DTV2 support was added, which includes these
opcodes as well.
In release 0.95.4, the remaining seven were added.
In release 0.95.6, "ANC" was removed from C64DTV2 mode.
Here are the new mnemonics, possible addressing modes and generated
opcodes (mnemonics in parentheses are used by other sources):
@ -57,7 +58,7 @@ Example:
*) Up until ACME version 0.95.1, anc#8 generated opcode 0x2b. Since
ACME version 0.95.2, anc#8 generates opcode 0x0b. Both opcodes work
the same way on a 6510. I am told 0x2b does not work on the C64DTV2.
the same way on a real 6510 CPU, but they do not work on the C64DTV2.
**) Note that DOP ("double nop") and TOP ("triple nop") can be used
with implied addressing, but the generated opcodes are those for

View File

@ -284,7 +284,7 @@ This is a list of the operators currently known by ACME:
14 arcsin(v) Inverse of sin()
14 arccos(v) Inverse of cos()
14 arctan(v) Inverse of tan()
14 addr(v) Mark as address
14 address(v) Mark as address addr(v)
14 int(v) Convert to integer
14 float(v) Convert to float
13 ! v Complement of NOT

View File

@ -1,5 +1,5 @@
// ACME - a crossassembler for producing 6502/65c02/65816 code.
// Copyright (C) 1998-2014 Marco Baye
// Copyright (C) 1998-2015 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
@ -15,9 +15,9 @@
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#define RELEASE "0.95.5" // update before release (FIXME)
#define RELEASE "0.95.6" // update before release (FIXME)
#define CODENAME "Fenchurch" // update before release
#define CHANGE_DATE "5 Feb" // update before release
#define CHANGE_DATE "15 Jun" // update before release
#define CHANGE_YEAR "2015" // update before release
//#define HOME_PAGE "http://home.pages.de/~mac_bacon/smorbrod/acme/" // FIXME
#define HOME_PAGE "http://sourceforge.net/p/acme-crossass/" // FIXME
@ -312,7 +312,9 @@ static int do_actual_work(void)
// so perform additional pass to find and show them.
if (Process_verbosity > 1)
puts("Extra pass needed to find error.");
ALU_throw_errors(); // activate error output (CAUTION - one-way!)
// activate error output
ALU_optional_notdef_handler = Throw_error;
++pass_count;
perform_pass(); // perform pass, but now show "value undefined"
return 0;

191
src/alu.c
View File

@ -1,5 +1,5 @@
// ACME - a crossassembler for producing 6502/65c02/65816 code.
// Copyright (C) 1998-2014 Marco Baye
// Copyright (C) 1998-2015 Marco Baye
// Have a look at "acme.c" for further info
//
// Arithmetic/logic unit
@ -11,6 +11,7 @@
// 7 May 2014 C-style "==" operators are now recognized (but
// give a warning).
// 31 May 2014 Added "0b" binary number prefix as alternative to "%".
// 28 Apr 2015 Added symbol name output to "value not defined" error.
#include "alu.h"
#include <stdlib.h>
#include <math.h> // only for fp support
@ -27,12 +28,13 @@
// constants
#define ERRORMSG_DYNABUF_INITIALSIZE 256 // ad hoc
#define FUNCTION_DYNABUF_INITIALSIZE 8 // enough for "arctan"
#define UNDEFSYM_DYNABUF_INITIALSIZE 256 // ad hoc
#define HALF_INITIAL_STACK_SIZE 8
static const char exception_div_by_zero[] = "Division by zero.";
static const char exception_no_value[] = "No value given.";
static const char exception_paren_open[] = "Too many '('.";
static const char exception_undefined[] = "Value not defined.";
#define s_or (s_eor + 1) // Yes, I know I'm sick
#define s_xor (s_scrxor + 3) // Yes, I know I'm sick
static const char s_arcsin[] = "arcsin";
@ -146,7 +148,9 @@ static struct operator ops_arctan = {OPHANDLE_ARCTAN, 32}; // function
// variables
static struct dynabuf *errormsg_dyna_buf; // dynamic buffer for "value not defined" error
static struct dynabuf *function_dyna_buf; // dynamic buffer for fn names
static struct dynabuf *undefsym_dyna_buf; // dynamic buffer for name of undefined symbol
static struct operator **operator_stack = NULL;
static int operator_stk_size = HALF_INITIAL_STACK_SIZE;
static int operator_sp; // operator stack pointer
@ -183,6 +187,7 @@ static struct ronode operator_list[] = {
static struct ronode *function_tree = NULL; // tree to hold functions
static struct ronode function_list[] = {
PREDEFNODE("addr", &ops_addr),
PREDEFNODE("address", &ops_addr),
PREDEFNODE("int", &ops_int),
PREDEFNODE("float", &ops_float),
PREDEFNODE(s_arcsin, &ops_arcsin),
@ -219,32 +224,28 @@ do { \
} while (0)
// handle "NeedValue" type errors: problems that may be solved by performing
// further passes. This function only counts, it will not show the errors to
// the user.
static void just_count(void)
// generate "Value not defined" error message with added symbol name
static char *value_not_defined(void)
{
++pass_undefined_count;
DYNABUF_CLEAR(errormsg_dyna_buf);
DynaBuf_add_string(errormsg_dyna_buf, "Value not defined (");
DynaBuf_add_string(errormsg_dyna_buf, undefsym_dyna_buf->buffer);
DynaBuf_add_string(errormsg_dyna_buf, ").");
DynaBuf_append(errormsg_dyna_buf, '\0');
return errormsg_dyna_buf->buffer;
}
// handle "NeedValue" type errors: problems that may be solved by performing
// further passes. This function counts these errors and shows them to the user.
static void count_and_throw(void)
// function pointer for "value undefined" error output. set to NULL to suppress those errors.
void (*ALU_optional_notdef_handler)(const char *) = NULL;
// function to handle "result is undefined" type errors.
// maybe split this into "_result_ is undefined" (in that case, count) and "symbol is undefined" (in that case, call handler)
static void result_is_undefined(void)
{
++pass_undefined_count;
Throw_error(exception_undefined);
}
// function pointer for "result is undefined" type errors.
static void (*result_is_undefined)(void) = just_count;
// activate error output for "value undefined"
void ALU_throw_errors(void)
{
result_is_undefined = count_and_throw;
if (ALU_optional_notdef_handler)
ALU_optional_notdef_handler(value_not_defined());
}
@ -271,7 +272,9 @@ static void enlarge_operand_stack(void)
// create dynamic buffer, operator/function trees and operator/operand stacks
void ALU_init(void)
{
errormsg_dyna_buf = DynaBuf_create(ERRORMSG_DYNABUF_INITIALSIZE);
function_dyna_buf = DynaBuf_create(FUNCTION_DYNABUF_INITIALSIZE);
undefsym_dyna_buf = DynaBuf_create(UNDEFSYM_DYNABUF_INITIALSIZE);
Tree_add_table(&operator_tree, operator_list);
Tree_add_table(&function_tree, function_list);
enlarge_operator_stack();
@ -316,17 +319,39 @@ static intval_t my_asr(intval_t left, intval_t right)
return ~((~left) >> right);
}
// if undefined, remember name for error output
static void check_for_def(int flags, int prefix, char *name, size_t length)
{
if ((flags & MVALUE_DEFINED) == 0) {
DYNABUF_CLEAR(undefsym_dyna_buf);
if (prefix) {
DynaBuf_append(undefsym_dyna_buf, LOCAL_PREFIX);
length++;
}
DynaBuf_add_string(undefsym_dyna_buf, name);
if (length > undefsym_dyna_buf->size) {
Bug_found("Illegal symbol name length", undefsym_dyna_buf->size - length);
} else {
undefsym_dyna_buf->size = length;
}
DynaBuf_append(undefsym_dyna_buf, '\0');
}
}
// Lookup (and create, if necessary) symbol tree item and return its value.
// DynaBuf holds the symbol's name and "zone" its zone.
// The name length must be given explicitly because of anonymous forward labels;
// 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(zone_t zone)
static void get_symbol_value(zone_t zone, int prefix, size_t name_length)
{
struct symbol *symbol;
// if the symbol gets created now, mark it as unsure
symbol = symbol_find(zone, MVALUE_UNSURE);
// if needed, remember name for "undefined" error output
check_for_def(symbol->result.flags, prefix, GLOBALDYNABUF_CURRENT, name_length);
// in first pass, count usage
if (pass_count == 0)
symbol->usage++;
@ -550,6 +575,8 @@ static void parse_program_counter(void) // Now GotByte = "*"
GetByte();
vcpu_read_pc(&pc);
// if needed, remember name for "undefined" error output
check_for_def(pc.flags, 0, "*", 1);
PUSH_INTOPERAND(pc.val.intval, pc.flags | MVALUE_EXISTS, pc.addr_refs);
}
@ -573,6 +600,7 @@ static void parse_function_call(void)
static void expect_operand_or_monadic_operator(void)
{
struct operator *operator;
int ugly_length_kluge;
int perform_negation;
SKIPSPACE();
@ -583,8 +611,9 @@ static void expect_operand_or_monadic_operator(void)
do
DYNABUF_APPEND(GlobalDynaBuf, '+');
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->zone);
get_symbol_value(Section_now->zone, 0, ugly_length_kluge);
goto now_expect_dyadic;
case '-': // NEGATION operator or anonymous backward label
@ -598,7 +627,7 @@ static void expect_operand_or_monadic_operator(void)
SKIPSPACE();
if (BYTEFLAGS(GotByte) & FOLLOWS_ANON) {
DynaBuf_append(GlobalDynaBuf, '\0');
get_symbol_value(Section_now->zone);
get_symbol_value(Section_now->zone, 0, GlobalDynaBuf->size - 1); // -1 to not count terminator
goto now_expect_dyadic;
}
@ -671,7 +700,7 @@ static void expect_operand_or_monadic_operator(void)
if (Input_read_keyword()) {
// Now GotByte = illegal char
get_symbol_value(Section_now->zone);
get_symbol_value(Section_now->zone, 1, GlobalDynaBuf->size - 1); // -1 to not count terminator
goto now_expect_dyadic;
}
@ -709,7 +738,7 @@ static void expect_operand_or_monadic_operator(void)
// however, apart from that check above, function calls have nothing to do with
// parentheses: "sin(x+y)" gets parsed just like "not(x+y)".
} else {
get_symbol_value(ZONE_GLOBAL);
get_symbol_value(ZONE_GLOBAL, 0, GlobalDynaBuf->size - 1); // -1 to not count terminator
goto now_expect_dyadic;
}
@ -1439,56 +1468,23 @@ static int parse_expression(struct result *result)
}
// return int value (if result is undefined, returns zero)
// If the result's "exists" flag is clear (=empty expression), it throws an
// error.
// If the result's "defined" flag is clear, result_is_undefined() is called.
intval_t ALU_any_int(void)
{
struct result result;
if (parse_expression(&result))
Throw_error(exception_paren_open);
if ((result.flags & MVALUE_EXISTS) == 0)
Throw_error(exception_no_value);
else if ((result.flags & MVALUE_DEFINED) == 0)
result_is_undefined();
if (result.flags & MVALUE_IS_FP)
return result.val.fpval;
else
return result.val.intval;
}
// return int value (if result is undefined, serious error is thrown)
intval_t ALU_defined_int(void)
{
struct result result;
if (parse_expression(&result))
Throw_error(exception_paren_open);
if ((result.flags & MVALUE_DEFINED) == 0)
Throw_serious_error(exception_undefined);
if (result.flags & MVALUE_IS_FP)
return result.val.fpval;
else
return result.val.intval;
}
// Store int value if given. Returns whether stored. Throws error if undefined.
// This function needs either a defined value or no expression at all. So
// empty expressions are accepted, but undefined ones are not.
// If the result's "defined" flag is clear and the "exists" flag is set, it
// throws a serious error and therefore stops assembly.
int ALU_optional_defined_int(intval_t *target)
// OPEN_PARENTHESIS: complain
// EMPTY: allow
// UNDEFINED: complain _seriously_
// FLOAT: convert to int
int ALU_optional_defined_int(intval_t *target) // ACCEPT_EMPTY
{
struct result result;
if (parse_expression(&result))
Throw_error(exception_paren_open);
if ((result.flags & MVALUE_GIVEN) == MVALUE_EXISTS)
Throw_serious_error(exception_undefined);
Throw_serious_error(value_not_defined());
if ((result.flags & MVALUE_EXISTS) == 0)
return 0;
// something was given, so store
@ -1504,7 +1500,11 @@ int ALU_optional_defined_int(intval_t *target)
// It the result's "exists" flag is clear (=empty expression), it throws an
// error.
// If the result's "defined" flag is clear, result_is_undefined() is called.
void ALU_int_result(struct result *intresult)
// OPEN_PARENTHESIS: complain
// EMPTY: complain
// UNDEFINED: allow
// FLOAT: convert to int
void ALU_int_result(struct result *intresult) // ACCEPT_UNDEFINED
{
if (parse_expression(intresult))
Throw_error(exception_paren_open);
@ -1520,11 +1520,60 @@ void ALU_int_result(struct result *intresult)
}
// return int value (if result is undefined, returns zero)
// If the result's "exists" flag is clear (=empty expression), it throws an
// error.
// If the result's "defined" flag is clear, result_is_undefined() is called.
// OPEN_PARENTHESIS: complain
// EMPTY: complain
// UNDEFINED: allow
// FLOAT: convert to int
intval_t ALU_any_int(void) // ACCEPT_UNDEFINED
{
// FIXME - replace this fn with a call to ALU_int_result() above!
struct result result;
if (parse_expression(&result))
Throw_error(exception_paren_open);
if ((result.flags & MVALUE_EXISTS) == 0)
Throw_error(exception_no_value);
else if ((result.flags & MVALUE_DEFINED) == 0)
result_is_undefined();
if (result.flags & MVALUE_IS_FP)
return result.val.fpval;
else
return result.val.intval;
}
// stores int value and flags (floats are transformed to int)
// if result was undefined, serious error is thrown
// OPEN_PARENTHESIS: complain
// EMPTY: treat as UNDEFINED <= this is a problem - maybe use a wrapper fn for this use case?
// UNDEFINED: complain _seriously_
// FLOAT: convert to int
extern void ALU_defined_int(struct result *intresult) // no ACCEPT constants?
{
if (parse_expression(intresult))
Throw_error(exception_paren_open);
if ((intresult->flags & MVALUE_DEFINED) == 0)
Throw_serious_error(value_not_defined());
if (intresult->flags & MVALUE_IS_FP) {
intresult->val.intval = intresult->val.fpval;
intresult->flags &= ~MVALUE_IS_FP;
}
}
// Store int value and flags.
// This function allows for one '(' too many. Needed when parsing indirect
// addressing modes where internal indices have to be possible. Returns number
// of parentheses still open (either 0 or 1).
int ALU_liberal_int(struct result *intresult)
// OPEN_PARENTHESIS: allow
// UNDEFINED: allow
// EMPTY: allow
// FLOAT: convert to int
int ALU_liberal_int(struct result *intresult) // ACCEPT_EMPTY | ACCEPT_UNDEFINED | ACCEPT_OPENPARENTHESIS
{
int parentheses_still_open;
@ -1549,7 +1598,11 @@ int ALU_liberal_int(struct result *intresult)
// It the result's "exists" flag is clear (=empty expression), it throws an
// error.
// If the result's "defined" flag is clear, result_is_undefined() is called.
void ALU_any_result(struct result *result)
// OPEN_PARENTHESIS: complain
// EMPTY: complain
// UNDEFINED: allow
// FLOAT: keep
void ALU_any_result(struct result *result) // ACCEPT_UNDEFINED | ACCEPT_FLOAT
{
if (parse_expression(result))
Throw_error(exception_paren_open);

View File

@ -31,16 +31,31 @@
// create dynamic buffer, operator/function trees and operator/operand stacks
extern void ALU_init(void);
// activate error output for "value undefined"
extern void ALU_throw_errors(void);
// returns int value (0 if result was undefined)
extern intval_t ALU_any_int(void);
// returns int value (if result was undefined, serious error is thrown)
extern intval_t ALU_defined_int(void);
// function pointer for "value undefined" error output.
// set to NULL to suppress those errors,
// set to Throw_error to show them.
extern void (*ALU_optional_notdef_handler)(const char *);
// FIXME - replace all the functions below with a single one using a "flags" arg!
#define ACCEPT_EMPTY (1u << 0) // if not given, throws error
#define ACCEPT_UNDEFINED (1u << 1) // if not given, undefined throws serious error
//#define ACCEPT_INT (1u << ) needed when strings come along!
#define ACCEPT_FLOAT (1u << 2) // if not given, floats are converted to integer
#define ACCEPT_OPENPARENTHESIS (1u << 3) // if not given, throws syntax error
//#define ACCEPT_STRING
// do I need ACCEPT_INT and/or ACCEPT_ADDRESS?
// stores int value if given. Returns whether stored. Throws error if undefined.
extern int ALU_optional_defined_int(intval_t *target);
// returns int value (0 if result was undefined)
extern intval_t ALU_any_int(void);
// stores int value and flags (floats are transformed to int)
extern void ALU_int_result(struct result *intresult);
// stores int value and flags (floats are transformed to int)
// if result was undefined, serious error is thrown
extern void ALU_defined_int(struct result *intresult);
// stores int value and flags, allowing for one '(' too many (x-indirect addr).
// returns number of additional '(' (1 or 0).
extern int ALU_liberal_int(struct result *intresult);

View File

@ -12,6 +12,7 @@ typedef unsigned int zone_t;
typedef signed long intval_t; // at least 32 bits
typedef unsigned long uintval_t; // just for logical shift right
// result structure type definition with support for floating point
// future result types: EMPTY, UNDEFINED, INT, FLOAT (, STRING)
struct result { // either int or float
int flags; // expression flags
union {

View File

@ -18,41 +18,39 @@
static struct cpu_type cpu_type_6502 = {
keyword_is_6502mnemo,
CPUFLAG_INDIRECTJMPBUGGY, // JMP ($xxFF) is buggy
234 // !align fills with "NOP"
234 // !align fills with "NOP"
};
static struct cpu_type cpu_type_6510 = {
keyword_is_6510mnemo,
CPUFLAG_INDIRECTJMPBUGGY | // JMP ($xxFF) is buggy
CPUFLAG_8B_AND_AB_NEED_0_ARG, // ANE/LXA #$xx are unstable unless arg is $00
234 // !align fills with "NOP"
CPUFLAG_INDIRECTJMPBUGGY | CPUFLAG_8B_AND_AB_NEED_0_ARG, // JMP ($xxFF) is buggy, ANE/LXA #$xx are unstable unless arg is $00
234 // !align fills with "NOP"
};
static struct cpu_type cpu_type_c64dtv2 = {
keyword_is_c64dtv2mnemo,
CPUFLAG_INDIRECTJMPBUGGY | // JMP ($xxFF) is buggy
CPUFLAG_8B_AND_AB_NEED_0_ARG, // ANE/LXA #$xx are unstable unless arg is $00 (FIXME - correct?)
234 // !align fills with "NOP"
CPUFLAG_INDIRECTJMPBUGGY | CPUFLAG_8B_AND_AB_NEED_0_ARG, // JMP ($xxFF) is buggy, ANE/LXA #$xx are unstable unless arg is $00
234 // !align fills with "NOP"
};
static struct cpu_type cpu_type_65c02 = {
keyword_is_65c02mnemo,
0, // no flags
234 // !align fills with "NOP"
0, // no flags
234 // !align fills with "NOP"
};
/*
static struct cpu_type cpu_type_Rockwell65c02 = {
keyword_is_Rockwell65c02mnemo,
0, // no flags
234 // !align fills with "NOP"
0, // no flags
234 // !align fills with "NOP"
};
static struct cpu_type cpu_type_WDC65c02 = {
keyword_is_WDC65c02mnemo,
0, // no flags
234 // !align fills with "NOP"
0, // no flags
234 // !align fills with "NOP"
};
*/
static struct cpu_type cpu_type_65816 = {
keyword_is_65816mnemo,
CPUFLAG_SUPPORTSLONGREGS, // allows A and XY to be 16bits wide
234 // !align fills with "NOP"
234 // !align fills with "NOP"
};

View File

@ -56,25 +56,26 @@ void flow_forloop(struct for_loop *loop)
Input_now = &loop_input;
// init counter
loop_counter.flags = MVALUE_DEFINED | MVALUE_EXISTS;
loop_counter.val.intval = loop->counter_first;
loop_counter.val.intval = loop->counter.first;
loop_counter.addr_refs = loop->counter.addr_refs;
symbol_set_value(loop->symbol, &loop_counter, TRUE);
if (loop->old_algo) {
// old algo for old syntax:
// if count == 0, skip loop
if (loop->counter_last) {
if (loop->counter.last) {
do {
loop_counter.val.intval += loop->counter_increment;
loop_counter.val.intval += loop->counter.increment;
symbol_set_value(loop->symbol, &loop_counter, TRUE);
parse_ram_block(&loop->block);
} while (loop_counter.val.intval < loop->counter_last);
} while (loop_counter.val.intval < loop->counter.last);
}
} else {
// new algo for new syntax:
do {
parse_ram_block(&loop->block);
loop_counter.val.intval += loop->counter_increment;
loop_counter.val.intval += loop->counter.increment;
symbol_set_value(loop->symbol, &loop_counter, TRUE);
} while (loop_counter.val.intval != (loop->counter_last + loop->counter_increment));
} while (loop_counter.val.intval != (loop->counter.last + loop->counter.increment));
}
// restore previous input:
Input_now = outer_input;
@ -119,7 +120,7 @@ void flow_store_doloop_condition(struct loop_condition *condition, char terminat
// check a condition expression
static int check_condition(struct loop_condition *condition)
{
intval_t expression;
struct result intresult;
// first, check whether there actually *is* a condition
if (condition->body == NULL)
@ -129,10 +130,10 @@ static int check_condition(struct loop_condition *condition)
Input_now->line_number = condition->line;
Input_now->src.ram_ptr = condition->body;
GetByte(); // proceed with next char
expression = ALU_defined_int();
ALU_defined_int(&intresult);
if (GotByte)
Throw_serious_error(exception_syntax);
return condition->is_until ? !expression : !!expression;
return condition->is_until ? !intresult.val.intval : !!intresult.val.intval;
}

View File

@ -1,5 +1,5 @@
// ACME - a crossassembler for producing 6502/65c02/65816 code.
// Copyright (C) 1998-2009 Marco Baye
// Copyright (C) 1998-2015 Marco Baye
// Have a look at "acme.c" for further info
//
// flow control stuff (loops, conditional assembly etc.)
@ -20,9 +20,12 @@ struct block {
struct for_loop {
struct symbol *symbol;
int old_algo; // actually bool
intval_t counter_first,
counter_last,
counter_increment;
struct {
intval_t first,
last,
increment;
int addr_refs; // address reference count
} counter;
struct block block;
};

View File

@ -70,9 +70,7 @@ static void report_srcchar(char new_char)
report->asc_used = 0; // clear buffer
prev_char = '\0';
}
if ((prev_char == '\n' || prev_char == '\r')) {
// this check makes empty lines screw up line numbers:
// && new_char != '\n') {
if (prev_char == '\n') {
// line start after line break detected and EOS processed,
// build report line:
// show line number...

View File

@ -1,5 +1,5 @@
// ACME - a crossassembler for producing 6502/65c02/65816 code.
// Copyright (C) 1998-2014 Marco Baye
// Copyright (C) 1998-2015 Marco Baye
// Have a look at "acme.c" for further info
//
// Mnemonics stuff
@ -146,8 +146,9 @@ static const char exception_highbyte_zero[] = "Using oversized addressing mode."
static struct dynabuf *mnemo_dyna_buf; // dynamic buffer for mnemonics
// predefined stuff
static struct ronode *mnemo_6502_tree = NULL; // holds 6502 mnemonics
static struct ronode *mnemo_6510_tree = NULL; // holds 6510 extensions
static struct ronode *mnemo_c64dtv2_tree = NULL; // holds C64DTV2 extensions
static struct ronode *mnemo_6502undoc1_tree = NULL; // holds 6502 undocumented ("illegal") opcodes supported by DTV2
static struct ronode *mnemo_6502undoc2_tree = NULL; // holds remaining 6502 undocumented ("illegal") opcodes (currently ANC only, maybe more will get moved)
static struct ronode *mnemo_c64dtv2_tree = NULL; // holds C64DTV2 extensions (BRA/SAC/SIR)
static struct ronode *mnemo_65c02_tree = NULL; // holds 65c02 extensions
//static struct ronode *mnemo_Rockwell65c02_tree = NULL; // Rockwell
static struct ronode *mnemo_WDC65c02_tree = NULL; // WDC's "stp"/"wai"
@ -223,7 +224,7 @@ static struct ronode mnemos_6502[] = {
// ^^^^ this marks the last element
};
static struct ronode mnemos_6510[] = {
static struct ronode mnemos_6502undoc1[] = {
PREDEFNODE("slo", MERGE(GROUP_ACCU, IDX_SLO)), // ASL + ORA (aka ASO)
PREDEFNODE("rla", MERGE(GROUP_ACCU, IDX_RLA)), // ROL + AND
PREDEFNODE("sre", MERGE(GROUP_ACCU, IDX_SRE)), // LSR + EOR (aka LSE)
@ -237,7 +238,6 @@ static struct ronode mnemos_6510[] = {
PREDEFNODE("sha", MERGE(GROUP_ACCU, IDX_SHA)), // {addr} = A & X & {H+1} (aka AXA aka AHX)
PREDEFNODE("shx", MERGE(GROUP_MISC, IDX_SHX)), // {addr} = X & {H+1} (aka XAS aka SXA)
PREDEFNODE("shy", MERGE(GROUP_MISC, IDX_SHY)), // {addr} = Y & {H+1} (aka SAY aka SYA)
PREDEFNODE("anc", MERGE(GROUP_MISC, IDX_ANC)), // ROL + AND, ASL + ORA (aka AAC)
PREDEFNODE(s_asr, MERGE(GROUP_MISC, IDX_ASR)), // LSR + EOR (aka ALR)
PREDEFNODE("arr", MERGE(GROUP_MISC, IDX_ARR)), // ROR + ADC
PREDEFNODE("sbx", MERGE(GROUP_MISC, IDX_SBX)), // DEX + CMP (aka AXS aka SAX)
@ -249,6 +249,11 @@ static struct ronode mnemos_6510[] = {
// ^^^^ this marks the last element
};
static struct ronode mnemos_6502undoc2[] = {
PREDEFLAST("anc", MERGE(GROUP_MISC, IDX_ANC)), // ROL + AND, ASL + ORA (aka AAC)
// ^^^^ this marks the last element
};
static struct ronode mnemos_c64dtv2[] = {
PREDEFNODE(s_bra, MERGE(GROUP_RELATIVE8, 0x12)), // branch always
PREDEFNODE("sac", MERGE(GROUP_MISC, IDX_SAC)), // set accumulator mapping
@ -370,7 +375,8 @@ void Mnemo_init(void)
{
mnemo_dyna_buf = DynaBuf_create(MNEMO_DYNABUF_INITIALSIZE);
Tree_add_table(&mnemo_6502_tree, mnemos_6502);
Tree_add_table(&mnemo_6510_tree, mnemos_6510);
Tree_add_table(&mnemo_6502undoc1_tree, mnemos_6502undoc1);
Tree_add_table(&mnemo_6502undoc2_tree, mnemos_6502undoc2);
Tree_add_table(&mnemo_c64dtv2_tree, mnemos_c64dtv2);
Tree_add_table(&mnemo_65c02_tree, mnemos_65c02);
// Tree_add_table(&mnemo_Rockwell65c02_tree, mnemos_Rockwell65c02);
@ -908,7 +914,11 @@ int keyword_is_6510mnemo(int length)
// make lower case version of mnemonic in local dynamic buffer
DynaBuf_to_lower(mnemo_dyna_buf, GlobalDynaBuf);
// first check undocumented ("illegal") opcodes...
if (check_mnemo_tree(mnemo_6510_tree, mnemo_dyna_buf))
if (check_mnemo_tree(mnemo_6502undoc1_tree, mnemo_dyna_buf))
return TRUE;
// then check some more undocumented ("illegal") opcodes...
if (check_mnemo_tree(mnemo_6502undoc2_tree, mnemo_dyna_buf))
return TRUE;
// ...then check original opcodes
@ -927,8 +937,8 @@ int keyword_is_c64dtv2mnemo(int length)
if (check_mnemo_tree(mnemo_c64dtv2_tree, mnemo_dyna_buf))
return TRUE;
// ...then check undocumented ("illegal") opcodes...
if (check_mnemo_tree(mnemo_6510_tree, mnemo_dyna_buf))
// ...then check a few undocumented ("illegal") opcodes...
if (check_mnemo_tree(mnemo_6502undoc1_tree, mnemo_dyna_buf))
return TRUE;
// ...then check original opcodes

View File

@ -49,8 +49,9 @@ static struct ronode *pseudo_opcode_tree = NULL; // tree to hold pseudo opcodes
void notreallypo_setpc(void)
{
int segment_flags = 0;
intval_t new_addr = ALU_defined_int();
struct result intresult;
ALU_defined_int(&intresult); // read new address
// check for modifiers
while (Input_accept_comma()) {
// parse modifier. if no keyword given, give up
@ -66,24 +67,24 @@ void notreallypo_setpc(void)
return;
}
}
vcpu_set_pc(new_addr, segment_flags);
vcpu_set_pc(intresult.val.intval, segment_flags);
}
// define default value for empty memory ("!initmem" pseudo opcode)
static enum eos po_initmem(void)
{
intval_t content;
struct result intresult;
// ignore in all passes but in first
if (pass_count)
return SKIP_REMAINDER;
// get value
content = ALU_defined_int();
if ((content > 0xff) || (content < -0x80))
ALU_defined_int(&intresult);
if ((intresult.val.intval > 0xff) || (intresult.val.intval < -0x80))
Throw_error(exception_number_out_of_range);
if (output_initmem(content & 0xff))
if (output_initmem(intresult.val.intval & 0xff))
return SKIP_REMAINDER;
return ENSURE_EOS;
}
@ -361,12 +362,13 @@ static enum eos po_binary(void)
// reserve space by sending bytes of given value ("!fi" / "!fill" pseudo opcode)
static enum eos po_fill(void)
{
intval_t fill = FILLVALUE_FILL,
size = ALU_defined_int();
struct result sizeresult;
intval_t fill = FILLVALUE_FILL;
ALU_defined_int(&sizeresult); // FIXME - forbid addresses!
if (Input_accept_comma())
fill = ALU_any_int();
while (size--)
fill = ALU_any_int(); // FIXME - forbid addresses!
while (sizeresult.val.intval--)
output_8(fill);
return ENSURE_EOS;
}
@ -376,9 +378,9 @@ static enum eos po_fill(void)
static enum eos po_align(void)
{
// FIXME - read cpu state via function call!
intval_t and,
equal,
fill,
struct result andresult,
equalresult;
intval_t fill,
test = CPU_state.pc.val.intval;
// make sure PC is defined.
@ -388,15 +390,15 @@ static enum eos po_align(void)
return SKIP_REMAINDER;
}
and = ALU_defined_int();
ALU_defined_int(&andresult); // FIXME - forbid addresses!
if (!Input_accept_comma())
Throw_error(exception_syntax);
equal = ALU_defined_int();
ALU_defined_int(&equalresult); // ...allow addresses (unlikely, but possible)
if (Input_accept_comma())
fill = ALU_any_int();
else
fill = CPU_state.type->default_align_value;
while ((test++ & and) != equal)
while ((test++ & andresult.val.intval) != equalresult.val.intval)
output_8(fill);
return ENSURE_EOS;
}
@ -410,14 +412,14 @@ static const char Error_old_offset_assembly[] =
static enum eos po_pseudopc(void)
{
// FIXME - read pc using a function call!
intval_t new_pc,
new_offset;
struct result new_pc_result;
intval_t new_offset;
int outer_flags = CPU_state.pc.flags;
// set new
new_pc = ALU_defined_int(); // FIXME - allow for undefined!
new_offset = (new_pc - CPU_state.pc.val.intval) & 0xffff;
CPU_state.pc.val.intval = new_pc;
ALU_defined_int(&new_pc_result); // FIXME - allow for undefined! (complaining about non-addresses would be logical, but annoying)
new_offset = (new_pc_result.val.intval - CPU_state.pc.val.intval) & 0xffff;
CPU_state.pc.val.intval = new_pc_result.val.intval;
CPU_state.pc.flags |= MVALUE_DEFINED; // FIXME - remove when allowing undefined!
// if there's a block, parse that and then restore old value!
if (Parse_optional_block()) {
@ -660,12 +662,12 @@ static enum eos po_source(void) // now GotByte = illegal char
// conditional assembly ("!if"). has to be re-entrant.
static enum eos po_if(void) // now GotByte = illegal char
{
intval_t cond;
struct result cond_result;
cond = ALU_defined_int();
ALU_defined_int(&cond_result);
if (GotByte != CHAR_SOB)
Throw_serious_error(exception_no_left_brace);
flow_parse_block_else_block(!!cond);
flow_parse_block_else_block(!!cond_result.val.intval);
return ENSURE_EOS;
}
@ -723,7 +725,7 @@ static enum eos po_for(void) // now GotByte = illegal char
{
zone_t zone;
int force_bit;
intval_t first_arg;
struct result intresult;
struct for_loop loop;
if (Input_read_zone_and_keyword(&zone) == 0) // skips spaces before
@ -737,23 +739,30 @@ static enum eos po_for(void) // now GotByte = illegal char
return SKIP_REMAINDER;
}
first_arg = ALU_defined_int();
ALU_defined_int(&intresult); // read first argument
loop.counter.addr_refs = intresult.addr_refs;
if (Input_accept_comma()) {
loop.old_algo = FALSE; // new format - yay!
if (!warn_on_old_for)
Throw_first_pass_warning("Found new \"!for\" syntax.");
loop.counter_first = first_arg; // use given argument
loop.counter_last = ALU_defined_int(); // read second argument
loop.counter_increment = (loop.counter_last < loop.counter_first) ? -1 : 1;
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
&& (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)
Throw_first_pass_warning("Found old \"!for\" syntax.");
if (first_arg < 0)
if (intresult.val.intval < 0)
Throw_serious_error("Loop count is negative.");
loop.counter_first = 0; // CAUTION - old algo pre-increments and therefore starts with 1!
loop.counter_last = first_arg; // use given argument
loop.counter_increment = 1;
loop.counter.first = 0; // CAUTION - old algo pre-increments and therefore starts with 1!
loop.counter.last = intresult.val.intval; // use given argument
loop.counter.increment = 1;
}
if (GotByte != CHAR_SOB)
Throw_serious_error(exception_no_left_brace);

View File

@ -1,5 +1,5 @@
// ACME - a crossassembler for producing 6502/65c02/65816 code.
// Copyright (C) 1998-2014 Marco Baye
// Copyright (C) 1998-2015 Marco Baye
// Have a look at "acme.c" for further info
//
// Section stuff
@ -20,6 +20,8 @@ struct section {
// Constants
// TODO: rename internal stuff from "zone" to "scope",
// then add cheap locals (so there's SCOPE_GLOBAL, scope_zone and scope_cheap)
#define ZONE_GLOBAL 0 // Number of "global zone"

View File

@ -15,6 +15,8 @@ struct symbol {
struct result result; // expression flags and value
int usage; // usage count
int pass; // pass of creation (for anon counters)
// add flag to indicate "has already been reported as undefined"
// add file ref + line num of last definition
};

View File

@ -39,8 +39,10 @@ void typesystem_want_imm(struct result *result)
return;
if (!(result->flags & MVALUE_DEFINED))
return;
if (result->addr_refs != 0)
if (result->addr_refs != 0) {
Throw_warning("Wrong type - expected integer.");
//printf("refcount should be 0, but is %d\n", result->addr_refs);
}
}
void typesystem_want_addr(struct result *result)
{
@ -48,6 +50,8 @@ void typesystem_want_addr(struct result *result)
return;
if (!(result->flags & MVALUE_DEFINED))
return;
if (result->addr_refs != 1)
if (result->addr_refs != 1) {
Throw_warning("Wrong type - expected address.");
//printf("refcount should be 1, but is %d\n", result->addr_refs);
}
}