2016-12-28 20:32:00 +00:00
|
|
|
// ACME - a crossassembler for producing 6502/65c02/65816/65ce02 code.
|
2020-04-25 10:20:52 +00:00
|
|
|
// Copyright (C) 1998-2020 Marco Baye
|
2012-02-27 21:14:46 +00:00
|
|
|
// Have a look at "acme.c" for further info
|
|
|
|
//
|
|
|
|
// Arithmetic/logic unit
|
|
|
|
// 11 Oct 2006 Improved float reading in parse_decimal_value()
|
|
|
|
// 24 Nov 2007 Now accepts floats starting with decimal point
|
|
|
|
// 31 Jul 2009 Changed ASR again, just to be on the safe side.
|
2014-01-16 18:16:24 +00:00
|
|
|
// 14 Jan 2014 Changed associativity of "power-of" operator,
|
|
|
|
// so a^b^c now means a^(b^c).
|
2014-05-07 09:40:50 +00:00
|
|
|
// 7 May 2014 C-style "==" operators are now recognized (but
|
|
|
|
// give a warning).
|
2014-05-31 00:46:55 +00:00
|
|
|
// 31 May 2014 Added "0b" binary number prefix as alternative to "%".
|
2015-06-14 23:16:23 +00:00
|
|
|
// 28 Apr 2015 Added symbol name output to "value not defined" error.
|
2020-04-26 16:24:34 +00:00
|
|
|
// 1 Feb 2019 Prepared to make "honor leading zeroes" optionally (now done)
|
2014-12-22 00:47:52 +00:00
|
|
|
#include "alu.h"
|
2012-02-27 21:14:46 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <math.h> // only for fp support
|
|
|
|
#include "platform.h"
|
|
|
|
#include "dynabuf.h"
|
|
|
|
#include "encoding.h"
|
|
|
|
#include "global.h"
|
|
|
|
#include "input.h"
|
2014-03-11 14:22:32 +00:00
|
|
|
#include "output.h"
|
2012-02-27 21:14:46 +00:00
|
|
|
#include "section.h"
|
2014-06-07 00:12:10 +00:00
|
|
|
#include "symbol.h"
|
2012-02-27 21:14:46 +00:00
|
|
|
#include "tree.h"
|
|
|
|
|
|
|
|
|
|
|
|
// constants
|
|
|
|
|
2015-06-14 23:16:23 +00:00
|
|
|
#define ERRORMSG_DYNABUF_INITIALSIZE 256 // ad hoc
|
2012-02-27 21:14:46 +00:00
|
|
|
#define FUNCTION_DYNABUF_INITIALSIZE 8 // enough for "arctan"
|
|
|
|
#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 '('.";
|
|
|
|
#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";
|
|
|
|
#define s_sin (s_arcsin + 3) // Yes, I know I'm sick
|
|
|
|
static const char s_arccos[] = "arccos";
|
|
|
|
#define s_cos (s_arccos + 3) // Yes, I know I'm sick
|
|
|
|
static const char s_arctan[] = "arctan";
|
|
|
|
#define s_tan (s_arctan + 3) // Yes, I know I'm sick
|
|
|
|
|
|
|
|
// operator handles (FIXME - use function pointers instead? or too slow?)
|
|
|
|
enum operator_handle {
|
|
|
|
// special values (pseudo operators)
|
2017-10-21 19:59:56 +00:00
|
|
|
OPHANDLE_EXPRSTART, // "start of expression"
|
|
|
|
OPHANDLE_EXPREND, // "end of expression"
|
2012-02-27 21:14:46 +00:00
|
|
|
// functions
|
2014-06-02 00:47:46 +00:00
|
|
|
OPHANDLE_ADDR, // addr(v)
|
2012-02-27 21:14:46 +00:00
|
|
|
OPHANDLE_INT, // int(v)
|
|
|
|
OPHANDLE_FLOAT, // float(v)
|
|
|
|
OPHANDLE_SIN, // sin(v)
|
|
|
|
OPHANDLE_COS, // cos(v)
|
|
|
|
OPHANDLE_TAN, // tan(v)
|
|
|
|
OPHANDLE_ARCSIN, // arcsin(v)
|
|
|
|
OPHANDLE_ARCCOS, // arccos(v)
|
|
|
|
OPHANDLE_ARCTAN, // arctan(v)
|
|
|
|
// monadic operators
|
|
|
|
OPHANDLE_OPENING, // (v '(', starts subexpression
|
|
|
|
OPHANDLE_NOT, // !v NOT v bit-wise NOT
|
|
|
|
OPHANDLE_NEGATE, // -v Negate
|
|
|
|
OPHANDLE_LOWBYTEOF, // <v Lowbyte of
|
|
|
|
OPHANDLE_HIGHBYTEOF, // >v Highbyte of
|
|
|
|
OPHANDLE_BANKBYTEOF, // ^v Bankbyte of
|
|
|
|
// dyadic operators
|
|
|
|
OPHANDLE_CLOSING, // v) ')', ends subexpression
|
|
|
|
OPHANDLE_POWEROF, // v^w
|
|
|
|
OPHANDLE_MULTIPLY, // v*w
|
|
|
|
OPHANDLE_DIVIDE, // v/w (Integer) Division
|
|
|
|
OPHANDLE_INTDIV, // v/w v DIV w Integer Division
|
|
|
|
OPHANDLE_MODULO, // v%w v MOD w Remainder
|
|
|
|
OPHANDLE_SL, // v<<w v ASL w v LSL w Shift left
|
|
|
|
OPHANDLE_ASR, // v>>w v ASR w Arithmetic shift right
|
|
|
|
OPHANDLE_LSR, // v>>>w v LSR w Logical shift right
|
|
|
|
OPHANDLE_ADD, // v+w
|
|
|
|
OPHANDLE_SUBTRACT, // v-w
|
|
|
|
OPHANDLE_EQUALS, // v=w
|
|
|
|
OPHANDLE_LE, // v<=w
|
|
|
|
OPHANDLE_LESSTHAN, // v< w
|
|
|
|
OPHANDLE_GE, // v>=w
|
|
|
|
OPHANDLE_GREATERTHAN, // v> w
|
|
|
|
OPHANDLE_NOTEQUAL, // v!=w v<>w v><w
|
|
|
|
OPHANDLE_AND, // v&w v AND w
|
|
|
|
OPHANDLE_OR, // v|w v OR w
|
|
|
|
OPHANDLE_EOR, // v EOR w v XOR w (FIXME:remove)
|
|
|
|
OPHANDLE_XOR, // v XOR w
|
|
|
|
};
|
2014-03-11 12:07:11 +00:00
|
|
|
struct operator {
|
2012-02-27 21:14:46 +00:00
|
|
|
enum operator_handle handle;
|
2014-01-16 18:16:24 +00:00
|
|
|
char priority_and_associativity;
|
2012-02-27 21:14:46 +00:00
|
|
|
};
|
2014-01-16 18:16:24 +00:00
|
|
|
#define IS_RIGHT_ASSOCIATIVE(p) ((p) & 1) // lsb of priority value signals right-associtivity
|
|
|
|
|
|
|
|
// operator structs (only hold handle and priority/associativity value)
|
2017-10-21 19:59:56 +00:00
|
|
|
static struct operator ops_exprend = {OPHANDLE_EXPREND, 0}; // special
|
|
|
|
static struct operator ops_exprstart = {OPHANDLE_EXPRSTART, 2}; // special
|
2014-03-11 12:07:11 +00:00
|
|
|
static struct operator ops_closing = {OPHANDLE_CLOSING, 4}; // dyadic
|
|
|
|
static struct operator ops_opening = {OPHANDLE_OPENING, 6}; // monadic
|
|
|
|
static struct operator ops_or = {OPHANDLE_OR, 8}; // dyadic
|
|
|
|
static struct operator ops_eor = {OPHANDLE_EOR, 10}; // (FIXME:remove)
|
|
|
|
static struct operator ops_xor = {OPHANDLE_XOR, 10}; // dyadic
|
|
|
|
static struct operator ops_and = {OPHANDLE_AND, 12}; // dyadic
|
|
|
|
static struct operator ops_equals = {OPHANDLE_EQUALS, 14}; // dyadic
|
|
|
|
static struct operator ops_notequal = {OPHANDLE_NOTEQUAL, 16}; // dyadic
|
2014-01-16 18:16:24 +00:00
|
|
|
// same priority for all comparison operators (left-associative)
|
2014-03-11 12:07:11 +00:00
|
|
|
static struct operator ops_le = {OPHANDLE_LE, 18}; // dyadic
|
|
|
|
static struct operator ops_lessthan = {OPHANDLE_LESSTHAN, 18}; // dyadic
|
|
|
|
static struct operator ops_ge = {OPHANDLE_GE, 18}; // dyadic
|
|
|
|
static struct operator ops_greaterthan = {OPHANDLE_GREATERTHAN,18}; // dyadic
|
2012-02-27 21:14:46 +00:00
|
|
|
// same priority for all byte extraction operators
|
2014-03-11 12:07:11 +00:00
|
|
|
static struct operator ops_lowbyteof = {OPHANDLE_LOWBYTEOF, 20}; // monadic
|
|
|
|
static struct operator ops_highbyteof = {OPHANDLE_HIGHBYTEOF, 20}; // monadic
|
|
|
|
static struct operator ops_bankbyteof = {OPHANDLE_BANKBYTEOF, 20}; // monadic
|
2014-01-16 18:16:24 +00:00
|
|
|
// same priority for all shift operators (left-associative, though they could be argued to be made right-associative :))
|
2014-03-11 12:07:11 +00:00
|
|
|
static struct operator ops_sl = {OPHANDLE_SL, 22}; // dyadic
|
|
|
|
static struct operator ops_asr = {OPHANDLE_ASR, 22}; // dyadic
|
|
|
|
static struct operator ops_lsr = {OPHANDLE_LSR, 22}; // dyadic
|
2014-01-16 18:16:24 +00:00
|
|
|
// same priority for "+" and "-" (left-associative)
|
2014-03-11 12:07:11 +00:00
|
|
|
static struct operator ops_add = {OPHANDLE_ADD, 24}; // dyadic
|
|
|
|
static struct operator ops_subtract = {OPHANDLE_SUBTRACT, 24}; // dyadic
|
2014-01-16 18:16:24 +00:00
|
|
|
// same priority for "*", "/" and "%" (left-associative)
|
2014-03-11 12:07:11 +00:00
|
|
|
static struct operator ops_multiply = {OPHANDLE_MULTIPLY, 26}; // dyadic
|
|
|
|
static struct operator ops_divide = {OPHANDLE_DIVIDE, 26}; // dyadic
|
|
|
|
static struct operator ops_intdiv = {OPHANDLE_INTDIV, 26}; // dyadic
|
|
|
|
static struct operator ops_modulo = {OPHANDLE_MODULO, 26}; // dyadic
|
2012-02-27 21:14:46 +00:00
|
|
|
// highest "real" priorities
|
2014-03-11 12:07:11 +00:00
|
|
|
static struct operator ops_negate = {OPHANDLE_NEGATE, 28}; // monadic
|
|
|
|
static struct operator ops_powerof = {OPHANDLE_POWEROF, 29}; // dyadic, right-associative
|
|
|
|
static struct operator ops_not = {OPHANDLE_NOT, 30}; // monadic
|
2014-12-16 08:21:44 +00:00
|
|
|
// function calls act as if they were monadic operators.
|
|
|
|
// they need high priorities to make sure they are evaluated once the
|
|
|
|
// parentheses' content is known:
|
|
|
|
// "sin(3 + 4) DYADIC_OPERATOR 5" becomes "sin 7 DYADIC_OPERATOR 5",
|
|
|
|
// so function calls' priority must be higher than all dyadic operators.
|
2014-06-02 00:47:46 +00:00
|
|
|
static struct operator ops_addr = {OPHANDLE_ADDR, 32}; // function
|
2014-03-11 12:07:11 +00:00
|
|
|
static struct operator ops_int = {OPHANDLE_INT, 32}; // function
|
|
|
|
static struct operator ops_float = {OPHANDLE_FLOAT, 32}; // function
|
|
|
|
static struct operator ops_sin = {OPHANDLE_SIN, 32}; // function
|
|
|
|
static struct operator ops_cos = {OPHANDLE_COS, 32}; // function
|
|
|
|
static struct operator ops_tan = {OPHANDLE_TAN, 32}; // function
|
|
|
|
static struct operator ops_arcsin = {OPHANDLE_ARCSIN, 32}; // function
|
|
|
|
static struct operator ops_arccos = {OPHANDLE_ARCCOS, 32}; // function
|
|
|
|
static struct operator ops_arctan = {OPHANDLE_ARCTAN, 32}; // function
|
2012-02-27 21:14:46 +00:00
|
|
|
|
|
|
|
|
|
|
|
// variables
|
2015-06-14 23:16:23 +00:00
|
|
|
static struct dynabuf *errormsg_dyna_buf; // dynamic buffer for "value not defined" error
|
2014-03-11 12:07:11 +00:00
|
|
|
static struct dynabuf *function_dyna_buf; // dynamic buffer for fn names
|
|
|
|
static struct operator **operator_stack = NULL;
|
2012-02-27 21:14:46 +00:00
|
|
|
static int operator_stk_size = HALF_INITIAL_STACK_SIZE;
|
|
|
|
static int operator_sp; // operator stack pointer
|
2020-04-28 16:02:09 +00:00
|
|
|
static struct number *operand_stack = NULL; // flags and value
|
2012-02-27 21:14:46 +00:00
|
|
|
static int operand_stk_size = HALF_INITIAL_STACK_SIZE;
|
|
|
|
static int operand_sp; // value stack pointer
|
2014-03-11 12:07:11 +00:00
|
|
|
enum alu_state {
|
2012-02-27 21:14:46 +00:00
|
|
|
STATE_EXPECT_OPERAND_OR_MONADIC_OPERATOR,
|
|
|
|
STATE_EXPECT_DYADIC_OPERATOR,
|
|
|
|
STATE_TRY_TO_REDUCE_STACKS,
|
|
|
|
STATE_MAX_GO_ON, // "border value" to find the stoppers:
|
|
|
|
STATE_ERROR, // error has occured
|
2014-03-11 12:07:11 +00:00
|
|
|
STATE_END // standard end
|
2012-02-27 21:14:46 +00:00
|
|
|
};
|
2014-03-11 12:07:11 +00:00
|
|
|
static enum alu_state alu_state; // deterministic finite automaton
|
2012-02-27 21:14:46 +00:00
|
|
|
// predefined stuff
|
2014-11-24 14:52:05 +00:00
|
|
|
static struct ronode *operator_tree = NULL; // tree to hold operators
|
|
|
|
static struct ronode operator_list[] = {
|
2012-02-27 21:14:46 +00:00
|
|
|
PREDEFNODE(s_asr, &ops_asr),
|
|
|
|
PREDEFNODE(s_lsr, &ops_lsr),
|
|
|
|
PREDEFNODE(s_asl, &ops_sl),
|
|
|
|
PREDEFNODE("lsl", &ops_sl),
|
|
|
|
PREDEFNODE("div", &ops_intdiv),
|
|
|
|
PREDEFNODE("mod", &ops_modulo),
|
|
|
|
PREDEFNODE(s_and, &ops_and),
|
|
|
|
PREDEFNODE(s_or, &ops_or),
|
|
|
|
PREDEFNODE(s_eor, &ops_eor), // (FIXME:remove)
|
|
|
|
PREDEFLAST(s_xor, &ops_xor),
|
|
|
|
// ^^^^ this marks the last element
|
|
|
|
};
|
2014-11-24 14:52:05 +00:00
|
|
|
static struct ronode *function_tree = NULL; // tree to hold functions
|
|
|
|
static struct ronode function_list[] = {
|
2014-06-02 00:47:46 +00:00
|
|
|
PREDEFNODE("addr", &ops_addr),
|
2015-06-14 23:16:23 +00:00
|
|
|
PREDEFNODE("address", &ops_addr),
|
2012-02-27 21:14:46 +00:00
|
|
|
PREDEFNODE("int", &ops_int),
|
|
|
|
PREDEFNODE("float", &ops_float),
|
|
|
|
PREDEFNODE(s_arcsin, &ops_arcsin),
|
|
|
|
PREDEFNODE(s_arccos, &ops_arccos),
|
|
|
|
PREDEFNODE(s_arctan, &ops_arctan),
|
|
|
|
PREDEFNODE(s_sin, &ops_sin),
|
|
|
|
PREDEFNODE(s_cos, &ops_cos),
|
|
|
|
PREDEFLAST(s_tan, &ops_tan),
|
|
|
|
// ^^^^ this marks the last element
|
|
|
|
};
|
|
|
|
|
2016-02-21 23:08:02 +00:00
|
|
|
#define LEFT_FLAGS (operand_stack[operand_sp - 2].flags)
|
|
|
|
#define RIGHT_FLAGS (operand_stack[operand_sp - 1].flags)
|
|
|
|
#define LEFT_INTVAL (operand_stack[operand_sp - 2].val.intval)
|
|
|
|
#define RIGHT_INTVAL (operand_stack[operand_sp - 1].val.intval)
|
|
|
|
#define LEFT_FPVAL (operand_stack[operand_sp - 2].val.fpval)
|
|
|
|
#define RIGHT_FPVAL (operand_stack[operand_sp - 1].val.fpval)
|
|
|
|
#define LEFT_ADDRREFS (operand_stack[operand_sp - 2].addr_refs)
|
|
|
|
#define RIGHT_ADDRREFS (operand_stack[operand_sp - 1].addr_refs)
|
2012-02-27 21:14:46 +00:00
|
|
|
|
|
|
|
#define PUSH_OPERATOR(x) operator_stack[operator_sp++] = (x)
|
|
|
|
|
2014-06-02 00:47:46 +00:00
|
|
|
#define PUSH_INTOPERAND(i, f, r) \
|
2012-02-27 21:14:46 +00:00
|
|
|
do { \
|
|
|
|
operand_stack[operand_sp].flags = (f); \
|
2014-06-02 00:47:46 +00:00
|
|
|
operand_stack[operand_sp].val.intval = (i); \
|
|
|
|
operand_stack[operand_sp++].addr_refs = (r); \
|
2012-02-27 21:14:46 +00:00
|
|
|
} while (0)
|
2020-04-28 16:02:09 +00:00
|
|
|
#define PUSH_FPOPERAND(fp, f) \
|
|
|
|
do { \
|
|
|
|
operand_stack[operand_sp].flags = (f) | NUMBER_IS_FLOAT; \
|
|
|
|
operand_stack[operand_sp].val.fpval = (fp); \
|
|
|
|
operand_stack[operand_sp++].addr_refs = 0; \
|
2012-02-27 21:14:46 +00:00
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
|
|
// enlarge operator stack
|
|
|
|
static void enlarge_operator_stack(void)
|
|
|
|
{
|
|
|
|
operator_stk_size *= 2;
|
|
|
|
operator_stack = realloc(operator_stack, operator_stk_size * sizeof(*operator_stack));
|
|
|
|
if (operator_stack == NULL)
|
|
|
|
Throw_serious_error(exception_no_memory_left);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// enlarge operand stack
|
|
|
|
static void enlarge_operand_stack(void)
|
|
|
|
{
|
|
|
|
operand_stk_size *= 2;
|
|
|
|
operand_stack = realloc(operand_stack, operand_stk_size * sizeof(*operand_stack));
|
|
|
|
if (operand_stack == NULL)
|
|
|
|
Throw_serious_error(exception_no_memory_left);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// create dynamic buffer, operator/function trees and operator/operand stacks
|
|
|
|
void ALU_init(void)
|
|
|
|
{
|
2015-06-14 23:16:23 +00:00
|
|
|
errormsg_dyna_buf = DynaBuf_create(ERRORMSG_DYNABUF_INITIALSIZE);
|
2012-02-27 21:14:46 +00:00
|
|
|
function_dyna_buf = DynaBuf_create(FUNCTION_DYNABUF_INITIALSIZE);
|
|
|
|
Tree_add_table(&operator_tree, operator_list);
|
|
|
|
Tree_add_table(&function_tree, function_list);
|
|
|
|
enlarge_operator_stack();
|
|
|
|
enlarge_operand_stack();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// not-so-braindead algorithm for calculating "to the power of" function for
|
|
|
|
// integer operands.
|
|
|
|
// my_pow(whatever, 0) returns 1. my_pow(0, whatever_but_zero) returns 0.
|
|
|
|
static intval_t my_pow(intval_t mantissa, intval_t exponent)
|
|
|
|
{
|
|
|
|
intval_t result = 1;
|
|
|
|
|
|
|
|
while (exponent) {
|
|
|
|
// handle exponent's lowmost bit
|
|
|
|
if (exponent & 1)
|
|
|
|
result *= mantissa;
|
|
|
|
// square the mantissa, halve the exponent
|
|
|
|
mantissa *= mantissa;
|
|
|
|
exponent >>= 1;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// arithmetic shift right (works even if C compiler does not support it)
|
|
|
|
static intval_t my_asr(intval_t left, intval_t right)
|
|
|
|
{
|
|
|
|
// if first operand is positive or zero, ASR and LSR are equivalent,
|
|
|
|
// so just do it and return the result:
|
|
|
|
if (left >= 0)
|
|
|
|
return left >> right;
|
|
|
|
|
|
|
|
// However, if the first operand is negative, the result is
|
|
|
|
// implementation-defined: While most compilers will do ASR, some others
|
|
|
|
// might do LSR instead, and *theoretically*, it is even possible for a
|
|
|
|
// compiler to define silly stuff like "shifting a negative value to the
|
|
|
|
// right will always return -1".
|
|
|
|
// Therefore, in case of a negative operand, we'll use this quick and
|
|
|
|
// simple workaround:
|
|
|
|
return ~((~left) >> right);
|
|
|
|
}
|
|
|
|
|
2020-05-02 21:59:20 +00:00
|
|
|
|
|
|
|
// if needed, throw "Value not defined" error
|
|
|
|
// This function is not allowed to change DynaBuf because the symbol's name
|
|
|
|
// might be stored there!
|
|
|
|
static void check_for_def(struct symbol *optional_symbol, int flags, char optional_prefix_char, char *name, size_t length)
|
2015-06-14 23:16:23 +00:00
|
|
|
{
|
2020-05-02 21:59:20 +00:00
|
|
|
if (flags & NUMBER_IS_DEFINED)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!pass.complain_about_undefined)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// only complain once per symbol
|
|
|
|
if (optional_symbol) {
|
|
|
|
if (optional_symbol->has_been_reported)
|
|
|
|
return;
|
|
|
|
|
|
|
|
optional_symbol->has_been_reported = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
DYNABUF_CLEAR(errormsg_dyna_buf);
|
|
|
|
DynaBuf_add_string(errormsg_dyna_buf, "Value not defined (");
|
|
|
|
length += errormsg_dyna_buf->size;
|
|
|
|
|
|
|
|
if (optional_prefix_char) {
|
|
|
|
DynaBuf_append(errormsg_dyna_buf, optional_prefix_char);
|
|
|
|
++length;
|
|
|
|
}
|
|
|
|
DynaBuf_add_string(errormsg_dyna_buf, name);
|
|
|
|
if (errormsg_dyna_buf->size < length) {
|
|
|
|
Bug_found("Illegal symbol name length", errormsg_dyna_buf->size - length);
|
|
|
|
} else {
|
|
|
|
errormsg_dyna_buf->size = length;
|
2015-06-14 23:16:23 +00:00
|
|
|
}
|
2020-05-02 21:59:20 +00:00
|
|
|
DynaBuf_add_string(errormsg_dyna_buf, ").");
|
|
|
|
DynaBuf_append(errormsg_dyna_buf, '\0');
|
|
|
|
Throw_error(errormsg_dyna_buf->buffer);
|
2015-06-14 23:16:23 +00:00
|
|
|
}
|
2012-02-27 21:14:46 +00:00
|
|
|
|
2020-05-02 21:59:20 +00:00
|
|
|
|
2014-06-07 00:12:10 +00:00
|
|
|
// Lookup (and create, if necessary) symbol tree item and return its value.
|
2016-08-05 09:59:07 +00:00
|
|
|
// DynaBuf holds the symbol's name and "scope" its scope.
|
2015-06-14 23:16:23 +00:00
|
|
|
// The name length must be given explicitly because of anonymous forward labels;
|
|
|
|
// their internal name is different (longer) than their displayed name.
|
2012-02-27 21:14:46 +00:00
|
|
|
// This function is not allowed to change DynaBuf because that's where the
|
2014-06-07 00:12:10 +00:00
|
|
|
// symbol name is stored!
|
2017-10-29 23:29:07 +00:00
|
|
|
static void get_symbol_value(scope_t scope, char optional_prefix_char, size_t name_length)
|
2012-02-27 21:14:46 +00:00
|
|
|
{
|
2014-06-07 00:12:10 +00:00
|
|
|
struct symbol *symbol;
|
2012-02-27 21:14:46 +00:00
|
|
|
|
2014-06-07 00:12:10 +00:00
|
|
|
// if the symbol gets created now, mark it as unsure
|
2020-04-28 16:02:09 +00:00
|
|
|
symbol = symbol_find(scope, NUMBER_EVER_UNDEFINED);
|
2020-05-02 21:59:20 +00:00
|
|
|
// if needed, output "value not defined" error
|
|
|
|
check_for_def(symbol, symbol->result.flags, optional_prefix_char, GLOBALDYNABUF_CURRENT, name_length);
|
2012-02-27 21:14:46 +00:00
|
|
|
// in first pass, count usage
|
2020-05-02 10:40:10 +00:00
|
|
|
if (FIRST_PASS)
|
2014-06-07 00:12:10 +00:00
|
|
|
symbol->usage++;
|
2012-02-27 21:14:46 +00:00
|
|
|
// push operand, regardless of whether int or float
|
2020-04-26 22:26:05 +00:00
|
|
|
operand_stack[operand_sp++] = symbol->result;
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-05-02 11:28:15 +00:00
|
|
|
// Parse program counter ('*')
|
|
|
|
static void parse_program_counter(void) // Now GotByte = "*"
|
|
|
|
{
|
|
|
|
struct number pc;
|
|
|
|
|
|
|
|
GetByte();
|
|
|
|
vcpu_read_pc(&pc);
|
2020-05-02 21:59:20 +00:00
|
|
|
// if needed, output "value not defined" error
|
|
|
|
check_for_def(NULL, pc.flags, 0, "*", 1);
|
2020-05-02 11:28:15 +00:00
|
|
|
PUSH_INTOPERAND(pc.val.intval, pc.flags, pc.addr_refs);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-02-27 21:14:46 +00:00
|
|
|
// Parse quoted character.
|
|
|
|
// The character will be converted using the current encoding.
|
|
|
|
static void parse_quoted_character(char closing_quote)
|
|
|
|
{
|
|
|
|
intval_t value;
|
|
|
|
|
|
|
|
// read character to parse - make sure not at end of statement
|
|
|
|
if (GetQuotedByte() == CHAR_EOS)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// on empty string, complain
|
|
|
|
if (GotByte == closing_quote) {
|
|
|
|
Throw_error(exception_missing_string);
|
2017-10-29 23:29:07 +00:00
|
|
|
alu_state = STATE_ERROR;
|
2012-02-27 21:14:46 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// parse character
|
2014-12-04 23:58:00 +00:00
|
|
|
value = (intval_t) encoding_encode_char(GotByte);
|
2012-02-27 21:14:46 +00:00
|
|
|
// Read closing quote (hopefully)
|
2016-02-21 23:08:02 +00:00
|
|
|
if (GetQuotedByte() == closing_quote) {
|
2012-02-27 21:14:46 +00:00
|
|
|
GetByte(); // if length == 1, proceed with next byte
|
2016-02-21 23:08:02 +00:00
|
|
|
} else {
|
2012-02-27 21:14:46 +00:00
|
|
|
if (GotByte) {
|
|
|
|
// if longer than one character
|
|
|
|
Throw_error("There's more than one character.");
|
2017-10-29 23:29:07 +00:00
|
|
|
alu_state = STATE_ERROR;
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
2016-02-21 23:08:02 +00:00
|
|
|
}
|
2020-04-28 16:02:09 +00:00
|
|
|
PUSH_INTOPERAND(value, NUMBER_IS_DEFINED | NUMBER_FITS_BYTE, 0);
|
2012-02-27 21:14:46 +00:00
|
|
|
// Now GotByte = char following closing quote (or CHAR_EOS on error)
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-31 00:46:55 +00:00
|
|
|
// Parse binary value. Apart from '0' and '1', it also accepts the characters
|
|
|
|
// '.' and '#', this is much more readable. The current value is stored as soon
|
|
|
|
// as a character is read that is none of those given above.
|
|
|
|
static void parse_binary_value(void) // Now GotByte = "%" or "b"
|
|
|
|
{
|
|
|
|
intval_t value = 0;
|
2020-04-28 16:02:09 +00:00
|
|
|
int flags = NUMBER_IS_DEFINED,
|
2014-05-31 00:46:55 +00:00
|
|
|
digits = -1; // digit counter
|
|
|
|
|
2020-04-28 11:18:22 +00:00
|
|
|
for (;;) {
|
2014-11-30 17:00:13 +00:00
|
|
|
++digits;
|
2014-05-31 00:46:55 +00:00
|
|
|
switch (GetByte()) {
|
|
|
|
case '0':
|
|
|
|
case '.':
|
|
|
|
value <<= 1;
|
2020-04-28 11:18:22 +00:00
|
|
|
continue;
|
2014-05-31 00:46:55 +00:00
|
|
|
case '1':
|
|
|
|
case '#':
|
|
|
|
value = (value << 1) | 1;
|
2020-04-28 11:18:22 +00:00
|
|
|
continue;
|
2014-05-31 00:46:55 +00:00
|
|
|
}
|
2020-04-28 11:18:22 +00:00
|
|
|
break; // found illegal character
|
|
|
|
}
|
2014-05-31 00:46:55 +00:00
|
|
|
// set force bits
|
2020-04-14 00:28:31 +00:00
|
|
|
if (config.honor_leading_zeroes) {
|
2019-02-01 11:23:28 +00:00
|
|
|
if (digits > 8) {
|
|
|
|
if (digits > 16) {
|
|
|
|
if (value < 65536)
|
2020-04-28 16:02:09 +00:00
|
|
|
flags |= NUMBER_FORCES_24;
|
2019-02-01 11:23:28 +00:00
|
|
|
} else {
|
|
|
|
if (value < 256)
|
2020-04-28 16:02:09 +00:00
|
|
|
flags |= NUMBER_FORCES_16;
|
2019-02-01 11:23:28 +00:00
|
|
|
}
|
2014-05-31 00:46:55 +00:00
|
|
|
}
|
|
|
|
}
|
2014-06-02 00:47:46 +00:00
|
|
|
PUSH_INTOPERAND(value, flags, 0);
|
2014-05-31 00:46:55 +00:00
|
|
|
// Now GotByte = non-binary char
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-02-27 21:14:46 +00:00
|
|
|
// Parse hexadecimal value. It accepts "0" to "9", "a" to "f" and "A" to "F".
|
|
|
|
// The current value is stored as soon as a character is read that is none of
|
|
|
|
// those given above.
|
|
|
|
static void parse_hexadecimal_value(void) // Now GotByte = "$" or "x"
|
|
|
|
{
|
|
|
|
char byte;
|
2020-04-28 11:18:22 +00:00
|
|
|
int digits = -1, // digit counter
|
2020-04-28 16:02:09 +00:00
|
|
|
flags = NUMBER_IS_DEFINED;
|
2012-02-27 21:14:46 +00:00
|
|
|
intval_t value = 0;
|
|
|
|
|
2020-04-28 11:18:22 +00:00
|
|
|
for (;;) {
|
2014-11-30 17:00:13 +00:00
|
|
|
++digits;
|
2012-02-27 21:14:46 +00:00
|
|
|
byte = GetByte();
|
2020-04-28 11:18:22 +00:00
|
|
|
// if digit or legal character, add value
|
2012-02-27 21:14:46 +00:00
|
|
|
if ((byte >= '0') && (byte <= '9')) {
|
|
|
|
value = (value << 4) + (byte - '0');
|
2020-04-28 11:18:22 +00:00
|
|
|
continue;
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
|
|
|
if ((byte >= 'a') && (byte <= 'f')) {
|
|
|
|
value = (value << 4) + (byte - 'a') + 10;
|
2020-04-28 11:18:22 +00:00
|
|
|
continue;
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
2020-04-28 11:18:22 +00:00
|
|
|
if ((byte >= 'A') && (byte <= 'F')) {
|
|
|
|
value = (value << 4) + (byte - 'A') + 10;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break; // found illegal character
|
|
|
|
}
|
2012-02-27 21:14:46 +00:00
|
|
|
// set force bits
|
2020-04-14 00:28:31 +00:00
|
|
|
if (config.honor_leading_zeroes) {
|
2019-02-01 11:23:28 +00:00
|
|
|
if (digits > 2) {
|
|
|
|
if (digits > 4) {
|
|
|
|
if (value < 65536)
|
2020-04-28 16:02:09 +00:00
|
|
|
flags |= NUMBER_FORCES_24;
|
2019-02-01 11:23:28 +00:00
|
|
|
} else {
|
|
|
|
if (value < 256)
|
2020-04-28 16:02:09 +00:00
|
|
|
flags |= NUMBER_FORCES_16;
|
2019-02-01 11:23:28 +00:00
|
|
|
}
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
|
|
|
}
|
2014-06-02 00:47:46 +00:00
|
|
|
PUSH_INTOPERAND(value, flags, 0);
|
2012-02-27 21:14:46 +00:00
|
|
|
// Now GotByte = non-hexadecimal char
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// parse fractional part of a floating-point value
|
|
|
|
static void parse_frac_part(int integer_part) // Now GotByte = first digit after decimal point
|
|
|
|
{
|
|
|
|
double denominator = 1,
|
|
|
|
fpval = integer_part;
|
|
|
|
|
|
|
|
// parse digits until no more
|
|
|
|
while ((GotByte >= '0') && (GotByte <= '9')) {
|
|
|
|
fpval = 10 * fpval + (GotByte & 15); // this works. it's ASCII.
|
|
|
|
denominator *= 10;
|
|
|
|
GetByte();
|
|
|
|
}
|
|
|
|
// FIXME - add possibility to read 'e' and exponent!
|
2020-04-28 16:02:09 +00:00
|
|
|
PUSH_FPOPERAND(fpval / denominator, NUMBER_IS_DEFINED);
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Parse a decimal value. As decimal values don't use any prefixes, this
|
2016-02-21 23:08:02 +00:00
|
|
|
// function expects the first digit to be read already.
|
|
|
|
// If the first two digits are "0x", this function branches to the one for
|
|
|
|
// parsing hexadecimal values.
|
|
|
|
// If the first two digits are "0b", this function branches to the one for
|
|
|
|
// parsing binary values.
|
|
|
|
// If a decimal point is read, this function branches to the one for parsing
|
|
|
|
// floating-point values.
|
2012-02-27 21:14:46 +00:00
|
|
|
// This function accepts '0' through '9' and one dot ('.') as the decimal
|
|
|
|
// point. The current value is stored as soon as a character is read that is
|
|
|
|
// none of those given above. Float usage is only activated when a decimal
|
|
|
|
// point has been found, so don't expect "100000000000000000000" to work.
|
|
|
|
// CAUTION: "100000000000000000000.0" won't work either, because when the
|
|
|
|
// decimal point gets parsed, the integer value will have overflown already.
|
|
|
|
static void parse_decimal_value(void) // Now GotByte = first digit
|
|
|
|
{
|
|
|
|
intval_t intval = (GotByte & 15); // this works. it's ASCII.
|
|
|
|
|
|
|
|
GetByte();
|
2014-05-31 00:46:55 +00:00
|
|
|
// check for "0b" (binary) and "0x" (hexadecimal) prefixes
|
|
|
|
if (intval == 0) {
|
|
|
|
if (GotByte == 'b') {
|
|
|
|
parse_binary_value();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (GotByte == 'x') {
|
|
|
|
parse_hexadecimal_value();
|
|
|
|
return;
|
|
|
|
}
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
|
|
|
// parse digits until no more
|
|
|
|
while ((GotByte >= '0') && (GotByte <= '9')) {
|
|
|
|
intval = 10 * intval + (GotByte & 15); // ASCII, see above
|
|
|
|
GetByte();
|
|
|
|
}
|
|
|
|
// check whether it's a float
|
|
|
|
if (GotByte == '.') {
|
|
|
|
// read fractional part
|
|
|
|
GetByte();
|
|
|
|
parse_frac_part(intval);
|
|
|
|
} else {
|
2020-04-28 16:02:09 +00:00
|
|
|
PUSH_INTOPERAND(intval, NUMBER_IS_DEFINED, 0);
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
|
|
|
// Now GotByte = non-decimal char
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Parse octal value. It accepts "0" to "7". The current value is stored as
|
|
|
|
// soon as a character is read that is none of those given above.
|
|
|
|
static void parse_octal_value(void) // Now GotByte = "&"
|
|
|
|
{
|
|
|
|
intval_t value = 0;
|
2020-04-28 16:02:09 +00:00
|
|
|
int flags = NUMBER_IS_DEFINED,
|
2012-02-27 21:14:46 +00:00
|
|
|
digits = 0; // digit counter
|
|
|
|
|
|
|
|
GetByte();
|
|
|
|
while ((GotByte >= '0') && (GotByte <= '7')) {
|
|
|
|
value = (value << 3) + (GotByte & 7); // this works. it's ASCII.
|
2014-11-30 17:00:13 +00:00
|
|
|
++digits;
|
2012-02-27 21:14:46 +00:00
|
|
|
GetByte();
|
|
|
|
}
|
|
|
|
// set force bits
|
2020-04-14 00:28:31 +00:00
|
|
|
if (config.honor_leading_zeroes) {
|
2019-02-01 11:23:28 +00:00
|
|
|
if (digits > 3) {
|
|
|
|
if (digits > 6) {
|
|
|
|
if (value < 65536)
|
2020-04-28 16:02:09 +00:00
|
|
|
flags |= NUMBER_FORCES_24;
|
2019-02-01 11:23:28 +00:00
|
|
|
} else {
|
|
|
|
if (value < 256)
|
2020-04-28 16:02:09 +00:00
|
|
|
flags |= NUMBER_FORCES_16;
|
2019-02-01 11:23:28 +00:00
|
|
|
}
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
|
|
|
}
|
2014-06-02 00:47:46 +00:00
|
|
|
PUSH_INTOPERAND(value, flags, 0);
|
2012-02-27 21:14:46 +00:00
|
|
|
// Now GotByte = non-octal char
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Parse function call (sin(), cos(), arctan(), ...)
|
|
|
|
static void parse_function_call(void)
|
|
|
|
{
|
|
|
|
void *node_body;
|
|
|
|
|
|
|
|
// make lower case version of name in local dynamic buffer
|
|
|
|
DynaBuf_to_lower(function_dyna_buf, GlobalDynaBuf);
|
|
|
|
// search for tree item
|
2017-10-29 23:29:07 +00:00
|
|
|
if (Tree_easy_scan(function_tree, &node_body, function_dyna_buf)) {
|
2014-12-16 08:21:44 +00:00
|
|
|
PUSH_OPERATOR((struct operator *) node_body);
|
2017-10-29 23:29:07 +00:00
|
|
|
} else {
|
2012-02-27 21:14:46 +00:00
|
|
|
Throw_error("Unknown function.");
|
2017-10-29 23:29:07 +00:00
|
|
|
alu_state = STATE_ERROR;
|
|
|
|
}
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Expect operand or monadic operator (hopefully inlined)
|
2020-04-26 22:26:05 +00:00
|
|
|
// returns TRUE if it ate any non-space (-> so expression isn't empty)
|
|
|
|
// returns FALSE if first non-space is delimiter (-> end of expression)
|
|
|
|
static int expect_operand_or_monadic_operator(void)
|
2012-02-27 21:14:46 +00:00
|
|
|
{
|
2014-03-11 12:07:11 +00:00
|
|
|
struct operator *operator;
|
2015-06-14 23:16:23 +00:00
|
|
|
int ugly_length_kluge;
|
2020-05-01 21:01:23 +00:00
|
|
|
boolean perform_negation;
|
2012-02-27 21:14:46 +00:00
|
|
|
|
|
|
|
SKIPSPACE();
|
|
|
|
switch (GotByte) {
|
|
|
|
case '+': // anonymous forward label
|
|
|
|
// count plus signs to build name of anonymous label
|
|
|
|
DYNABUF_CLEAR(GlobalDynaBuf);
|
|
|
|
do
|
|
|
|
DYNABUF_APPEND(GlobalDynaBuf, '+');
|
|
|
|
while (GetByte() == '+');
|
2015-06-14 23:16:23 +00:00
|
|
|
ugly_length_kluge = GlobalDynaBuf->size; // FIXME - get rid of this!
|
2014-06-07 00:12:10 +00:00
|
|
|
symbol_fix_forward_anon_name(FALSE); // FALSE: do not increment counter
|
2017-10-29 23:29:07 +00:00
|
|
|
get_symbol_value(section_now->local_scope, 0, ugly_length_kluge);
|
2012-02-27 21:14:46 +00:00
|
|
|
goto now_expect_dyadic;
|
|
|
|
|
|
|
|
case '-': // NEGATION operator or anonymous backward label
|
|
|
|
// count minus signs in case it's an anonymous backward label
|
|
|
|
perform_negation = FALSE;
|
|
|
|
DYNABUF_CLEAR(GlobalDynaBuf);
|
|
|
|
do {
|
|
|
|
DYNABUF_APPEND(GlobalDynaBuf, '-');
|
|
|
|
perform_negation = !perform_negation;
|
|
|
|
} while (GetByte() == '-');
|
|
|
|
SKIPSPACE();
|
2020-04-28 11:18:22 +00:00
|
|
|
if (BYTE_FOLLOWS_ANON(GotByte)) {
|
2012-02-27 21:14:46 +00:00
|
|
|
DynaBuf_append(GlobalDynaBuf, '\0');
|
2017-10-29 23:29:07 +00:00
|
|
|
get_symbol_value(section_now->local_scope, 0, GlobalDynaBuf->size - 1); // -1 to not count terminator
|
2012-02-27 21:14:46 +00:00
|
|
|
goto now_expect_dyadic;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (perform_negation)
|
|
|
|
PUSH_OPERATOR(&ops_negate);
|
|
|
|
// State doesn't change
|
|
|
|
break;
|
|
|
|
// Real monadic operators (state doesn't change, still ExpectMonadic)
|
|
|
|
case '!': // NOT operator
|
|
|
|
operator = &ops_not;
|
|
|
|
goto get_byte_and_push_monadic;
|
|
|
|
|
|
|
|
case '<': // LOWBYTE operator
|
|
|
|
operator = &ops_lowbyteof;
|
|
|
|
goto get_byte_and_push_monadic;
|
|
|
|
|
|
|
|
case '>': // HIGHBYTE operator
|
|
|
|
operator = &ops_highbyteof;
|
|
|
|
goto get_byte_and_push_monadic;
|
|
|
|
|
|
|
|
case '^': // BANKBYTE operator
|
|
|
|
operator = &ops_bankbyteof;
|
|
|
|
goto get_byte_and_push_monadic;
|
|
|
|
|
|
|
|
// Faked monadic operators
|
|
|
|
case '(': // left parenthesis
|
|
|
|
operator = &ops_opening;
|
|
|
|
goto get_byte_and_push_monadic;
|
|
|
|
|
|
|
|
case ')': // right parenthesis
|
|
|
|
// this makes "()" also throw a syntax error
|
|
|
|
Throw_error(exception_syntax);
|
|
|
|
alu_state = STATE_ERROR;
|
|
|
|
break;
|
|
|
|
// Operands (values, state changes to ExpectDyadic)
|
|
|
|
case '"': // Quoted character
|
|
|
|
case '\'': // Quoted character
|
|
|
|
// Character will be converted using current encoding
|
|
|
|
parse_quoted_character(GotByte);
|
|
|
|
// Now GotByte = char following closing quote
|
|
|
|
goto now_expect_dyadic;
|
|
|
|
|
|
|
|
case '%': // Binary value
|
|
|
|
parse_binary_value(); // Now GotByte = non-binary char
|
|
|
|
goto now_expect_dyadic;
|
|
|
|
|
|
|
|
case '&': // Octal value
|
|
|
|
parse_octal_value(); // Now GotByte = non-octal char
|
|
|
|
goto now_expect_dyadic;
|
|
|
|
|
|
|
|
case '$': // Hexadecimal value
|
|
|
|
parse_hexadecimal_value();
|
|
|
|
// Now GotByte = non-hexadecimal char
|
|
|
|
goto now_expect_dyadic;
|
|
|
|
|
|
|
|
case '*': // Program counter
|
2014-03-11 12:07:11 +00:00
|
|
|
parse_program_counter();
|
2012-02-27 21:14:46 +00:00
|
|
|
// Now GotByte = char after closing quote
|
|
|
|
goto now_expect_dyadic;
|
|
|
|
|
2013-06-26 23:01:00 +00:00
|
|
|
// FIXME - find a way to tell decimal point and LOCAL_PREFIX apart!
|
2014-06-07 00:12:10 +00:00
|
|
|
case '.': // local symbol or fractional part of float value
|
2012-02-27 21:14:46 +00:00
|
|
|
GetByte(); // start after '.'
|
|
|
|
// check for fractional part of float value
|
|
|
|
if ((GotByte >= '0') && (GotByte <= '9')) {
|
|
|
|
parse_frac_part(0);
|
|
|
|
// Now GotByte = non-decimal char
|
|
|
|
goto now_expect_dyadic;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Input_read_keyword()) {
|
|
|
|
// Now GotByte = illegal char
|
2017-10-29 23:29:07 +00:00
|
|
|
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
|
2012-02-27 21:14:46 +00:00
|
|
|
goto now_expect_dyadic;
|
|
|
|
}
|
|
|
|
|
2017-10-29 23:29:07 +00:00
|
|
|
// if we're here, Input_read_keyword() will have thrown an error (like "no string given"):
|
2012-02-27 21:14:46 +00:00
|
|
|
alu_state = STATE_ERROR;
|
|
|
|
break;
|
2014-06-07 00:12:10 +00:00
|
|
|
// decimal values and global symbols
|
2012-02-27 21:14:46 +00:00
|
|
|
default: // all other characters
|
|
|
|
if ((GotByte >= '0') && (GotByte <= '9')) {
|
|
|
|
parse_decimal_value();
|
|
|
|
// Now GotByte = non-decimal char
|
|
|
|
goto now_expect_dyadic;
|
|
|
|
}
|
|
|
|
|
2020-04-28 11:18:22 +00:00
|
|
|
if (BYTE_STARTS_KEYWORD(GotByte)) {
|
2012-02-27 21:14:46 +00:00
|
|
|
register int length;
|
2016-02-21 23:08:02 +00:00
|
|
|
|
2012-02-27 21:14:46 +00:00
|
|
|
// Read global label (or "NOT")
|
|
|
|
length = Input_read_keyword();
|
|
|
|
// Now GotByte = illegal char
|
|
|
|
// Check for NOT. Okay, it's hardcoded,
|
|
|
|
// but so what? Sue me...
|
|
|
|
if ((length == 3)
|
|
|
|
&& ((GlobalDynaBuf->buffer[0] | 32) == 'n')
|
|
|
|
&& ((GlobalDynaBuf->buffer[1] | 32) == 'o')
|
|
|
|
&& ((GlobalDynaBuf->buffer[2] | 32) == 't')) {
|
|
|
|
PUSH_OPERATOR(&ops_not);
|
|
|
|
// state doesn't change
|
|
|
|
} else {
|
|
|
|
if (GotByte == '(') {
|
|
|
|
parse_function_call();
|
2014-12-16 08:21:44 +00:00
|
|
|
// i thought about making the parentheses optional, so you can write "a = sin b"
|
|
|
|
// just like "a = not b". but then each new function name would have to be made
|
|
|
|
// a reserved keyword, otherwise stuff like "a = sin * < b" would be ambiguous:
|
|
|
|
// it could mean either "compare sine of PC to b" or "multiply 'sin' by low byte
|
|
|
|
// of b".
|
|
|
|
// however, apart from that check above, function calls have nothing to do with
|
|
|
|
// parentheses: "sin(x+y)" gets parsed just like "not(x+y)".
|
2012-02-27 21:14:46 +00:00
|
|
|
} else {
|
2016-08-05 09:59:07 +00:00
|
|
|
get_symbol_value(SCOPE_GLOBAL, 0, GlobalDynaBuf->size - 1); // -1 to not count terminator
|
2012-02-27 21:14:46 +00:00
|
|
|
goto now_expect_dyadic;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// illegal character read - so don't go on
|
2017-10-21 19:59:56 +00:00
|
|
|
// we found end-of-expression instead of an operand,
|
|
|
|
// that's either an empty expression or an erroneous one!
|
2014-06-02 00:47:46 +00:00
|
|
|
PUSH_INTOPERAND(0, 0, 0); // push dummy operand so stack is ok
|
2017-10-21 19:59:56 +00:00
|
|
|
if (operator_stack[operator_sp - 1] == &ops_exprstart) {
|
|
|
|
PUSH_OPERATOR(&ops_exprend);
|
2012-02-27 21:14:46 +00:00
|
|
|
alu_state = STATE_TRY_TO_REDUCE_STACKS;
|
|
|
|
} else {
|
|
|
|
Throw_error(exception_syntax);
|
|
|
|
alu_state = STATE_ERROR;
|
|
|
|
}
|
2020-04-26 22:26:05 +00:00
|
|
|
return FALSE; // found delimiter
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
// no other possibilities, so here are the shared endings
|
|
|
|
|
|
|
|
get_byte_and_push_monadic:
|
|
|
|
GetByte();
|
|
|
|
PUSH_OPERATOR(operator);
|
|
|
|
// State doesn't change
|
|
|
|
break;
|
|
|
|
|
|
|
|
now_expect_dyadic:
|
2017-10-29 23:29:07 +00:00
|
|
|
// 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;
|
2012-02-27 21:14:46 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-04-26 22:26:05 +00:00
|
|
|
return TRUE; // parsed something
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Expect dyadic operator (hopefully inlined)
|
|
|
|
static void expect_dyadic_operator(void)
|
|
|
|
{
|
2014-03-11 12:07:11 +00:00
|
|
|
void *node_body;
|
|
|
|
struct operator *operator;
|
2012-02-27 21:14:46 +00:00
|
|
|
|
|
|
|
SKIPSPACE();
|
|
|
|
switch (GotByte) {
|
|
|
|
// Single-character dyadic operators
|
|
|
|
case '^': // "to the power of"
|
2014-03-11 12:07:11 +00:00
|
|
|
operator = &ops_powerof;
|
2012-02-27 21:14:46 +00:00
|
|
|
goto get_byte_and_push_dyadic;
|
|
|
|
|
|
|
|
case '+': // add
|
2014-03-11 12:07:11 +00:00
|
|
|
operator = &ops_add;
|
2012-02-27 21:14:46 +00:00
|
|
|
goto get_byte_and_push_dyadic;
|
|
|
|
|
|
|
|
case '-': // subtract
|
2014-03-11 12:07:11 +00:00
|
|
|
operator = &ops_subtract;
|
2012-02-27 21:14:46 +00:00
|
|
|
goto get_byte_and_push_dyadic;
|
|
|
|
|
|
|
|
case '*': // multiply
|
2014-03-11 12:07:11 +00:00
|
|
|
operator = &ops_multiply;
|
2012-02-27 21:14:46 +00:00
|
|
|
goto get_byte_and_push_dyadic;
|
|
|
|
|
|
|
|
case '/': // divide
|
2014-03-11 12:07:11 +00:00
|
|
|
operator = &ops_divide;
|
2012-02-27 21:14:46 +00:00
|
|
|
goto get_byte_and_push_dyadic;
|
|
|
|
|
|
|
|
case '%': // modulo
|
2014-03-11 12:07:11 +00:00
|
|
|
operator = &ops_modulo;
|
2012-02-27 21:14:46 +00:00
|
|
|
goto get_byte_and_push_dyadic;
|
|
|
|
|
|
|
|
case '&': // bitwise AND
|
2014-03-11 12:07:11 +00:00
|
|
|
operator = &ops_and;
|
2012-02-27 21:14:46 +00:00
|
|
|
goto get_byte_and_push_dyadic;
|
|
|
|
|
|
|
|
case '|': // bitwise OR
|
2014-03-11 12:07:11 +00:00
|
|
|
operator = &ops_or;
|
2012-02-27 21:14:46 +00:00
|
|
|
goto get_byte_and_push_dyadic;
|
|
|
|
|
|
|
|
// This part is commented out because there is no XOR character defined
|
|
|
|
// case ???: // bitwise exclusive OR
|
2014-03-11 12:07:11 +00:00
|
|
|
// operator = &ops_xor;
|
2012-02-27 21:14:46 +00:00
|
|
|
// goto get_byte_and_push_dyadic;
|
|
|
|
|
|
|
|
case '=': // is equal
|
2014-03-11 12:07:11 +00:00
|
|
|
operator = &ops_equals;
|
2014-05-06 22:16:41 +00:00
|
|
|
// if it's "==", accept but warn
|
|
|
|
if (GetByte() == '=') {
|
2014-05-31 00:46:55 +00:00
|
|
|
Throw_first_pass_warning("C-style \"==\" comparison detected.");
|
2014-05-06 22:16:41 +00:00
|
|
|
goto get_byte_and_push_dyadic;
|
|
|
|
}
|
|
|
|
goto push_dyadic;
|
2012-02-27 21:14:46 +00:00
|
|
|
|
|
|
|
case ')': // closing parenthesis
|
2014-03-11 12:07:11 +00:00
|
|
|
operator = &ops_closing;
|
2012-02-27 21:14:46 +00:00
|
|
|
goto get_byte_and_push_dyadic;
|
|
|
|
|
|
|
|
// Multi-character dyadic operators
|
|
|
|
case '!': // "!="
|
|
|
|
if (GetByte() == '=') {
|
2014-03-11 12:07:11 +00:00
|
|
|
operator = &ops_notequal;
|
2012-02-27 21:14:46 +00:00
|
|
|
goto get_byte_and_push_dyadic;
|
|
|
|
}
|
|
|
|
|
|
|
|
Throw_error(exception_syntax);
|
|
|
|
alu_state = STATE_ERROR;
|
|
|
|
break;
|
|
|
|
case '<': // "<", "<=", "<<" and "<>"
|
|
|
|
switch (GetByte()) {
|
|
|
|
case '=': // "<=", less or equal
|
2014-03-11 12:07:11 +00:00
|
|
|
operator = &ops_le;
|
2012-02-27 21:14:46 +00:00
|
|
|
goto get_byte_and_push_dyadic;
|
|
|
|
|
|
|
|
case '<': // "<<", shift left
|
2014-03-11 12:07:11 +00:00
|
|
|
operator = &ops_sl;
|
2012-02-27 21:14:46 +00:00
|
|
|
goto get_byte_and_push_dyadic;
|
|
|
|
|
|
|
|
case '>': // "<>", not equal
|
2014-03-11 12:07:11 +00:00
|
|
|
operator = &ops_notequal;
|
2012-02-27 21:14:46 +00:00
|
|
|
goto get_byte_and_push_dyadic;
|
|
|
|
|
|
|
|
default: // "<", less than
|
2014-03-11 12:07:11 +00:00
|
|
|
operator = &ops_lessthan;
|
2012-02-27 21:14:46 +00:00
|
|
|
goto push_dyadic;
|
|
|
|
|
|
|
|
}
|
|
|
|
//break; unreachable
|
|
|
|
case '>': // ">", ">=", ">>", ">>>" and "><"
|
|
|
|
switch (GetByte()) {
|
|
|
|
case '=': // ">=", greater or equal
|
2014-03-11 12:07:11 +00:00
|
|
|
operator = &ops_ge;
|
2012-02-27 21:14:46 +00:00
|
|
|
goto get_byte_and_push_dyadic;
|
|
|
|
|
|
|
|
case '<': // "><", not equal
|
2014-03-11 12:07:11 +00:00
|
|
|
operator = &ops_notequal;
|
2012-02-27 21:14:46 +00:00
|
|
|
goto get_byte_and_push_dyadic;
|
|
|
|
|
|
|
|
case '>': // ">>" or ">>>", shift right
|
2014-03-11 12:07:11 +00:00
|
|
|
operator = &ops_asr; // arithmetic shift right
|
2012-02-27 21:14:46 +00:00
|
|
|
if (GetByte() != '>')
|
|
|
|
goto push_dyadic;
|
|
|
|
|
2014-03-11 12:07:11 +00:00
|
|
|
operator = &ops_lsr; // logical shift right
|
2012-02-27 21:14:46 +00:00
|
|
|
goto get_byte_and_push_dyadic;
|
|
|
|
|
|
|
|
default: // ">", greater than
|
2014-03-11 12:07:11 +00:00
|
|
|
operator = &ops_greaterthan;
|
2012-02-27 21:14:46 +00:00
|
|
|
goto push_dyadic;
|
|
|
|
|
|
|
|
}
|
|
|
|
//break; unreachable
|
|
|
|
// end of expression or text version of dyadic operator
|
|
|
|
default:
|
2014-06-02 00:47:46 +00:00
|
|
|
// check string versions of operators
|
2020-04-28 11:18:22 +00:00
|
|
|
if (BYTE_STARTS_KEYWORD(GotByte)) {
|
2012-02-27 21:14:46 +00:00
|
|
|
Input_read_and_lower_keyword();
|
|
|
|
// Now GotByte = illegal char
|
|
|
|
// search for tree item
|
|
|
|
if (Tree_easy_scan(operator_tree, &node_body, GlobalDynaBuf)) {
|
2014-03-11 12:07:11 +00:00
|
|
|
operator = node_body;
|
2012-02-27 21:14:46 +00:00
|
|
|
goto push_dyadic;
|
|
|
|
}
|
|
|
|
|
|
|
|
// goto means we don't need an "else {" here
|
|
|
|
Throw_error("Unknown operator.");
|
|
|
|
alu_state = STATE_ERROR;
|
|
|
|
} else {
|
2017-10-21 19:59:56 +00:00
|
|
|
// we found end-of-expression when expecting an operator, that's ok.
|
|
|
|
operator = &ops_exprend;
|
2012-02-27 21:14:46 +00:00
|
|
|
goto push_dyadic;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
// shared endings
|
|
|
|
get_byte_and_push_dyadic:
|
|
|
|
GetByte();
|
|
|
|
push_dyadic:
|
2014-03-11 12:07:11 +00:00
|
|
|
PUSH_OPERATOR(operator);
|
2012-02-27 21:14:46 +00:00
|
|
|
alu_state = STATE_TRY_TO_REDUCE_STACKS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// call C's sin/cos/tan function
|
|
|
|
static void perform_fp(double (*fn)(double))
|
|
|
|
{
|
2020-04-28 16:02:09 +00:00
|
|
|
if ((RIGHT_FLAGS & NUMBER_IS_FLOAT) == 0) {
|
2012-02-27 21:14:46 +00:00
|
|
|
RIGHT_FPVAL = RIGHT_INTVAL;
|
2020-04-28 16:02:09 +00:00
|
|
|
RIGHT_FLAGS |= NUMBER_IS_FLOAT;
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
|
|
|
RIGHT_FPVAL = fn(RIGHT_FPVAL);
|
2014-06-02 00:47:46 +00:00
|
|
|
RIGHT_ADDRREFS = 0; // result now is a non-address
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// make sure arg is in [-1, 1] range before calling function
|
|
|
|
static void perform_ranged_fp(double (*fn)(double))
|
|
|
|
{
|
2020-04-28 16:02:09 +00:00
|
|
|
if ((RIGHT_FLAGS & NUMBER_IS_FLOAT) == 0) {
|
2012-02-27 21:14:46 +00:00
|
|
|
RIGHT_FPVAL = RIGHT_INTVAL;
|
2020-04-28 16:02:09 +00:00
|
|
|
RIGHT_FLAGS |= NUMBER_IS_FLOAT;
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
|
|
|
if ((RIGHT_FPVAL >= -1) && (RIGHT_FPVAL <= 1)) {
|
|
|
|
RIGHT_FPVAL = fn(RIGHT_FPVAL);
|
|
|
|
} else {
|
2020-04-28 16:02:09 +00:00
|
|
|
if (RIGHT_FLAGS & NUMBER_IS_DEFINED)
|
2012-02-27 21:14:46 +00:00
|
|
|
Throw_error("Argument out of range.");
|
|
|
|
RIGHT_FPVAL = 0;
|
|
|
|
}
|
2014-06-02 00:47:46 +00:00
|
|
|
RIGHT_ADDRREFS = 0; // result now is a non-address
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// convert right-hand value from fp to int
|
2014-11-22 01:36:02 +00:00
|
|
|
static void right_fp_to_int(void)
|
2012-02-27 21:14:46 +00:00
|
|
|
{
|
|
|
|
RIGHT_INTVAL = RIGHT_FPVAL;
|
2020-04-28 16:02:09 +00:00
|
|
|
RIGHT_FLAGS &= ~NUMBER_IS_FLOAT;
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// check both left-hand and right-hand values. if float, convert to int.
|
|
|
|
// in first pass, throw warning
|
|
|
|
static void both_ensure_int(int warn)
|
|
|
|
{
|
2020-04-28 16:02:09 +00:00
|
|
|
if (LEFT_FLAGS & NUMBER_IS_FLOAT) {
|
2012-02-27 21:14:46 +00:00
|
|
|
LEFT_INTVAL = LEFT_FPVAL;
|
2020-04-28 16:02:09 +00:00
|
|
|
LEFT_FLAGS &= ~NUMBER_IS_FLOAT;
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
2020-04-28 16:02:09 +00:00
|
|
|
if (RIGHT_FLAGS & NUMBER_IS_FLOAT) {
|
2012-02-27 21:14:46 +00:00
|
|
|
RIGHT_INTVAL = RIGHT_FPVAL;
|
2020-04-28 16:02:09 +00:00
|
|
|
RIGHT_FLAGS &= ~NUMBER_IS_FLOAT;
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
2014-06-02 00:47:46 +00:00
|
|
|
// FIXME - warning is never seen if both operands are undefined in first pass!
|
2012-02-27 21:14:46 +00:00
|
|
|
Throw_first_pass_warning("Converted to integer for binary logic operator.");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// check both left-hand and right-hand values. if int, convert to float.
|
|
|
|
static void both_ensure_fp(void)
|
|
|
|
{
|
2020-04-28 16:02:09 +00:00
|
|
|
if ((LEFT_FLAGS & NUMBER_IS_FLOAT) == 0) {
|
2012-02-27 21:14:46 +00:00
|
|
|
LEFT_FPVAL = LEFT_INTVAL;
|
2020-04-28 16:02:09 +00:00
|
|
|
LEFT_FLAGS |= NUMBER_IS_FLOAT;
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
2020-04-28 16:02:09 +00:00
|
|
|
if ((RIGHT_FLAGS & NUMBER_IS_FLOAT) == 0) {
|
2012-02-27 21:14:46 +00:00
|
|
|
RIGHT_FPVAL = RIGHT_INTVAL;
|
2020-04-28 16:02:09 +00:00
|
|
|
RIGHT_FLAGS |= NUMBER_IS_FLOAT;
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// make sure both values are float, but mark left one as int (will become one)
|
|
|
|
static void ensure_int_from_fp(void)
|
|
|
|
{
|
|
|
|
both_ensure_fp();
|
2020-04-28 16:02:09 +00:00
|
|
|
LEFT_FLAGS &= ~NUMBER_IS_FLOAT;
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Try to reduce stacks by performing high-priority operations
|
2017-10-21 19:59:56 +00:00
|
|
|
// (if the previous operator has a higher priority than the current one, do it)
|
2020-04-26 20:14:39 +00:00
|
|
|
static void try_to_reduce_stacks(struct expression *expression)
|
2012-02-27 21:14:46 +00:00
|
|
|
{
|
|
|
|
if (operator_sp < 2) {
|
|
|
|
alu_state = STATE_EXPECT_OPERAND_OR_MONADIC_OPERATOR;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-01-16 18:16:24 +00:00
|
|
|
// previous operator has lower piority than current one? then do nothing.
|
|
|
|
if (operator_stack[operator_sp - 2]->priority_and_associativity < operator_stack[operator_sp - 1]->priority_and_associativity) {
|
|
|
|
alu_state = STATE_EXPECT_OPERAND_OR_MONADIC_OPERATOR;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// previous operator has same priority as current one? then check associativity
|
|
|
|
if ((operator_stack[operator_sp - 2]->priority_and_associativity == operator_stack[operator_sp - 1]->priority_and_associativity)
|
|
|
|
&& IS_RIGHT_ASSOCIATIVE(operator_stack[operator_sp - 1]->priority_and_associativity)) {
|
2012-02-27 21:14:46 +00:00
|
|
|
alu_state = STATE_EXPECT_OPERAND_OR_MONADIC_OPERATOR;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-10-21 19:59:56 +00:00
|
|
|
// process previous operator
|
2012-02-27 21:14:46 +00:00
|
|
|
switch (operator_stack[operator_sp - 2]->handle) {
|
|
|
|
// special (pseudo) operators
|
2017-10-21 19:59:56 +00:00
|
|
|
case OPHANDLE_EXPRSTART:
|
|
|
|
// the only operator with a lower priority than this
|
|
|
|
// "start-of-expression" operator is "end-of-expression",
|
|
|
|
// therefore we know we are done.
|
2020-04-26 20:14:39 +00:00
|
|
|
// don't touch "is_parenthesized", because start/end are obviously not "real" operators
|
2014-11-30 17:00:13 +00:00
|
|
|
--operator_sp; // decrement operator stack pointer
|
2012-02-27 21:14:46 +00:00
|
|
|
alu_state = STATE_END;
|
2020-04-26 20:14:39 +00:00
|
|
|
break; // FIXME - why not return?
|
2012-02-27 21:14:46 +00:00
|
|
|
case OPHANDLE_OPENING:
|
2020-04-26 20:14:39 +00:00
|
|
|
expression->is_parenthesized = TRUE; // found parentheses. if this is not the outermost level, the outermost level will fix this.
|
2012-02-27 21:14:46 +00:00
|
|
|
switch (operator_stack[operator_sp - 1]->handle) {
|
|
|
|
case OPHANDLE_CLOSING: // matching parentheses
|
|
|
|
operator_sp -= 2; // remove both of them
|
|
|
|
alu_state = STATE_EXPECT_DYADIC_OPERATOR;
|
|
|
|
break;
|
2017-10-21 19:59:56 +00:00
|
|
|
case OPHANDLE_EXPREND: // unmatched parenthesis
|
2020-04-26 20:14:39 +00:00
|
|
|
++(expression->open_parentheses); // count
|
2012-02-27 21:14:46 +00:00
|
|
|
goto RNTLObutDontTouchIndirectFlag;
|
|
|
|
|
|
|
|
default:
|
|
|
|
Bug_found("StrangeParenthesis", operator_stack[operator_sp - 1]->handle);
|
|
|
|
}
|
2020-04-26 20:14:39 +00:00
|
|
|
break; // FIXME - why not return?
|
2012-02-27 21:14:46 +00:00
|
|
|
case OPHANDLE_CLOSING:
|
|
|
|
Throw_error("Too many ')'.");
|
2017-10-29 23:29:07 +00:00
|
|
|
alu_state = STATE_ERROR;
|
2020-04-26 20:14:39 +00:00
|
|
|
return; // FIXME - why not break?
|
2012-02-27 21:14:46 +00:00
|
|
|
|
|
|
|
// functions
|
2014-06-02 00:47:46 +00:00
|
|
|
case OPHANDLE_ADDR:
|
|
|
|
RIGHT_ADDRREFS = 1; // result now is an address
|
|
|
|
goto remove_next_to_last_operator;
|
|
|
|
|
2012-02-27 21:14:46 +00:00
|
|
|
case OPHANDLE_INT:
|
2020-04-28 16:02:09 +00:00
|
|
|
if (RIGHT_FLAGS & NUMBER_IS_FLOAT)
|
2012-02-27 21:14:46 +00:00
|
|
|
right_fp_to_int();
|
2014-06-02 00:47:46 +00:00
|
|
|
RIGHT_ADDRREFS = 0; // result now is a non-address
|
2012-02-27 21:14:46 +00:00
|
|
|
goto remove_next_to_last_operator;
|
|
|
|
|
|
|
|
case OPHANDLE_FLOAT:
|
|
|
|
// convert right-hand value from int to fp
|
2020-04-28 16:02:09 +00:00
|
|
|
if ((RIGHT_FLAGS & NUMBER_IS_FLOAT) == 0) {
|
2012-02-27 21:14:46 +00:00
|
|
|
RIGHT_FPVAL = RIGHT_INTVAL;
|
2020-04-28 16:02:09 +00:00
|
|
|
RIGHT_FLAGS |= NUMBER_IS_FLOAT;
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
2014-06-02 00:47:46 +00:00
|
|
|
RIGHT_ADDRREFS = 0; // result now is a non-address
|
2012-02-27 21:14:46 +00:00
|
|
|
goto remove_next_to_last_operator;
|
|
|
|
|
|
|
|
case OPHANDLE_SIN:
|
2014-06-02 00:47:46 +00:00
|
|
|
perform_fp(sin); // also zeroes addr_refs
|
2012-02-27 21:14:46 +00:00
|
|
|
goto remove_next_to_last_operator;
|
|
|
|
|
|
|
|
case OPHANDLE_COS:
|
2014-06-02 00:47:46 +00:00
|
|
|
perform_fp(cos); // also zeroes addr_refs
|
2012-02-27 21:14:46 +00:00
|
|
|
goto remove_next_to_last_operator;
|
|
|
|
|
|
|
|
case OPHANDLE_TAN:
|
2014-06-02 00:47:46 +00:00
|
|
|
perform_fp(tan); // also zeroes addr_refs
|
2012-02-27 21:14:46 +00:00
|
|
|
goto remove_next_to_last_operator;
|
|
|
|
|
|
|
|
case OPHANDLE_ARCSIN:
|
2014-06-02 00:47:46 +00:00
|
|
|
perform_ranged_fp(asin); // also zeroes addr_refs
|
2012-02-27 21:14:46 +00:00
|
|
|
goto remove_next_to_last_operator;
|
|
|
|
|
|
|
|
case OPHANDLE_ARCCOS:
|
2014-06-02 00:47:46 +00:00
|
|
|
perform_ranged_fp(acos); // also zeroes addr_refs
|
2012-02-27 21:14:46 +00:00
|
|
|
goto remove_next_to_last_operator;
|
|
|
|
|
|
|
|
case OPHANDLE_ARCTAN:
|
2014-06-02 00:47:46 +00:00
|
|
|
perform_fp(atan); // also zeroes addr_refs
|
2012-02-27 21:14:46 +00:00
|
|
|
goto remove_next_to_last_operator;
|
|
|
|
|
|
|
|
// monadic operators
|
|
|
|
case OPHANDLE_NOT:
|
2013-06-26 23:01:00 +00:00
|
|
|
// fp becomes int
|
2020-04-28 16:02:09 +00:00
|
|
|
if (RIGHT_FLAGS & NUMBER_IS_FLOAT)
|
2012-02-27 21:14:46 +00:00
|
|
|
right_fp_to_int();
|
|
|
|
RIGHT_INTVAL = ~(RIGHT_INTVAL);
|
2020-04-28 16:02:09 +00:00
|
|
|
RIGHT_FLAGS &= ~NUMBER_FITS_BYTE;
|
2012-02-27 21:14:46 +00:00
|
|
|
goto remove_next_to_last_operator;
|
|
|
|
|
|
|
|
case OPHANDLE_NEGATE:
|
|
|
|
// different operations for fp and int
|
2020-04-28 16:02:09 +00:00
|
|
|
if (RIGHT_FLAGS & NUMBER_IS_FLOAT)
|
2012-02-27 21:14:46 +00:00
|
|
|
RIGHT_FPVAL = -(RIGHT_FPVAL);
|
|
|
|
else
|
|
|
|
RIGHT_INTVAL = -(RIGHT_INTVAL);
|
2020-04-28 16:02:09 +00:00
|
|
|
RIGHT_FLAGS &= ~NUMBER_FITS_BYTE;
|
2014-06-07 00:12:10 +00:00
|
|
|
RIGHT_ADDRREFS = -RIGHT_ADDRREFS; // negate address ref count as well
|
2012-02-27 21:14:46 +00:00
|
|
|
goto remove_next_to_last_operator;
|
|
|
|
|
|
|
|
case OPHANDLE_LOWBYTEOF:
|
|
|
|
// fp becomes int
|
2020-04-28 16:02:09 +00:00
|
|
|
if (RIGHT_FLAGS & NUMBER_IS_FLOAT)
|
2012-02-27 21:14:46 +00:00
|
|
|
right_fp_to_int();
|
|
|
|
RIGHT_INTVAL = (RIGHT_INTVAL) & 255;
|
2020-04-28 16:02:09 +00:00
|
|
|
RIGHT_FLAGS |= NUMBER_FITS_BYTE;
|
|
|
|
RIGHT_FLAGS &= ~NUMBER_FORCEBITS;
|
2014-06-02 00:47:46 +00:00
|
|
|
RIGHT_ADDRREFS = 0; // result now is a non-address
|
2012-02-27 21:14:46 +00:00
|
|
|
goto remove_next_to_last_operator;
|
|
|
|
|
|
|
|
case OPHANDLE_HIGHBYTEOF:
|
|
|
|
// fp becomes int
|
2020-04-28 16:02:09 +00:00
|
|
|
if (RIGHT_FLAGS & NUMBER_IS_FLOAT)
|
2012-02-27 21:14:46 +00:00
|
|
|
right_fp_to_int();
|
|
|
|
RIGHT_INTVAL = ((RIGHT_INTVAL) >> 8) & 255;
|
2020-04-28 16:02:09 +00:00
|
|
|
RIGHT_FLAGS |= NUMBER_FITS_BYTE;
|
|
|
|
RIGHT_FLAGS &= ~NUMBER_FORCEBITS;
|
2014-06-02 00:47:46 +00:00
|
|
|
RIGHT_ADDRREFS = 0; // result now is a non-address
|
2012-02-27 21:14:46 +00:00
|
|
|
goto remove_next_to_last_operator;
|
|
|
|
|
|
|
|
case OPHANDLE_BANKBYTEOF:
|
|
|
|
// fp becomes int
|
2020-04-28 16:02:09 +00:00
|
|
|
if (RIGHT_FLAGS & NUMBER_IS_FLOAT)
|
2012-02-27 21:14:46 +00:00
|
|
|
right_fp_to_int();
|
|
|
|
RIGHT_INTVAL = ((RIGHT_INTVAL) >> 16) & 255;
|
2020-04-28 16:02:09 +00:00
|
|
|
RIGHT_FLAGS |= NUMBER_FITS_BYTE;
|
|
|
|
RIGHT_FLAGS &= ~NUMBER_FORCEBITS;
|
2014-06-02 00:47:46 +00:00
|
|
|
RIGHT_ADDRREFS = 0; // result now is a non-address
|
2012-02-27 21:14:46 +00:00
|
|
|
goto remove_next_to_last_operator;
|
|
|
|
|
|
|
|
// dyadic operators
|
|
|
|
case OPHANDLE_POWEROF:
|
2020-04-28 16:02:09 +00:00
|
|
|
if ((RIGHT_FLAGS | LEFT_FLAGS) & NUMBER_IS_FLOAT) {
|
2012-02-27 21:14:46 +00:00
|
|
|
both_ensure_fp();
|
|
|
|
LEFT_FPVAL = pow(LEFT_FPVAL, RIGHT_FPVAL);
|
2014-06-02 00:47:46 +00:00
|
|
|
LEFT_ADDRREFS = 0; // result now is a non-address
|
2012-02-27 21:14:46 +00:00
|
|
|
goto handle_flags_and_dec_stacks;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (RIGHT_INTVAL >= 0) {
|
|
|
|
LEFT_INTVAL = my_pow(LEFT_INTVAL, RIGHT_INTVAL);
|
|
|
|
} else {
|
2020-04-28 16:02:09 +00:00
|
|
|
if (RIGHT_FLAGS & NUMBER_IS_DEFINED)
|
2012-02-27 21:14:46 +00:00
|
|
|
Throw_error("Exponent is negative.");
|
|
|
|
LEFT_INTVAL = 0;
|
|
|
|
}
|
2014-06-02 00:47:46 +00:00
|
|
|
LEFT_ADDRREFS = 0; // result now is a non-address
|
2012-02-27 21:14:46 +00:00
|
|
|
goto handle_flags_and_dec_stacks;
|
|
|
|
|
|
|
|
case OPHANDLE_MULTIPLY:
|
2020-04-28 16:02:09 +00:00
|
|
|
if ((RIGHT_FLAGS | LEFT_FLAGS) & NUMBER_IS_FLOAT) {
|
2012-02-27 21:14:46 +00:00
|
|
|
both_ensure_fp();
|
|
|
|
LEFT_FPVAL *= RIGHT_FPVAL;
|
|
|
|
} else {
|
|
|
|
LEFT_INTVAL *= RIGHT_INTVAL;
|
|
|
|
}
|
2014-06-02 00:47:46 +00:00
|
|
|
LEFT_ADDRREFS = 0; // result now is a non-address
|
2012-02-27 21:14:46 +00:00
|
|
|
goto handle_flags_and_dec_stacks;
|
|
|
|
|
|
|
|
case OPHANDLE_DIVIDE:
|
2020-04-28 16:02:09 +00:00
|
|
|
if ((RIGHT_FLAGS | LEFT_FLAGS) & NUMBER_IS_FLOAT) {
|
2012-02-27 21:14:46 +00:00
|
|
|
both_ensure_fp();
|
|
|
|
if (RIGHT_FPVAL) {
|
|
|
|
LEFT_FPVAL /= RIGHT_FPVAL;
|
|
|
|
} else {
|
2020-04-28 16:02:09 +00:00
|
|
|
if (RIGHT_FLAGS & NUMBER_IS_DEFINED)
|
2012-02-27 21:14:46 +00:00
|
|
|
Throw_error(exception_div_by_zero);
|
|
|
|
LEFT_FPVAL = 0;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (RIGHT_INTVAL) {
|
|
|
|
LEFT_INTVAL /= RIGHT_INTVAL;
|
|
|
|
} else {
|
2020-04-28 16:02:09 +00:00
|
|
|
if (RIGHT_FLAGS & NUMBER_IS_DEFINED)
|
2012-02-27 21:14:46 +00:00
|
|
|
Throw_error(exception_div_by_zero);
|
|
|
|
LEFT_INTVAL = 0;
|
|
|
|
}
|
|
|
|
}
|
2014-06-02 00:47:46 +00:00
|
|
|
LEFT_ADDRREFS = 0; // result now is a non-address
|
2012-02-27 21:14:46 +00:00
|
|
|
goto handle_flags_and_dec_stacks;
|
|
|
|
|
|
|
|
case OPHANDLE_INTDIV:
|
2020-04-28 16:02:09 +00:00
|
|
|
if ((RIGHT_FLAGS | LEFT_FLAGS) & NUMBER_IS_FLOAT) {
|
2012-02-27 21:14:46 +00:00
|
|
|
both_ensure_fp();
|
|
|
|
if (RIGHT_FPVAL) {
|
|
|
|
LEFT_INTVAL = LEFT_FPVAL / RIGHT_FPVAL;
|
|
|
|
} else {
|
2020-04-28 16:02:09 +00:00
|
|
|
if (RIGHT_FLAGS & NUMBER_IS_DEFINED)
|
2012-02-27 21:14:46 +00:00
|
|
|
Throw_error(exception_div_by_zero);
|
|
|
|
LEFT_INTVAL = 0;
|
|
|
|
}
|
2020-04-28 16:02:09 +00:00
|
|
|
LEFT_FLAGS &= ~NUMBER_IS_FLOAT;
|
2012-02-27 21:14:46 +00:00
|
|
|
} else {
|
|
|
|
if (RIGHT_INTVAL) {
|
|
|
|
LEFT_INTVAL /= RIGHT_INTVAL;
|
|
|
|
} else {
|
2020-04-28 16:02:09 +00:00
|
|
|
if (RIGHT_FLAGS & NUMBER_IS_DEFINED)
|
2012-02-27 21:14:46 +00:00
|
|
|
Throw_error(exception_div_by_zero);
|
|
|
|
LEFT_INTVAL = 0;
|
|
|
|
}
|
|
|
|
}
|
2014-06-02 00:47:46 +00:00
|
|
|
LEFT_ADDRREFS = 0; // result now is a non-address
|
2012-02-27 21:14:46 +00:00
|
|
|
goto handle_flags_and_dec_stacks;
|
|
|
|
|
|
|
|
case OPHANDLE_MODULO:
|
2020-04-28 16:02:09 +00:00
|
|
|
if ((RIGHT_FLAGS | LEFT_FLAGS) & NUMBER_IS_FLOAT)
|
2012-02-27 21:14:46 +00:00
|
|
|
both_ensure_int(FALSE);
|
|
|
|
if (RIGHT_INTVAL) {
|
|
|
|
LEFT_INTVAL %= RIGHT_INTVAL;
|
|
|
|
} else {
|
2020-04-28 16:02:09 +00:00
|
|
|
if (RIGHT_FLAGS & NUMBER_IS_DEFINED)
|
2012-02-27 21:14:46 +00:00
|
|
|
Throw_error(exception_div_by_zero);
|
|
|
|
LEFT_INTVAL = 0;
|
|
|
|
}
|
2014-06-02 00:47:46 +00:00
|
|
|
LEFT_ADDRREFS = 0; // result now is a non-address
|
2012-02-27 21:14:46 +00:00
|
|
|
goto handle_flags_and_dec_stacks;
|
|
|
|
|
|
|
|
case OPHANDLE_ADD:
|
2020-04-28 16:02:09 +00:00
|
|
|
if ((RIGHT_FLAGS | LEFT_FLAGS) & NUMBER_IS_FLOAT) {
|
2012-02-27 21:14:46 +00:00
|
|
|
both_ensure_fp();
|
|
|
|
LEFT_FPVAL += RIGHT_FPVAL;
|
|
|
|
} else {
|
|
|
|
LEFT_INTVAL += RIGHT_INTVAL;
|
|
|
|
}
|
2014-06-02 00:47:46 +00:00
|
|
|
LEFT_ADDRREFS += RIGHT_ADDRREFS; // add address references
|
2012-02-27 21:14:46 +00:00
|
|
|
goto handle_flags_and_dec_stacks;
|
|
|
|
|
|
|
|
case OPHANDLE_SUBTRACT:
|
2020-04-28 16:02:09 +00:00
|
|
|
if ((RIGHT_FLAGS | LEFT_FLAGS) & NUMBER_IS_FLOAT) {
|
2012-02-27 21:14:46 +00:00
|
|
|
both_ensure_fp();
|
|
|
|
LEFT_FPVAL -= RIGHT_FPVAL;
|
|
|
|
} else {
|
|
|
|
LEFT_INTVAL -= RIGHT_INTVAL;
|
|
|
|
}
|
2014-06-02 00:47:46 +00:00
|
|
|
LEFT_ADDRREFS -= RIGHT_ADDRREFS; // subtract address references
|
2012-02-27 21:14:46 +00:00
|
|
|
goto handle_flags_and_dec_stacks;
|
|
|
|
|
|
|
|
case OPHANDLE_SL:
|
2020-04-28 16:02:09 +00:00
|
|
|
if (RIGHT_FLAGS & NUMBER_IS_FLOAT)
|
2012-02-27 21:14:46 +00:00
|
|
|
right_fp_to_int();
|
2020-04-28 16:02:09 +00:00
|
|
|
if (LEFT_FLAGS & NUMBER_IS_FLOAT)
|
2013-06-26 23:01:00 +00:00
|
|
|
LEFT_FPVAL *= pow(2.0, RIGHT_INTVAL);
|
2012-02-27 21:14:46 +00:00
|
|
|
else
|
|
|
|
LEFT_INTVAL <<= RIGHT_INTVAL;
|
2014-06-02 00:47:46 +00:00
|
|
|
LEFT_ADDRREFS = 0; // result now is a non-address
|
2012-02-27 21:14:46 +00:00
|
|
|
goto handle_flags_and_dec_stacks;
|
|
|
|
|
|
|
|
case OPHANDLE_ASR:
|
2020-04-28 16:02:09 +00:00
|
|
|
if (RIGHT_FLAGS & NUMBER_IS_FLOAT)
|
2012-02-27 21:14:46 +00:00
|
|
|
right_fp_to_int();
|
2020-04-28 16:02:09 +00:00
|
|
|
if (LEFT_FLAGS & NUMBER_IS_FLOAT)
|
2012-02-27 21:14:46 +00:00
|
|
|
LEFT_FPVAL /= (1 << RIGHT_INTVAL);
|
|
|
|
else
|
|
|
|
LEFT_INTVAL = my_asr(LEFT_INTVAL, RIGHT_INTVAL);
|
2014-06-02 00:47:46 +00:00
|
|
|
LEFT_ADDRREFS = 0; // result now is a non-address
|
2012-02-27 21:14:46 +00:00
|
|
|
goto handle_flags_and_dec_stacks;
|
|
|
|
|
|
|
|
case OPHANDLE_LSR:
|
2013-06-26 23:01:00 +00:00
|
|
|
// fp become int
|
2020-04-28 16:02:09 +00:00
|
|
|
if ((RIGHT_FLAGS | LEFT_FLAGS) & NUMBER_IS_FLOAT)
|
2012-02-27 21:14:46 +00:00
|
|
|
both_ensure_int(TRUE);
|
|
|
|
LEFT_INTVAL = ((uintval_t) LEFT_INTVAL) >> RIGHT_INTVAL;
|
2014-06-02 00:47:46 +00:00
|
|
|
LEFT_ADDRREFS = 0; // result now is a non-address
|
2012-02-27 21:14:46 +00:00
|
|
|
goto handle_flags_and_dec_stacks;
|
|
|
|
|
|
|
|
case OPHANDLE_LE:
|
2020-04-28 16:02:09 +00:00
|
|
|
if ((RIGHT_FLAGS | LEFT_FLAGS) & NUMBER_IS_FLOAT) {
|
2012-02-27 21:14:46 +00:00
|
|
|
ensure_int_from_fp();
|
|
|
|
LEFT_INTVAL = (LEFT_FPVAL <= RIGHT_FPVAL);
|
|
|
|
} else {
|
|
|
|
LEFT_INTVAL = (LEFT_INTVAL <= RIGHT_INTVAL);
|
|
|
|
}
|
2014-06-02 00:47:46 +00:00
|
|
|
LEFT_ADDRREFS = 0; // result now is a non-address
|
2012-02-27 21:14:46 +00:00
|
|
|
goto handle_flags_and_dec_stacks;
|
|
|
|
|
|
|
|
case OPHANDLE_LESSTHAN:
|
2020-04-28 16:02:09 +00:00
|
|
|
if ((RIGHT_FLAGS | LEFT_FLAGS) & NUMBER_IS_FLOAT) {
|
2012-02-27 21:14:46 +00:00
|
|
|
ensure_int_from_fp();
|
|
|
|
LEFT_INTVAL = (LEFT_FPVAL < RIGHT_FPVAL);
|
|
|
|
} else {
|
|
|
|
LEFT_INTVAL = (LEFT_INTVAL < RIGHT_INTVAL);
|
|
|
|
}
|
2014-06-02 00:47:46 +00:00
|
|
|
LEFT_ADDRREFS = 0; // result now is a non-address
|
2012-02-27 21:14:46 +00:00
|
|
|
goto handle_flags_and_dec_stacks;
|
|
|
|
|
|
|
|
case OPHANDLE_GE:
|
2020-04-28 16:02:09 +00:00
|
|
|
if ((RIGHT_FLAGS | LEFT_FLAGS) & NUMBER_IS_FLOAT) {
|
2012-02-27 21:14:46 +00:00
|
|
|
ensure_int_from_fp();
|
|
|
|
LEFT_INTVAL = (LEFT_FPVAL >= RIGHT_FPVAL);
|
|
|
|
} else {
|
|
|
|
LEFT_INTVAL = (LEFT_INTVAL >= RIGHT_INTVAL);
|
|
|
|
}
|
2014-06-02 00:47:46 +00:00
|
|
|
LEFT_ADDRREFS = 0; // result now is a non-address
|
2012-02-27 21:14:46 +00:00
|
|
|
goto handle_flags_and_dec_stacks;
|
|
|
|
|
|
|
|
case OPHANDLE_GREATERTHAN:
|
2020-04-28 16:02:09 +00:00
|
|
|
if ((RIGHT_FLAGS | LEFT_FLAGS) & NUMBER_IS_FLOAT) {
|
2012-02-27 21:14:46 +00:00
|
|
|
ensure_int_from_fp();
|
|
|
|
LEFT_INTVAL = (LEFT_FPVAL > RIGHT_FPVAL);
|
|
|
|
} else {
|
|
|
|
LEFT_INTVAL = (LEFT_INTVAL > RIGHT_INTVAL);
|
|
|
|
}
|
2014-06-02 00:47:46 +00:00
|
|
|
LEFT_ADDRREFS = 0; // result now is a non-address
|
2012-02-27 21:14:46 +00:00
|
|
|
goto handle_flags_and_dec_stacks;
|
|
|
|
|
|
|
|
case OPHANDLE_NOTEQUAL:
|
2020-04-28 16:02:09 +00:00
|
|
|
if ((RIGHT_FLAGS | LEFT_FLAGS) & NUMBER_IS_FLOAT) {
|
2012-02-27 21:14:46 +00:00
|
|
|
ensure_int_from_fp();
|
|
|
|
LEFT_INTVAL = (LEFT_FPVAL != RIGHT_FPVAL);
|
|
|
|
} else {
|
|
|
|
LEFT_INTVAL = (LEFT_INTVAL != RIGHT_INTVAL);
|
|
|
|
}
|
2014-06-02 00:47:46 +00:00
|
|
|
LEFT_ADDRREFS = 0; // result now is a non-address
|
2012-02-27 21:14:46 +00:00
|
|
|
goto handle_flags_and_dec_stacks;
|
|
|
|
|
|
|
|
case OPHANDLE_EQUALS:
|
2020-04-28 16:02:09 +00:00
|
|
|
if ((RIGHT_FLAGS | LEFT_FLAGS) & NUMBER_IS_FLOAT) {
|
2012-02-27 21:14:46 +00:00
|
|
|
ensure_int_from_fp();
|
|
|
|
LEFT_INTVAL = (LEFT_FPVAL == RIGHT_FPVAL);
|
|
|
|
} else {
|
|
|
|
LEFT_INTVAL = (LEFT_INTVAL == RIGHT_INTVAL);
|
|
|
|
}
|
2014-06-02 00:47:46 +00:00
|
|
|
LEFT_ADDRREFS = 0; // result now is a non-address
|
2012-02-27 21:14:46 +00:00
|
|
|
goto handle_flags_and_dec_stacks;
|
|
|
|
|
|
|
|
case OPHANDLE_AND:
|
2013-06-26 23:01:00 +00:00
|
|
|
// fp become int
|
2020-04-28 16:02:09 +00:00
|
|
|
if ((RIGHT_FLAGS | LEFT_FLAGS) & NUMBER_IS_FLOAT)
|
2012-02-27 21:14:46 +00:00
|
|
|
both_ensure_int(TRUE);
|
|
|
|
LEFT_INTVAL &= RIGHT_INTVAL;
|
2014-06-02 00:47:46 +00:00
|
|
|
LEFT_ADDRREFS += RIGHT_ADDRREFS; // add address references
|
2012-02-27 21:14:46 +00:00
|
|
|
goto handle_flags_and_dec_stacks;
|
|
|
|
|
|
|
|
case OPHANDLE_EOR:
|
|
|
|
Throw_first_pass_warning("\"EOR\" is deprecated; use \"XOR\" instead.");
|
|
|
|
/*FALLTHROUGH*/
|
|
|
|
case OPHANDLE_XOR:
|
2013-06-26 23:01:00 +00:00
|
|
|
// fp become int
|
2020-04-28 16:02:09 +00:00
|
|
|
if ((RIGHT_FLAGS | LEFT_FLAGS) & NUMBER_IS_FLOAT)
|
2012-02-27 21:14:46 +00:00
|
|
|
both_ensure_int(TRUE);
|
|
|
|
LEFT_INTVAL ^= RIGHT_INTVAL;
|
2014-06-02 00:47:46 +00:00
|
|
|
LEFT_ADDRREFS += RIGHT_ADDRREFS; // add address references
|
2012-02-27 21:14:46 +00:00
|
|
|
goto handle_flags_and_dec_stacks;
|
|
|
|
|
|
|
|
case OPHANDLE_OR:
|
2013-06-26 23:01:00 +00:00
|
|
|
// fp become int
|
2020-04-28 16:02:09 +00:00
|
|
|
if ((RIGHT_FLAGS | LEFT_FLAGS) & NUMBER_IS_FLOAT)
|
2012-02-27 21:14:46 +00:00
|
|
|
both_ensure_int(TRUE);
|
|
|
|
LEFT_INTVAL |= RIGHT_INTVAL;
|
2014-06-02 00:47:46 +00:00
|
|
|
LEFT_ADDRREFS += RIGHT_ADDRREFS; // add address references
|
2012-02-27 21:14:46 +00:00
|
|
|
goto handle_flags_and_dec_stacks;
|
|
|
|
|
|
|
|
default:
|
|
|
|
Bug_found("IllegalOperatorHandle", operator_stack[operator_sp - 2]->handle);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
|
|
// shared endings:
|
|
|
|
|
|
|
|
// entry point for dyadic operators
|
|
|
|
handle_flags_and_dec_stacks:
|
|
|
|
// Handle flags and decrement value stack pointer
|
2020-04-28 16:02:09 +00:00
|
|
|
// "OR" EVER_UNDEFINED and FORCEBIT flags
|
|
|
|
LEFT_FLAGS |= RIGHT_FLAGS & (NUMBER_EVER_UNDEFINED | NUMBER_FORCEBITS);
|
2012-02-27 21:14:46 +00:00
|
|
|
// "AND" DEFINED flag
|
2020-04-28 16:02:09 +00:00
|
|
|
LEFT_FLAGS &= (RIGHT_FLAGS | ~NUMBER_IS_DEFINED);
|
|
|
|
LEFT_FLAGS &= ~NUMBER_FITS_BYTE; // clear FITS BYTE flag
|
2014-11-30 17:00:13 +00:00
|
|
|
--operand_sp;
|
2012-02-27 21:14:46 +00:00
|
|
|
// entry point for monadic operators
|
|
|
|
remove_next_to_last_operator:
|
2020-04-26 20:14:39 +00:00
|
|
|
// operation was something other than parentheses
|
|
|
|
expression->is_parenthesized = FALSE;
|
|
|
|
// entry point for when '(' operator meets "end of expression": keep is_parenthesized set!
|
2012-02-27 21:14:46 +00:00
|
|
|
RNTLObutDontTouchIndirectFlag:
|
|
|
|
// Remove operator and shift down next one
|
2016-02-21 23:08:02 +00:00
|
|
|
operator_stack[operator_sp - 2] = operator_stack[operator_sp - 1];
|
2014-11-30 17:00:13 +00:00
|
|
|
--operator_sp; // decrement operator stack pointer
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-04-26 18:53:14 +00:00
|
|
|
// The core of it.
|
2012-02-27 21:14:46 +00:00
|
|
|
// FIXME - make state machine using function pointers? or too slow?
|
2020-04-26 18:53:14 +00:00
|
|
|
static void parse_expression(struct expression *expression)
|
2012-02-27 21:14:46 +00:00
|
|
|
{
|
2020-04-28 16:02:09 +00:00
|
|
|
struct number *result = &expression->number;
|
2020-04-26 18:53:14 +00:00
|
|
|
|
2020-04-26 20:14:39 +00:00
|
|
|
// init
|
2020-04-26 22:26:05 +00:00
|
|
|
expression->is_empty = TRUE; // becomes FALSE when first valid char gets parsed
|
2020-04-26 18:53:14 +00:00
|
|
|
expression->open_parentheses = 0;
|
2020-04-26 20:14:39 +00:00
|
|
|
expression->is_parenthesized = FALSE; // toplevel operator will set this: '(' to TRUE, all others to FALSE
|
|
|
|
//expression->number will be overwritten later, so no need to init
|
2012-02-27 21:14:46 +00:00
|
|
|
|
|
|
|
operator_sp = 0; // operator stack pointer
|
|
|
|
operand_sp = 0; // value stack pointer
|
|
|
|
// begin by reading value (or monadic operator)
|
|
|
|
alu_state = STATE_EXPECT_OPERAND_OR_MONADIC_OPERATOR;
|
2017-10-21 19:59:56 +00:00
|
|
|
PUSH_OPERATOR(&ops_exprstart);
|
2012-02-27 21:14:46 +00:00
|
|
|
do {
|
|
|
|
// check stack sizes. enlarge if needed
|
|
|
|
if (operator_sp >= operator_stk_size)
|
|
|
|
enlarge_operator_stack();
|
|
|
|
if (operand_sp >= operand_stk_size)
|
|
|
|
enlarge_operand_stack();
|
|
|
|
switch (alu_state) {
|
|
|
|
case STATE_EXPECT_OPERAND_OR_MONADIC_OPERATOR:
|
2020-04-26 22:26:05 +00:00
|
|
|
if (expect_operand_or_monadic_operator())
|
|
|
|
expression->is_empty = FALSE;
|
2012-02-27 21:14:46 +00:00
|
|
|
break;
|
|
|
|
case STATE_EXPECT_DYADIC_OPERATOR:
|
|
|
|
expect_dyadic_operator();
|
|
|
|
break; // no fallthrough; state might
|
|
|
|
// have been changed to END or ERROR
|
|
|
|
case STATE_TRY_TO_REDUCE_STACKS:
|
2020-04-26 20:14:39 +00:00
|
|
|
try_to_reduce_stacks(expression);
|
2012-02-27 21:14:46 +00:00
|
|
|
break;
|
|
|
|
case STATE_MAX_GO_ON: // suppress
|
|
|
|
case STATE_ERROR: // compiler
|
|
|
|
case STATE_END: // warnings
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (alu_state < STATE_MAX_GO_ON);
|
|
|
|
// done. check state.
|
|
|
|
if (alu_state == STATE_END) {
|
|
|
|
// check for bugs
|
|
|
|
if (operand_sp != 1)
|
|
|
|
Bug_found("OperandStackNotEmpty", operand_sp);
|
|
|
|
if (operator_sp != 1)
|
|
|
|
Bug_found("OperatorStackNotEmpty", operator_sp);
|
|
|
|
// copy result
|
|
|
|
*result = operand_stack[0];
|
|
|
|
// only allow *one* force bit
|
2020-04-28 16:02:09 +00:00
|
|
|
if (result->flags & NUMBER_FORCES_24)
|
|
|
|
result->flags &= ~(NUMBER_FORCES_16 | NUMBER_FORCES_8);
|
|
|
|
else if (result->flags & NUMBER_FORCES_16)
|
|
|
|
result->flags &= ~NUMBER_FORCES_8;
|
2020-05-02 10:40:10 +00:00
|
|
|
// if there was nothing to parse, mark as undefined FIXME - change this! make "nothing" its own result type; only numbers may be undefined
|
2012-02-27 21:14:46 +00:00
|
|
|
// (so ALU_defined_int() can react)
|
2020-05-02 14:58:17 +00:00
|
|
|
if (expression->is_empty) {
|
2020-04-28 16:02:09 +00:00
|
|
|
result->flags &= ~NUMBER_IS_DEFINED;
|
2020-05-02 14:58:17 +00:00
|
|
|
} else {
|
|
|
|
// not empty. undefined?
|
|
|
|
if (!(expression->number.flags & NUMBER_IS_DEFINED)) {
|
|
|
|
// then count (in all passes)
|
|
|
|
++pass.undefined_count;
|
|
|
|
}
|
|
|
|
}
|
2012-02-27 21:14:46 +00:00
|
|
|
// do some checks depending on int/float
|
2020-04-28 16:02:09 +00:00
|
|
|
if (result->flags & NUMBER_IS_FLOAT) {
|
2012-02-27 21:14:46 +00:00
|
|
|
/*float*/ // if undefined, return zero
|
2020-04-28 16:02:09 +00:00
|
|
|
if ((result->flags & NUMBER_IS_DEFINED) == 0)
|
2012-02-27 21:14:46 +00:00
|
|
|
result->val.fpval = 0;
|
2020-04-28 16:02:09 +00:00
|
|
|
// if value is sure, check to set FITS BYTE
|
|
|
|
else if (((result->flags & NUMBER_EVER_UNDEFINED) == 0)
|
2012-02-27 21:14:46 +00:00
|
|
|
&& (result->val.fpval <= 255.0)
|
|
|
|
&& (result->val.fpval >= -128.0))
|
2020-04-28 16:02:09 +00:00
|
|
|
result->flags |= NUMBER_FITS_BYTE;
|
2012-02-27 21:14:46 +00:00
|
|
|
} else {
|
|
|
|
/*int*/ // if undefined, return zero
|
2020-04-28 16:02:09 +00:00
|
|
|
if ((result->flags & NUMBER_IS_DEFINED) == 0)
|
2012-02-27 21:14:46 +00:00
|
|
|
result->val.intval = 0;
|
2020-04-28 16:02:09 +00:00
|
|
|
// if value is sure, check to set FITS BYTE
|
|
|
|
else if (((result->flags & NUMBER_EVER_UNDEFINED) == 0)
|
2012-02-27 21:14:46 +00:00
|
|
|
&& (result->val.intval <= 255)
|
|
|
|
&& (result->val.intval >= -128))
|
2020-04-28 16:02:09 +00:00
|
|
|
result->flags |= NUMBER_FITS_BYTE;
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
|
|
|
} else {
|
2017-10-29 23:29:07 +00:00
|
|
|
// State is STATE_ERROR. Errors have already been reported,
|
|
|
|
// but we must make sure not to pass bogus data to caller.
|
2020-05-02 10:40:10 +00:00
|
|
|
// FIXME - just use the return value to indicate "there were errors, do not use result!"
|
2017-10-29 23:29:07 +00:00
|
|
|
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"!)
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 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.
|
2020-05-02 10:40:10 +00:00
|
|
|
// If the result is non-empty but undefined, a serious error is thrown, stopping assembly.
|
2015-06-14 23:16:23 +00:00
|
|
|
// OPEN_PARENTHESIS: complain
|
|
|
|
// EMPTY: allow
|
|
|
|
// UNDEFINED: complain _seriously_
|
|
|
|
// FLOAT: convert to int
|
2020-05-02 14:58:17 +00:00
|
|
|
boolean ALU_optional_defined_int(intval_t *target) // ACCEPT_EMPTY
|
2012-02-27 21:14:46 +00:00
|
|
|
{
|
2020-04-26 18:53:14 +00:00
|
|
|
struct expression expression;
|
2020-05-02 21:59:20 +00:00
|
|
|
boolean buf = pass.complain_about_undefined;
|
2012-02-27 21:14:46 +00:00
|
|
|
|
2020-05-02 21:59:20 +00:00
|
|
|
pass.complain_about_undefined = TRUE;
|
2020-04-26 18:53:14 +00:00
|
|
|
parse_expression(&expression);
|
2020-05-02 21:59:20 +00:00
|
|
|
pass.complain_about_undefined = buf;
|
2020-04-26 18:53:14 +00:00
|
|
|
if (expression.open_parentheses)
|
2012-02-27 21:14:46 +00:00
|
|
|
Throw_error(exception_paren_open);
|
2020-05-02 10:40:10 +00:00
|
|
|
if ((!expression.is_empty)
|
|
|
|
&& (!(expression.number.flags & NUMBER_IS_DEFINED)))
|
2020-05-02 21:59:20 +00:00
|
|
|
Throw_serious_error(exception_value_not_defined);
|
2020-04-26 22:26:05 +00:00
|
|
|
if (expression.is_empty)
|
2020-05-02 14:58:17 +00:00
|
|
|
return FALSE;
|
2016-02-21 23:08:02 +00:00
|
|
|
|
2012-02-27 21:14:46 +00:00
|
|
|
// something was given, so store
|
2020-04-28 16:02:09 +00:00
|
|
|
if (expression.number.flags & NUMBER_IS_FLOAT)
|
2020-04-26 18:53:14 +00:00
|
|
|
*target = expression.number.val.fpval;
|
2012-02-27 21:14:46 +00:00
|
|
|
else
|
2020-04-26 18:53:14 +00:00
|
|
|
*target = expression.number.val.intval;
|
2020-05-02 14:58:17 +00:00
|
|
|
return TRUE;
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-05-02 10:40:10 +00:00
|
|
|
// return int value (if undefined, return zero)
|
|
|
|
// For empty expressions, an error is thrown.
|
2015-06-14 23:16:23 +00:00
|
|
|
// OPEN_PARENTHESIS: complain
|
|
|
|
// EMPTY: complain
|
|
|
|
// UNDEFINED: allow
|
|
|
|
// FLOAT: convert to int
|
|
|
|
intval_t ALU_any_int(void) // ACCEPT_UNDEFINED
|
|
|
|
{
|
2020-04-26 18:53:14 +00:00
|
|
|
struct expression expression;
|
2015-06-14 23:16:23 +00:00
|
|
|
|
2020-04-26 18:53:14 +00:00
|
|
|
parse_expression(&expression);
|
|
|
|
if (expression.open_parentheses)
|
2015-06-14 23:16:23 +00:00
|
|
|
Throw_error(exception_paren_open);
|
2020-04-26 22:26:05 +00:00
|
|
|
if (expression.is_empty)
|
2015-06-14 23:16:23 +00:00
|
|
|
Throw_error(exception_no_value);
|
2020-04-28 16:02:09 +00:00
|
|
|
if (expression.number.flags & NUMBER_IS_FLOAT)
|
2020-04-26 18:53:14 +00:00
|
|
|
return expression.number.val.fpval;
|
2015-06-14 23:16:23 +00:00
|
|
|
else
|
2020-04-26 18:53:14 +00:00
|
|
|
return expression.number.val.intval;
|
2015-06-14 23:16:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// stores int value and flags (floats are transformed to int)
|
2020-05-02 10:40:10 +00:00
|
|
|
// if result is empty or undefined, serious error is thrown
|
2015-06-14 23:16:23 +00:00
|
|
|
// OPEN_PARENTHESIS: complain
|
2020-05-02 10:40:10 +00:00
|
|
|
// EMPTY: complain _seriously_
|
2015-06-14 23:16:23 +00:00
|
|
|
// UNDEFINED: complain _seriously_
|
|
|
|
// FLOAT: convert to int
|
2020-04-28 16:02:09 +00:00
|
|
|
void ALU_defined_int(struct number *intresult) // no ACCEPT constants?
|
2015-06-14 23:16:23 +00:00
|
|
|
{
|
2020-04-26 18:53:14 +00:00
|
|
|
struct expression expression;
|
2020-05-02 21:59:20 +00:00
|
|
|
boolean buf = pass.complain_about_undefined;
|
2020-04-26 18:53:14 +00:00
|
|
|
|
2020-05-02 21:59:20 +00:00
|
|
|
pass.complain_about_undefined = TRUE;
|
2020-04-26 18:53:14 +00:00
|
|
|
parse_expression(&expression);
|
2020-05-02 21:59:20 +00:00
|
|
|
pass.complain_about_undefined = buf;
|
2020-04-26 18:53:14 +00:00
|
|
|
*intresult = expression.number;
|
|
|
|
if (expression.open_parentheses)
|
2015-06-14 23:16:23 +00:00
|
|
|
Throw_error(exception_paren_open);
|
2020-05-02 10:40:10 +00:00
|
|
|
if (expression.is_empty)
|
|
|
|
Throw_serious_error(exception_no_value);
|
|
|
|
if (!(intresult->flags & NUMBER_IS_DEFINED))
|
2020-05-02 21:59:20 +00:00
|
|
|
Throw_serious_error(exception_value_not_defined);
|
2020-04-28 16:02:09 +00:00
|
|
|
if (intresult->flags & NUMBER_IS_FLOAT) {
|
2015-06-14 23:16:23 +00:00
|
|
|
intresult->val.intval = intresult->val.fpval;
|
2020-04-28 16:02:09 +00:00
|
|
|
intresult->flags &= ~NUMBER_IS_FLOAT;
|
2015-06-14 23:16:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-02-27 21:14:46 +00:00
|
|
|
// Store int value and flags.
|
2020-05-07 23:32:06 +00:00
|
|
|
// This function allows for "paren" '(' too many. Needed when parsing indirect
|
2020-04-26 18:53:14 +00:00
|
|
|
// addressing modes where internal indices have to be possible.
|
2020-05-02 10:40:10 +00:00
|
|
|
// For empty expressions, an error is thrown.
|
2015-06-14 23:16:23 +00:00
|
|
|
// OPEN_PARENTHESIS: allow
|
|
|
|
// UNDEFINED: allow
|
2020-04-26 16:24:34 +00:00
|
|
|
// EMPTY: complain
|
2015-06-14 23:16:23 +00:00
|
|
|
// FLOAT: convert to int
|
2020-05-07 23:32:06 +00:00
|
|
|
void ALU_addrmode_int(struct expression *expression, int paren) // ACCEPT_UNDEFINED | ACCEPT_OPENPARENTHESIS
|
2012-02-27 21:14:46 +00:00
|
|
|
{
|
2020-04-26 18:53:14 +00:00
|
|
|
parse_expression(expression);
|
2020-05-08 00:34:46 +00:00
|
|
|
// convert float to int
|
|
|
|
if (expression->number.flags & NUMBER_IS_FLOAT) {
|
|
|
|
expression->number.val.intval = expression->number.val.fpval;
|
|
|
|
expression->number.flags &= ~NUMBER_IS_FLOAT;
|
2014-06-02 00:47:46 +00:00
|
|
|
}
|
2020-05-07 23:32:06 +00:00
|
|
|
if (expression->open_parentheses > paren) {
|
2020-04-26 18:53:14 +00:00
|
|
|
expression->open_parentheses = 0;
|
2012-02-27 21:14:46 +00:00
|
|
|
Throw_error(exception_paren_open);
|
|
|
|
}
|
2020-04-26 22:26:05 +00:00
|
|
|
if (expression->is_empty)
|
2020-04-26 16:24:34 +00:00
|
|
|
Throw_error(exception_no_value);
|
2012-02-27 21:14:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Store value and flags (result may be either int or float)
|
2020-05-02 10:40:10 +00:00
|
|
|
// For empty expressions, an error is thrown.
|
2015-06-14 23:16:23 +00:00
|
|
|
// OPEN_PARENTHESIS: complain
|
|
|
|
// EMPTY: complain
|
|
|
|
// UNDEFINED: allow
|
|
|
|
// FLOAT: keep
|
2020-04-28 16:02:09 +00:00
|
|
|
void ALU_any_result(struct number *result) // ACCEPT_UNDEFINED | ACCEPT_FLOAT
|
2012-02-27 21:14:46 +00:00
|
|
|
{
|
2020-04-26 18:53:14 +00:00
|
|
|
struct expression expression;
|
|
|
|
|
|
|
|
parse_expression(&expression);
|
|
|
|
*result = expression.number;
|
|
|
|
if (expression.open_parentheses)
|
2012-02-27 21:14:46 +00:00
|
|
|
Throw_error(exception_paren_open);
|
2020-04-26 22:26:05 +00:00
|
|
|
if (expression.is_empty)
|
2012-02-27 21:14:46 +00:00
|
|
|
Throw_error(exception_no_value);
|
|
|
|
}
|
2020-04-30 16:34:09 +00:00
|
|
|
|
2020-05-02 10:40:10 +00:00
|
|
|
|
2020-04-30 16:34:09 +00:00
|
|
|
/* TODO
|
|
|
|
|
2020-05-08 00:34:46 +00:00
|
|
|
// stores int value and flags, allowing for "paren" '(' too many (x-indirect addr).
|
2020-05-07 23:32:06 +00:00
|
|
|
void ALU_addrmode_int(struct expression *expression, int paren)
|
2020-04-30 16:34:09 +00:00
|
|
|
mnemo.c
|
2020-05-08 00:34:46 +00:00
|
|
|
when parsing addressing modes needvalue!
|
2020-04-30 16:34:09 +00:00
|
|
|
|
|
|
|
// stores value and flags (result may be either int or float)
|
|
|
|
void ALU_any_result(struct number *result)
|
|
|
|
macro.c
|
2020-05-02 14:58:17 +00:00
|
|
|
macro call, when parsing call-by-value arg don't care
|
2020-04-30 16:34:09 +00:00
|
|
|
pseudoopcodes.c
|
2020-05-02 14:58:17 +00:00
|
|
|
!set don't care
|
|
|
|
when throwing user-specified errors don't care
|
2020-04-30 16:34:09 +00:00
|
|
|
symbol.c
|
2020-05-02 14:58:17 +00:00
|
|
|
explicit symbol definition don't care
|
2020-04-30 16:34:09 +00:00
|
|
|
|
|
|
|
// stores int value and flags (floats are transformed to int)
|
|
|
|
// if result was undefined, serious error is thrown
|
|
|
|
void ALU_defined_int(struct number *intresult)
|
|
|
|
flow.c
|
2020-05-02 14:58:17 +00:00
|
|
|
when parsing loop conditions make bool serious
|
2020-04-30 16:34:09 +00:00
|
|
|
pseudoopcodes.c
|
2020-05-02 14:58:17 +00:00
|
|
|
*= (FIXME, allow undefined) needvalue!
|
|
|
|
!initmem serious
|
|
|
|
!fill (1st arg) (maybe allow undefined?) needvalue!
|
|
|
|
!skip (maybe allow undefined?) needvalue!
|
|
|
|
!align (1st + 2nd arg) (maybe allow undefined?) needvalue!
|
|
|
|
!pseudopc (FIXME, allow undefined) needvalue!
|
|
|
|
!if make bool serious
|
|
|
|
twice in !for serious
|
2020-04-30 16:34:09 +00:00
|
|
|
|
|
|
|
// stores int value if given. Returns whether stored. Throws error if undefined.
|
|
|
|
int ALU_optional_defined_int(intval_t *target)
|
|
|
|
pseudoopcodes.c
|
2020-05-02 14:58:17 +00:00
|
|
|
twice for !binary (maybe allow undefined?) needvalue!
|
2020-04-30 16:34:09 +00:00
|
|
|
//!enum
|
|
|
|
|
|
|
|
// returns int value (0 if result was undefined)
|
|
|
|
intval_t ALU_any_int(void)
|
|
|
|
pseudoopcodes.c
|
2020-05-02 14:58:17 +00:00
|
|
|
!xor needvalue!
|
|
|
|
iterator for !by, !wo, etc. needvalue!
|
|
|
|
byte values in !raw, !tx, etc. needvalue!
|
|
|
|
!scrxor needvalue!
|
|
|
|
!fill (2nd arg) needvalue!
|
|
|
|
!align (3rd arg) needvalue!
|
2020-04-30 16:34:09 +00:00
|
|
|
*/
|