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"
2015-06-14 23:16:23 +00:00
# define UNDEFSYM_DYNABUF_INITIALSIZE 256 // ad hoc
2012-02-27 21:14:46 +00:00
# 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
2016-02-21 23:08:02 +00:00
static struct dynabuf * undefsym_dyna_buf ; // dynamic buffer for name of undefined symbol TODO - get rid of this intermediate kluge and report errors immediately
2014-03-11 12:07:11 +00:00
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 )
2015-06-14 23:16:23 +00:00
// generate "Value not defined" error message with added symbol name
static char * value_not_defined ( void )
2012-02-27 21:14:46 +00:00
{
2015-06-14 23:16:23 +00:00
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 ;
2012-02-27 21:14:46 +00:00
}
2015-06-14 23:16:23 +00:00
// function pointer for "value undefined" error output. set to NULL to suppress those errors.
void ( * ALU_optional_notdef_handler ) ( const char * ) = NULL ;
2012-02-27 21:14:46 +00:00
2015-06-14 23:16:23 +00:00
// 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 )
2012-02-27 21:14:46 +00:00
{
2015-06-14 23:16:23 +00:00
+ + pass_undefined_count ;
if ( ALU_optional_notdef_handler )
ALU_optional_notdef_handler ( value_not_defined ( ) ) ;
2012-02-27 21:14:46 +00:00
}
// 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 ) ;
2015-06-14 23:16:23 +00:00
undefsym_dyna_buf = DynaBuf_create ( UNDEFSYM_DYNABUF_INITIALSIZE ) ;
2012-02-27 21:14:46 +00:00
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 ) ;
}
2015-06-14 23:16:23 +00:00
// if undefined, remember name for error output
2017-10-29 23:29:07 +00:00
static void check_for_def ( int flags , char optional_prefix_char , char * name , size_t length )
2015-06-14 23:16:23 +00:00
{
2020-04-28 16:02:09 +00:00
if ( ( flags & NUMBER_IS_DEFINED ) = = 0 ) {
2015-06-14 23:16:23 +00:00
DYNABUF_CLEAR ( undefsym_dyna_buf ) ;
2017-10-29 23:29:07 +00:00
if ( optional_prefix_char ) {
DynaBuf_append ( undefsym_dyna_buf , optional_prefix_char ) ;
2015-06-14 23:16:23 +00:00
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 ' ) ;
}
}
2012-02-27 21:14:46 +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 ) ;
2015-06-14 23:16:23 +00:00
// if needed, remember name for "undefined" error output
2017-10-29 23:29:07 +00:00
check_for_def ( symbol - > result . flags , optional_prefix_char , GLOBALDYNABUF_CURRENT , name_length ) ;
2012-02-27 21:14:46 +00:00
// in first pass, count usage
if ( pass_count = = 0 )
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
}
// 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
}
2014-03-11 12:07:11 +00:00
// Parse program counter ('*')
static void parse_program_counter ( void ) // Now GotByte = "*"
{
2020-04-28 16:02:09 +00:00
struct number pc ;
2014-03-11 14:22:32 +00:00
2014-03-11 12:07:11 +00:00
GetByte ( ) ;
2014-03-11 14:22:32 +00:00
vcpu_read_pc ( & pc ) ;
2015-06-14 23:16:23 +00:00
// if needed, remember name for "undefined" error output
check_for_def ( pc . flags , 0 , " * " , 1 ) ;
2020-04-26 22:26:05 +00:00
PUSH_INTOPERAND ( pc . val . intval , pc . flags , pc . addr_refs ) ;
2014-03-11 12:07:11 +00:00
}
2012-02-27 21:14:46 +00:00
// 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 ;
2012-02-27 21:14:46 +00:00
// if there was nothing to parse, mark as undefined
// (so ALU_defined_int() can react)
2020-04-26 22:26:05 +00:00
if ( expression - > is_empty )
2020-04-28 16:02:09 +00:00
result - > flags & = ~ NUMBER_IS_DEFINED ;
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.
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.
// If the result's "defined" flag is clear and the "exists" flag is set, it
// throws a serious error and therefore stops assembly.
2015-06-14 23:16:23 +00:00
// OPEN_PARENTHESIS: complain
// EMPTY: allow
// UNDEFINED: complain _seriously_
// FLOAT: convert to int
int 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 ;
2012-02-27 21:14:46 +00:00
2020-04-26 18:53:14 +00:00
parse_expression ( & expression ) ;
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 = = FALSE )
2020-04-28 16:02:09 +00:00
& & ( ( expression . number . flags & NUMBER_IS_DEFINED ) = = 0 ) )
2020-04-26 16:24:34 +00:00
Throw_serious_error ( value_not_defined ( ) ) ;
2020-04-26 22:26:05 +00:00
if ( expression . is_empty )
2012-02-27 21:14:46 +00:00
return 0 ;
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 ;
2012-02-27 21:14:46 +00:00
return 1 ;
}
// Store int value and flags (floats are transformed to int)
// 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.
2015-06-14 23:16:23 +00:00
// OPEN_PARENTHESIS: complain
// EMPTY: complain
// UNDEFINED: allow
// FLOAT: convert to int
2020-04-28 16:02:09 +00:00
void ALU_int_result ( struct number * intresult ) // ACCEPT_UNDEFINED
2012-02-27 21:14:46 +00:00
{
2020-04-26 18:53:14 +00:00
struct expression expression ;
parse_expression ( & expression ) ;
* intresult = expression . number ;
if ( expression . open_parentheses )
2012-02-27 21:14:46 +00:00
Throw_error ( exception_paren_open ) ;
2014-06-02 00:47:46 +00:00
// make sure result is not float
2020-04-28 16:02:09 +00:00
if ( intresult - > flags & NUMBER_IS_FLOAT ) {
2014-06-02 00:47:46 +00:00
intresult - > val . intval = intresult - > val . fpval ;
2020-04-28 16:02:09 +00:00
intresult - > flags & = ~ NUMBER_IS_FLOAT ;
2014-06-02 00:47:46 +00:00
}
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-28 16:02:09 +00:00
else if ( ( intresult - > flags & NUMBER_IS_DEFINED ) = = 0 )
2012-02-27 21:14:46 +00:00
result_is_undefined ( ) ;
}
2015-06-14 23:16:23 +00:00
// 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!
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
else if ( ( expression . number . flags & NUMBER_IS_DEFINED ) = = 0 )
2015-06-14 23:16:23 +00:00
result_is_undefined ( ) ;
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)
// 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
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 ;
parse_expression ( & expression ) ;
* intresult = expression . number ;
if ( expression . open_parentheses )
2015-06-14 23:16:23 +00:00
Throw_error ( exception_paren_open ) ;
2020-04-28 16:02:09 +00:00
if ( ( intresult - > flags & NUMBER_IS_DEFINED ) = = 0 )
2015-06-14 23:16:23 +00:00
Throw_serious_error ( 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.
// This function allows for one '(' too many. Needed when parsing indirect
2020-04-26 18:53:14 +00:00
// addressing modes where internal indices have to be possible.
2020-04-26 16:24:34 +00:00
// If the result's "exists" flag is clear (=empty expression), it throws an
// error.
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-04-26 18:53:14 +00:00
void ALU_liberal_int ( struct expression * expression ) // ACCEPT_UNDEFINED | ACCEPT_OPENPARENTHESIS
2012-02-27 21:14:46 +00:00
{
2020-04-28 16:02:09 +00:00
struct number * intresult = & expression - > number ;
2012-02-27 21:14:46 +00:00
2020-04-26 18:53:14 +00:00
parse_expression ( expression ) ;
2014-06-02 00:47:46 +00:00
// make sure result is not float
2020-04-28 16:02:09 +00:00
if ( intresult - > flags & NUMBER_IS_FLOAT ) {
2014-06-02 00:47:46 +00:00
intresult - > val . intval = intresult - > val . fpval ;
2020-04-28 16:02:09 +00:00
intresult - > flags & = ~ NUMBER_IS_FLOAT ;
2014-06-02 00:47:46 +00:00
}
2020-04-26 18:53:14 +00:00
if ( expression - > open_parentheses > 1 ) {
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 ) ;
2020-04-26 22:26:05 +00:00
if ( ( expression - > is_empty = = FALSE )
2020-04-28 16:02:09 +00:00
& & ( ( intresult - > flags & NUMBER_IS_DEFINED ) = = 0 ) )
2012-02-27 21:14:46 +00:00
result_is_undefined ( ) ;
}
// Store value and flags (result may be either int or float)
// 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.
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-28 16:02:09 +00:00
else if ( ( result - > flags & NUMBER_IS_DEFINED ) = = 0 )
2012-02-27 21:14:46 +00:00
result_is_undefined ( ) ;
}
2020-04-30 16:34:09 +00:00
/* TODO
// stores int value and flags, allowing for one '(' too many (x-indirect addr).
void ALU_liberal_int ( struct expression * expression )
mnemo . c
when parsing addressing mode ( except after ' # ' and ' [ ' )
// stores int value and flags (floats are transformed to int)
void ALU_int_result ( struct number * intresult )
mnemo . c
when parsing address arg after ' # '
when parsing address arg after ' [ '
when parsing address after near branch ( needs ( ) check )
when parsing address after far branch ( needs ( ) check )
when parsing address after bbrX / bbsX ( needs ( ) check )
when parsing address after rmbX / smbX ( needs ( ) check )
twice when parsing MVN / MVP ( needs ( ) check )
// stores value and flags (result may be either int or float)
void ALU_any_result ( struct number * result )
macro . c
macro call , when parsing call - by - value arg
pseudoopcodes . c
! set
when throwing user - specified errors
symbol . c
explicit symbol definition
// 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
when parsing loop conditions ( should be rather bool ? )
pseudoopcodes . c
* = ( FIXME , allow undefined )
! initmem
! fill ( 1 st arg ) ( maybe allow undefined ? )
! skip ( maybe allow undefined ? )
! align ( 1 st + 2 nd arg ) ( maybe allow undefined ? )
! pseudopc ( FIXME , allow undefined )
! if ( should be rather bool ? )
twice in ! for
// stores int value if given. Returns whether stored. Throws error if undefined.
int ALU_optional_defined_int ( intval_t * target )
pseudoopcodes . c
twice for ! binary ( maybe allow undefined ? )
//!enum
// returns int value (0 if result was undefined)
intval_t ALU_any_int ( void )
pseudoopcodes . c
! xor
iterator for ! by , ! wo , etc .
byte values in ! raw , ! tx , etc .
! scrxor
! fill ( 2 nd arg )
! align ( 3 rd arg )
*/