mirror of
https://github.com/uffejakobsen/acme.git
synced 2025-01-10 21:30:30 +00:00
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:
parent
9c3d91adfa
commit
8d2719db8a
@ -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
|
||||
----------------------------------------------------------------------
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
10
src/acme.c
10
src/acme.c
@ -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
191
src/alu.c
@ -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);
|
||||
|
27
src/alu.h
27
src/alu.h
@ -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);
|
||||
|
@ -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 {
|
||||
|
26
src/cpu.c
26
src/cpu.c
@ -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"
|
||||
};
|
||||
|
||||
|
||||
|
19
src/flow.c
19
src/flow.c
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
11
src/flow.h
11
src/flow.h
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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...
|
||||
|
28
src/mnemo.c
28
src/mnemo.c
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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"
|
||||
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user