2018-01-23 14:07:23 +02:00
//
2021-03-08 00:43:25 +02:00
// RMAC - Renamed Macro Assembler for all Atari computers
2011-12-27 00:50:27 +02:00
// EXPR.C - Expression Analyzer
2021-03-08 00:43:25 +02:00
// Copyright (C) 199x Landon Dyer, 2011-2021 Reboot and Friends
2011-12-27 00:50:27 +02:00
// RMAC derived from MADMAC v1.07 Written by Landon Dyer, 1986
2015-02-19 16:56:14 +02:00
// Source utilised with the kind permission of Landon Dyer
2011-12-27 01:54:45 +02:00
//
2011-12-27 00:50:27 +02:00
# include "expr.h"
2012-11-24 21:48:52 +02:00
# include "direct.h"
2011-12-27 00:50:27 +02:00
# include "error.h"
2012-11-24 21:48:52 +02:00
# include "listing.h"
2011-12-27 00:50:27 +02:00
# include "mach.h"
2012-11-24 21:48:52 +02:00
# include "procln.h"
2013-03-02 22:22:33 +02:00
# include "riscasm.h"
2012-11-24 21:48:52 +02:00
# include "sect.h"
# include "symbol.h"
# include "token.h"
2011-12-27 00:50:27 +02:00
2017-04-14 23:52:31 +03:00
# define DEF_KW // Declare keyword values
2015-01-13 19:06:11 +02:00
# include "kwtab.h" // Incl generated keyword tables & defs
2011-12-27 00:50:27 +02:00
2015-01-13 19:06:11 +02:00
// N.B.: The size of tokenClass should be identical to the largest value of
// a token; we're assuming 256 but not 100% sure!
static char tokenClass [ 256 ] ; // Generated table of token classes
2017-10-08 16:40:02 +03:00
static uint64_t evstk [ EVSTACKSIZE ] ; // Evaluator value stack
2015-01-13 19:06:11 +02:00
static WORD evattr [ EVSTACKSIZE ] ; // Evaluator attribute stack
2011-12-27 00:50:27 +02:00
// Token-class initialization list
char itokcl [ ] = {
2015-01-13 19:06:11 +02:00
0 , // END
2017-10-26 15:24:25 +03:00
CONST , FCONST , SYMBOL , 0 , // ID
2015-01-13 19:06:11 +02:00
' ( ' , ' [ ' , ' { ' , 0 , // OPAR
2017-04-14 23:52:31 +03:00
' ) ' , ' ] ' , ' } ' , 0 , // CPAR
2015-01-13 19:06:11 +02:00
CR_DEFINED , CR_REFERENCED , // SUNARY (special unary)
2012-01-18 04:06:46 +02:00
CR_STREQ , CR_MACDEF ,
2017-04-14 23:52:31 +03:00
CR_DATE , CR_TIME ,
2020-01-03 08:46:19 +02:00
CR_ABSCOUNT , CR_FILESIZE , 0 ,
2018-06-23 19:57:21 +03:00
' ! ' , ' ~ ' , UNMINUS , UNLT , UNGT , 0 , // UNARY
2017-04-14 23:52:31 +03:00
' * ' , ' / ' , ' % ' , 0 , // MULT
' + ' , ' - ' , 0 , // ADD
SHL , SHR , 0 , // SHIFT
LE , GE , ' < ' , ' > ' , NE , ' = ' , 0 , // REL
' & ' , 0 , // AND
' ^ ' , 0 , // XOR
' | ' , 0 , // OR
1 // (the end)
2011-12-27 00:50:27 +02:00
} ;
2012-11-24 21:48:52 +02:00
const char missym_error [ ] = " missing symbol " ;
const char str_error [ ] = " missing symbol or string " ;
2018-06-23 19:57:21 +03:00
const char noflt_error [ ] = " operator not usable with float " ;
2011-12-27 00:50:27 +02:00
// Convert expression to postfix
2017-11-29 15:57:58 +02:00
static PTR evalTokenBuffer ; // Deposit tokens here (this is really a
// pointer to exprbuf from direct.c)
// (Can also be from others, like
// riscasm.c)
static int symbolNum ; // Pointer to the entry in symbolPtr[]
2012-01-18 04:06:46 +02:00
2011-12-27 00:50:27 +02:00
//
2015-01-13 19:06:11 +02:00
// Obtain a string value
2011-12-27 00:50:27 +02:00
//
2017-08-29 20:20:17 +03:00
static uint32_t str_value ( char * p )
2012-01-18 04:06:46 +02:00
{
2017-08-29 20:20:17 +03:00
uint32_t v ;
2011-12-27 00:50:27 +02:00
2012-11-26 06:49:46 +02:00
for ( v = 0 ; * p ; p + + )
2012-01-18 04:06:46 +02:00
v = ( v < < 8 ) | ( * p & 0xFF ) ;
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
return v ;
2011-12-27 00:50:27 +02:00
}
//
2015-01-13 19:06:11 +02:00
// Initialize expression analyzer
2011-12-27 00:50:27 +02:00
//
2013-03-05 19:47:22 +02:00
void InitExpression ( void )
2012-01-18 04:06:46 +02:00
{
2013-03-04 15:36:09 +02:00
// Initialize token-class table (all set to END)
2017-04-20 22:29:31 +03:00
for ( int i = 0 ; i < 256 ; i + + )
2013-03-04 15:36:09 +02:00
tokenClass [ i ] = END ;
2012-01-18 04:06:46 +02:00
2017-04-20 22:29:31 +03:00
int i = 0 ;
for ( char * p = itokcl ; * p ! = 1 ; p + + )
2012-01-18 04:06:46 +02:00
{
if ( * p = = 0 )
2012-11-23 18:39:09 +02:00
i + + ;
2017-04-14 23:52:31 +03:00
else
2013-03-04 15:36:09 +02:00
tokenClass [ ( int ) ( * p ) ] = ( char ) i ;
2012-01-18 04:06:46 +02:00
}
2012-11-24 21:48:52 +02:00
symbolNum = 0 ;
2011-12-27 00:50:27 +02:00
}
2022-05-31 22:42:55 +03:00
extern int correctMathRules ;
int xor ( void ) ;
int and ( void ) ;
int rel ( void ) ;
int shift ( void ) ;
int sum ( void ) ;
int product ( void ) ;
2011-12-27 00:50:27 +02:00
//
2022-05-31 22:42:55 +03:00
// Binary operators (all the same precedence,
// except if -4 is passed to the command line)
2011-12-27 00:50:27 +02:00
//
2022-05-31 22:42:55 +03:00
# define precedence(HIERARCHY_HIGHER, HIERARCHY_CURRENT) \
do \
{ \
if ( HIERARCHY_HIGHER ( ) ! = OK ) \
return ERROR ; \
while ( tokenClass [ * tok ] = = HIERARCHY_CURRENT ) \
{ \
TOKEN t = * tok + + ; \
if ( HIERARCHY_HIGHER ( ) ! = OK ) \
return ERROR ; \
* evalTokenBuffer . u32 + + = t ; \
} \
} while ( 0 )
2012-01-18 04:06:46 +02:00
int expr0 ( void )
{
2022-05-31 22:42:55 +03:00
if ( correctMathRules = = 0 )
2012-01-18 04:06:46 +02:00
{
if ( expr1 ( ) ! = OK )
return ERROR ;
2011-12-27 00:50:27 +02:00
2022-05-31 22:42:55 +03:00
while ( tokenClass [ * tok ] > = MULT )
{
TOKEN t = * tok + + ;
if ( expr1 ( ) ! = OK )
return ERROR ;
* evalTokenBuffer . u32 + + = t ;
}
}
else
{
// The order of C precedence (lower to higher):
// bitwise XOR ^
// bitwise OR |
// bitwise AND &
// relational = < <= >= > !=
// shifts << >>
// sum + -
// product * /
precedence ( xor , OR ) ;
2012-01-18 04:06:46 +02:00
}
2022-05-31 22:42:55 +03:00
return OK ;
}
int xor ( void )
{
precedence ( and , XOR ) ;
return OK ;
}
int and ( void )
{
precedence ( rel , AND ) ;
return OK ;
}
int rel ( void )
{
precedence ( shift , REL ) ;
return OK ;
}
int shift ( void )
{
precedence ( sum , SHIFT ) ;
return OK ;
}
int sum ( void )
{
precedence ( product , ADD ) ;
return OK ;
}
2011-12-27 00:50:27 +02:00
2022-05-31 22:42:55 +03:00
int product ( void )
{
precedence ( expr1 , MULT ) ;
2012-01-18 04:06:46 +02:00
return OK ;
2011-12-27 00:50:27 +02:00
}
//
2012-01-18 04:06:46 +02:00
// Unary operators (detect unary '-')
2017-11-21 15:54:55 +02:00
// ggn: If expression starts with a plus then also eat it up. For some reason
// the parser gets confused when this happens and emits a "bad
// expression".
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
int expr1 ( void )
{
2018-06-23 19:57:21 +03:00
char * p ;
2012-01-18 04:06:46 +02:00
WORD w ;
2017-11-29 15:57:58 +02:00
int class = tokenClass [ * tok ] ;
2012-01-18 04:06:46 +02:00
2018-06-23 19:57:21 +03:00
if ( * tok = = ' - ' | | * tok = = ' + ' | | * tok = = ' < ' | | * tok = = ' > ' | | class = = UNARY )
2012-01-18 04:06:46 +02:00
{
2018-06-23 19:57:21 +03:00
TOKEN t = * tok + + ;
2012-01-18 04:06:46 +02:00
if ( expr2 ( ) ! = OK )
return ERROR ;
if ( t = = ' - ' )
t = UNMINUS ;
2018-06-23 19:57:21 +03:00
else if ( t = = ' < ' )
t = UNLT ;
else if ( t = = ' > ' )
t = UNGT ;
2012-01-18 04:06:46 +02:00
2017-11-21 15:54:55 +02:00
// With leading + we don't have to deposit anything to the buffer
// because there's no unary '+' nor we have to do anything about it
2017-10-26 15:24:25 +03:00
if ( t ! = ' + ' )
2017-11-21 15:54:55 +02:00
* evalTokenBuffer . u32 + + = t ;
2012-01-18 04:06:46 +02:00
}
else if ( class = = SUNARY )
{
2017-11-29 15:57:58 +02:00
switch ( * tok + + )
2012-01-18 04:06:46 +02:00
{
2015-11-10 22:46:53 +02:00
case CR_ABSCOUNT :
2018-06-27 13:15:36 +03:00
if ( cursect ! = ABS )
{
* evalTokenBuffer . u32 + + = CONST ;
* evalTokenBuffer . u64 + + = sect [ ABS ] . sloc ;
}
else
{
* evalTokenBuffer . u32 + + = CONST ;
* evalTokenBuffer . u64 + + = sloc ;
}
2015-11-10 22:46:53 +02:00
break ;
2020-01-03 08:46:19 +02:00
case CR_FILESIZE :
if ( * tok + + ! = STRING )
return error ( " ^^FILESIZE expects filename inside string " ) ;
* evalTokenBuffer . u32 + + = CONST ;
// @@copypasted from d_incbin, maybe factor this out somehow?
// Attempt to open the include file in the current directory, then (if that
// failed) try list of include files passed in the enviroment string or by
// the "-d" option.
int fd , i ;
char buf1 [ 256 ] ;
if ( ( fd = open ( string [ * tok ] , _OPEN_INC ) ) < 0 )
{
2020-01-17 13:56:40 +02:00
for ( i = 0 ; nthpath ( " RMACPATH " , i , buf1 ) ! = 0 ; i + + )
2020-01-03 08:46:19 +02:00
{
fd = strlen ( buf1 ) ;
2020-01-03 18:37:08 +02:00
2020-01-03 08:46:19 +02:00
// Append path char if necessary
if ( ( fd > 0 ) & & ( buf1 [ fd - 1 ] ! = SLASHCHAR ) )
strcat ( buf1 , SLASHSTRING ) ;
2020-01-03 18:37:08 +02:00
2020-01-03 08:46:19 +02:00
strcat ( buf1 , string [ * tok ] ) ;
2020-01-03 18:37:08 +02:00
2020-01-03 08:46:19 +02:00
if ( ( fd = open ( buf1 , _OPEN_INC ) ) > = 0 )
goto allright ;
}
2020-01-03 18:37:08 +02:00
2023-06-18 16:05:01 +03:00
return error ( " cannot open: \" %s \" " , string [ * tok ] ) ;
2020-01-03 08:46:19 +02:00
}
allright :
* evalTokenBuffer . u64 + + = ( uint64_t ) lseek ( fd , 0L , SEEK_END ) ;
close ( fd ) ;
// Advance tok because of consumed string token
tok + + ;
break ;
2012-01-18 04:06:46 +02:00
case CR_TIME :
2017-11-21 15:54:55 +02:00
* evalTokenBuffer . u32 + + = CONST ;
* evalTokenBuffer . u64 + + = dos_time ( ) ;
2012-01-18 04:06:46 +02:00
break ;
case CR_DATE :
2017-11-21 15:54:55 +02:00
* evalTokenBuffer . u32 + + = CONST ;
* evalTokenBuffer . u64 + + = dos_date ( ) ;
2012-01-18 04:06:46 +02:00
break ;
2017-11-21 15:54:55 +02:00
case CR_MACDEF : // ^^macdef <macro-name>
2017-11-29 15:57:58 +02:00
if ( * tok + + ! = SYMBOL )
2012-01-18 04:06:46 +02:00
return error ( missym_error ) ;
2017-11-29 15:57:58 +02:00
p = string [ * tok + + ] ;
2012-11-24 21:48:52 +02:00
w = ( lookup ( p , MACRO , 0 ) = = NULL ? 0 : 1 ) ;
2017-11-21 15:54:55 +02:00
* evalTokenBuffer . u32 + + = CONST ;
* evalTokenBuffer . u64 + + = ( uint64_t ) w ;
2012-01-18 04:06:46 +02:00
break ;
case CR_DEFINED :
w = DEFINED ;
goto getsym ;
case CR_REFERENCED :
w = REFERENCED ;
getsym :
2017-11-29 15:57:58 +02:00
if ( * tok + + ! = SYMBOL )
2012-01-18 04:06:46 +02:00
return error ( missym_error ) ;
2017-11-29 15:57:58 +02:00
p = string [ * tok + + ] ;
2018-06-23 19:57:21 +03:00
int j = ( * p = = ' . ' ? curenv : 0 ) ;
SYM * sy = lookup ( p , LABEL , j ) ;
w = ( ( sy ! = NULL ) & & ( sy - > sattr & w ? 1 : 0 ) ) ;
2017-11-21 15:54:55 +02:00
* evalTokenBuffer . u32 + + = CONST ;
* evalTokenBuffer . u64 + + = ( uint64_t ) w ;
2012-01-18 04:06:46 +02:00
break ;
case CR_STREQ :
2017-11-29 15:57:58 +02:00
if ( * tok ! = SYMBOL & & * tok ! = STRING )
2012-01-18 04:06:46 +02:00
return error ( str_error ) ;
2017-11-29 15:57:58 +02:00
p = string [ tok [ 1 ] ] ;
tok + = 2 ;
2012-01-18 04:06:46 +02:00
2017-11-29 15:57:58 +02:00
if ( * tok + + ! = ' , ' )
2012-01-18 04:06:46 +02:00
return error ( comma_error ) ;
2017-11-29 15:57:58 +02:00
if ( * tok ! = SYMBOL & & * tok ! = STRING )
2012-01-18 04:06:46 +02:00
return error ( str_error ) ;
2018-06-23 19:57:21 +03:00
char * p2 = string [ tok [ 1 ] ] ;
2017-11-29 15:57:58 +02:00
tok + = 2 ;
2012-01-18 04:06:46 +02:00
w = ( WORD ) ( ! strcmp ( p , p2 ) ) ;
2017-11-21 15:54:55 +02:00
* evalTokenBuffer . u32 + + = CONST ;
* evalTokenBuffer . u64 + + = ( uint64_t ) w ;
2012-01-18 04:06:46 +02:00
break ;
}
}
2017-04-14 23:52:31 +03:00
else
2012-01-18 04:06:46 +02:00
return expr2 ( ) ;
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
return OK ;
2011-12-27 00:50:27 +02:00
}
//
2012-01-18 04:06:46 +02:00
// Terminals (CONSTs) and parenthesis grouping
2011-12-27 00:50:27 +02:00
//
2012-01-18 04:06:46 +02:00
int expr2 ( void )
{
2017-11-29 15:57:58 +02:00
PTR ptk ;
2012-01-18 04:06:46 +02:00
2017-11-29 15:57:58 +02:00
switch ( * tok + + )
2012-01-18 04:06:46 +02:00
{
case CONST :
2017-11-30 02:52:47 +02:00
ptk . u32 = tok ;
* evalTokenBuffer . u32 + + = CONST ;
* evalTokenBuffer . u64 + + = * ptk . u64 + + ;
tok = ptk . u32 ;
break ;
2017-10-26 15:24:25 +03:00
case FCONST :
2017-11-29 15:57:58 +02:00
ptk . u32 = tok ;
2018-01-21 16:25:06 +02:00
* evalTokenBuffer . u32 + + = FCONST ;
2017-11-29 15:57:58 +02:00
* evalTokenBuffer . u64 + + = * ptk . u64 + + ;
tok = ptk . u32 ;
2012-01-18 04:06:46 +02:00
break ;
case SYMBOL :
2018-06-23 19:57:21 +03:00
{
char * p = string [ * tok + + ] ;
int j = ( * p = = ' . ' ? curenv : 0 ) ;
SYM * sy = lookup ( p , LABEL , j ) ;
2012-01-18 04:06:46 +02:00
if ( sy = = NULL )
2012-11-24 21:48:52 +02:00
sy = NewSymbol ( p , LABEL , j ) ;
2012-01-18 04:06:46 +02:00
2017-11-21 15:54:55 +02:00
* evalTokenBuffer . u32 + + = SYMBOL ;
* evalTokenBuffer . u32 + + = symbolNum ;
2012-11-24 21:48:52 +02:00
symbolPtr [ symbolNum ] = sy ;
symbolNum + + ;
2012-01-18 04:06:46 +02:00
break ;
2018-06-23 19:57:21 +03:00
}
2012-01-18 04:06:46 +02:00
case STRING :
2017-11-21 15:54:55 +02:00
* evalTokenBuffer . u32 + + = CONST ;
2017-11-29 15:57:58 +02:00
* evalTokenBuffer . u64 + + = str_value ( string [ * tok + + ] ) ;
2012-01-18 04:06:46 +02:00
break ;
case ' ( ' :
if ( expr0 ( ) ! = OK )
return ERROR ;
2017-11-29 15:57:58 +02:00
if ( * tok + + ! = ' ) ' )
2017-06-24 03:03:24 +03:00
return error ( " missing closing parenthesis ') ' " ) ;
2012-01-18 04:06:46 +02:00
break ;
case ' [ ' :
if ( expr0 ( ) ! = OK )
return ERROR ;
2017-11-29 15:57:58 +02:00
if ( * tok + + ! = ' ] ' )
2017-06-24 03:03:24 +03:00
return error ( " missing closing bracket ']' " ) ;
2012-01-18 04:06:46 +02:00
2017-11-29 15:57:58 +02:00
break ;
case ' { ' :
if ( expr0 ( ) ! = OK ) // Eat up first parameter (register or immediate)
return ERROR ;
if ( * tok + + ! = ' : ' ) // Demand a ':' there
return error ( " missing colon ':' " ) ;
if ( expr0 ( ) ! = OK ) // Eat up second parameter (register or immediate)
return ERROR ;
if ( * tok + + ! = ' } ' )
return error ( " missing closing brace '}' " ) ;
2012-01-18 04:06:46 +02:00
break ;
case ' $ ' :
2017-11-21 15:54:55 +02:00
* evalTokenBuffer . u32 + + = ACONST ; // Attributed const
* evalTokenBuffer . u32 + + = sloc ; // Current location
2020-09-01 09:44:56 +03:00
* evalTokenBuffer . u32 + + = DEFINED | ( ( orgactive | org68k_active ) ? 0 : cursect ) ; // Store attribs
2012-01-18 04:06:46 +02:00
break ;
case ' * ' :
2017-11-21 15:54:55 +02:00
* evalTokenBuffer . u32 + + = ACONST ; // Attributed const
2012-01-18 04:06:46 +02:00
2013-11-09 17:01:57 +02:00
// pcloc == location at start of line
2017-11-21 15:54:55 +02:00
* evalTokenBuffer . u32 + + = ( orgactive ? orgaddr : pcloc ) ;
2015-02-19 16:56:14 +02:00
// '*' takes attributes of current section, not ABS!
2020-09-01 09:44:56 +03:00
// Also, if we're ORG'd, the symbol is absolute
* evalTokenBuffer . u32 + + = DEFINED | ( ( orgactive | org68k_active ) ? 0 : cursect ) ;
2012-01-18 04:06:46 +02:00
break ;
default :
return error ( " bad expression " ) ;
}
return OK ;
}
2011-12-27 00:50:27 +02:00
2012-01-18 04:06:46 +02:00
//
// Recursive-descent expression analyzer (with some simple speed hacks)
//
2017-11-29 15:57:58 +02:00
int expr ( TOKEN * otk , uint64_t * a_value , WORD * a_attr , SYM * * a_esym )
2012-01-18 04:06:46 +02:00
{
2013-02-12 20:32:56 +02:00
// Passed in values (once derefenced, that is) can all be zero. They are
// there so that the expression analyzer can fill them in as needed. The
2013-03-04 15:36:09 +02:00
// expression analyzer gets its input from the global token pointer "tok",
// and not from anything passed in by the user.
SYM * symbol ;
2012-01-18 04:06:46 +02:00
char * p ;
int j ;
2017-11-29 15:57:58 +02:00
PTR ptk ;
2012-01-18 04:06:46 +02:00
2017-11-29 15:57:58 +02:00
evalTokenBuffer . u32 = otk ; // Set token pointer to 'exprbuf' (direct.c)
2021-06-08 06:42:33 +03:00
// Also set in various other places too (riscasm.c,
// e.g.)
2012-01-18 04:06:46 +02:00
// Optimize for single constant or single symbol.
2020-09-01 09:44:56 +03:00
// Shamus: Seems to me that this could be greatly simplified by 1st
// checking if the first token is a multibyte token, *then*
// checking if there's an EOL after it depending on the actual
// length of the token (multiple vs. single). Otherwise, we have
// the horror show that is the following:
2017-11-29 15:57:58 +02:00
if ( ( tok [ 1 ] = = EOL
& & ( tok [ 0 ] ! = CONST & & tokenClass [ tok [ 0 ] ] ! = SUNARY ) )
2021-06-08 06:42:33 +03:00
| | ( ( tok [ 0 ] = = SYMBOL )
2017-11-29 15:57:58 +02:00
& & ( tokenClass [ tok [ 2 ] ] < UNARY ) )
| | ( ( tok [ 0 ] = = CONST ) & & ( tokenClass [ tok [ 3 ] ] < UNARY ) )
2017-10-08 16:40:02 +03:00
)
2021-06-08 06:42:33 +03:00
// Shamus: Yes, you can parse that out and make some kind of sense of it, but damn, it takes a while to get it and understand the subtle bugs that result from not being careful about what you're checking; especially vis-a-vis naively checking tok[1] for an EOL. O_o
2012-01-18 04:06:46 +02:00
{
2021-06-08 06:42:33 +03:00
if ( * tok = = CONST )
2012-01-18 04:06:46 +02:00
{
2017-11-29 15:57:58 +02:00
ptk . u32 = tok ;
* evalTokenBuffer . u32 + + = * ptk . u32 + + ;
* evalTokenBuffer . u64 + + = * a_value = * ptk . u64 + + ;
2012-01-18 04:06:46 +02:00
* a_attr = ABS | DEFINED ;
2017-11-29 15:57:58 +02:00
tok = ptk . u32 ;
2012-01-18 04:06:46 +02:00
if ( a_esym ! = NULL )
* a_esym = NULL ;
2013-09-12 18:00:35 +03:00
2017-11-29 15:57:58 +02:00
//printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
2017-10-26 15:24:25 +03:00
}
2017-11-21 15:54:55 +02:00
// Not sure that removing float constant here is going to break anything and/or
// make things significantly slower, but having this here seems to cause the
// complexity of the check to get to this part of the parse to go through the
// roof, and dammit, I just don't feel like fighting that fight ATM. :-P
#if 0
2017-11-29 15:57:58 +02:00
else if ( * tok = = FCONST )
2017-10-26 15:24:25 +03:00
{
2017-11-29 15:57:58 +02:00
* evalTokenBuffer . u32 + + = * tok + + ;
2017-11-21 15:54:55 +02:00
* evalTokenBuffer . u64 + + = * a_value = * tok . u64 + + ;
2017-10-26 15:24:25 +03:00
* a_attr = ABS | DEFINED | FLOAT ;
if ( a_esym ! = NULL )
* a_esym = NULL ;
2017-11-29 15:57:58 +02:00
//printf("Quick eval in expr(): CONST = %i, tokenClass[tok[2]] = %i\n", *a_value, tokenClass[*tok]);
2012-01-18 04:06:46 +02:00
}
2017-11-21 15:54:55 +02:00
# endif
2017-11-29 15:57:58 +02:00
else if ( * tok = = ' * ' )
2012-01-18 04:06:46 +02:00
{
2017-11-21 15:54:55 +02:00
* evalTokenBuffer . u32 + + = CONST ;
2012-01-18 04:06:46 +02:00
2020-09-01 09:44:56 +03:00
if ( orgactive | org68k_active )
{
2017-11-21 15:54:55 +02:00
* evalTokenBuffer . u64 + + = * a_value = orgaddr ;
2020-09-01 09:44:56 +03:00
* a_attr = DEFINED ; // We have ORG active, it doesn't belong in a section!
}
2012-01-18 04:06:46 +02:00
else
2020-09-01 09:44:56 +03:00
{
2017-11-21 15:54:55 +02:00
* evalTokenBuffer . u64 + + = * a_value = pcloc ;
2020-09-01 09:44:56 +03:00
// '*' takes attributes of current section, not ABS!
* a_attr = cursect | DEFINED ;
}
2012-01-18 04:06:46 +02:00
if ( a_esym ! = NULL )
* a_esym = NULL ;
2017-11-29 15:57:58 +02:00
tok + + ;
2012-01-18 04:06:46 +02:00
}
2017-11-29 15:57:58 +02:00
else if ( * tok = = STRING | | * tok = = SYMBOL )
2012-01-18 04:06:46 +02:00
{
2017-11-29 15:57:58 +02:00
p = string [ tok [ 1 ] ] ;
2013-03-02 22:22:33 +02:00
j = ( * p = = ' . ' ? curenv : 0 ) ;
2013-03-04 15:36:09 +02:00
symbol = lookup ( p , LABEL , j ) ;
2012-01-18 04:06:46 +02:00
2013-03-04 15:36:09 +02:00
if ( symbol = = NULL )
symbol = NewSymbol ( p , LABEL , j ) ;
2012-01-18 04:06:46 +02:00
2013-03-04 15:36:09 +02:00
symbol - > sattr | = REFERENCED ;
2012-01-18 04:06:46 +02:00
2015-01-16 16:24:24 +02:00
// Check for undefined register equates, but only if it's not part
// of a #<SYMBOL> construct, as it could be that the label that's
// been undefined may later be used as an address label--which
// means it will be fixed up later, and thus, not an error.
if ( ( symbol - > sattre & UNDEF_EQUR ) & & ! riscImmTokenSeen )
2013-03-02 22:22:33 +02:00
{
2017-06-24 03:03:24 +03:00
error ( " undefined register equate '%s' " , symbol - > sname ) ;
2013-03-02 22:22:33 +02:00
}
2017-11-21 15:54:55 +02:00
* evalTokenBuffer . u32 + + = SYMBOL ;
2012-11-24 21:48:52 +02:00
#if 0
2013-03-04 15:36:09 +02:00
* evalTokenBuffer + + = ( TOKEN ) symbol ;
2012-11-24 21:48:52 +02:00
# else
2013-03-04 15:36:09 +02:00
/*
While this approach works , it ' s wasteful . It would be better to use something
that ' s already available , like the symbol " order defined " table ( which needs to
be converted from a linked list into an array ) .
*/
2017-11-21 15:54:55 +02:00
* evalTokenBuffer . u32 + + = symbolNum ;
2013-03-04 15:36:09 +02:00
symbolPtr [ symbolNum ] = symbol ;
2012-11-24 21:48:52 +02:00
symbolNum + + ;
# endif
2012-01-18 04:06:46 +02:00
2020-01-04 18:24:57 +02:00
* a_value = ( symbol - > sattr & DEFINED ? symbol - > svalue : 0 ) ;
* a_attr = ( WORD ) ( symbol - > sattr & ~ GLOBAL ) ;
2012-01-18 04:06:46 +02:00
2017-04-14 23:52:31 +03:00
if ( symbol - > sattre & EQUATEDREG )
2020-01-04 18:24:57 +02:00
{
* a_attr | = RISCREG ; // Mark it as a register, 'cause it is
* a_esym = symbol ;
}
2012-01-18 04:06:46 +02:00
2015-02-19 16:56:14 +02:00
if ( ( symbol - > sattr & ( GLOBAL | DEFINED ) ) = = GLOBAL
& & a_esym ! = NULL )
2013-03-04 15:36:09 +02:00
* a_esym = symbol ;
2013-09-12 18:00:35 +03:00
2017-11-29 15:57:58 +02:00
tok + = 2 ;
2012-01-18 04:06:46 +02:00
}
2018-06-23 19:57:21 +03:00
// Holy hell... This is likely due to the fact that LSR is mistakenly set as a SUNARY type... Need to fix this... !!! FIX !!!
else if ( m6502 )
{
* evalTokenBuffer . u32 + + = * tok + + ;
}
2013-09-12 17:44:40 +03:00
else
{
2015-01-16 16:24:24 +02:00
// Unknown type here... Alert the user!,
2018-06-23 19:57:21 +03:00
error ( " undefined RISC register in expression [token=$%X] " , * tok ) ;
2013-09-12 18:00:35 +03:00
// Prevent spurious error reporting...
2017-11-29 15:57:58 +02:00
tok + + ;
2013-09-12 17:44:40 +03:00
return ERROR ;
}
2012-01-18 04:06:46 +02:00
2017-11-21 15:54:55 +02:00
* evalTokenBuffer . u32 + + = ENDEXPR ;
2012-01-18 04:06:46 +02:00
return OK ;
}
if ( expr0 ( ) ! = OK )
return ERROR ;
2017-11-21 15:54:55 +02:00
* evalTokenBuffer . u32 + + = ENDEXPR ;
2012-01-18 04:06:46 +02:00
return evexpr ( otk , a_value , a_attr , a_esym ) ;
2011-12-27 00:50:27 +02:00
}
//
// Evaluate expression.
2012-01-18 04:06:46 +02:00
// If the expression involves only ONE external symbol, the expression is
2022-10-17 19:49:32 +03:00
// UNDEFINED, but its value includes everything but the symbol value, and
2017-11-21 15:54:55 +02:00
// 'a_esym' is set to the external symbol.
2011-12-27 00:50:27 +02:00
//
2017-11-29 15:57:58 +02:00
int evexpr ( TOKEN * _tk , uint64_t * a_value , WORD * a_attr , SYM * * a_esym )
2012-01-18 04:06:46 +02:00
{
2018-01-30 14:29:52 +02:00
WORD attr ;
2012-01-18 04:06:46 +02:00
SYM * sy ;
2017-10-08 16:40:02 +03:00
uint64_t * sval = evstk ; // (Empty) initial stack
2017-05-02 21:02:47 +03:00
WORD * sattr = evattr ;
SYM * esym = NULL ; // No external symbol involved
WORD sym_seg = 0 ;
2017-11-29 15:57:58 +02:00
PTR tk ;
tk . u32 = _tk ;
2012-01-18 04:06:46 +02:00
2017-11-21 15:54:55 +02:00
while ( * tk . u32 ! = ENDEXPR )
2012-01-18 04:06:46 +02:00
{
2017-11-21 15:54:55 +02:00
switch ( ( int ) * tk . u32 + + )
2012-01-18 04:06:46 +02:00
{
case SYMBOL :
2017-11-21 15:54:55 +02:00
sy = symbolPtr [ * tk . u32 + + ] ;
2017-04-14 23:52:31 +03:00
sy - > sattr | = REFERENCED ; // Set "referenced" bit
2012-01-18 04:06:46 +02:00
if ( ! ( sy - > sattr & DEFINED ) )
{
2012-11-24 21:48:52 +02:00
// Reference to undefined symbol
2012-01-18 04:06:46 +02:00
if ( ! ( sy - > sattr & GLOBAL ) )
2012-11-24 21:48:52 +02:00
{
2012-01-18 04:06:46 +02:00
* a_attr = 0 ;
* a_value = 0 ;
return OK ;
}
2012-11-24 21:48:52 +02:00
if ( esym ! = NULL ) // Check for multiple externals
2012-01-18 04:06:46 +02:00
return error ( seg_error ) ;
esym = sy ;
}
if ( sy - > sattr & DEFINED )
2012-11-24 21:48:52 +02:00
* + + sval = sy - > svalue ; // Push symbol's value
2012-01-18 04:06:46 +02:00
else
2017-04-14 23:52:31 +03:00
* + + sval = 0 ; // 0 for undefined symbols
2012-01-18 04:06:46 +02:00
2012-11-24 21:48:52 +02:00
* + + sattr = ( WORD ) ( sy - > sattr & ~ GLOBAL ) ; // Push attribs
2015-02-19 16:56:14 +02:00
sym_seg = ( WORD ) ( sy - > sattr & TDB ) ;
2012-01-18 04:06:46 +02:00
break ;
2018-01-21 16:25:06 +02:00
2012-01-18 04:06:46 +02:00
case CONST :
2017-11-21 15:54:55 +02:00
* + + sval = * tk . u64 + + ;
2012-11-24 21:48:52 +02:00
* + + sattr = ABS | DEFINED ; // Push simple attribs
2012-01-18 04:06:46 +02:00
break ;
2018-01-21 16:25:06 +02:00
2017-10-26 15:24:25 +03:00
case FCONST :
2018-01-21 16:25:06 +02:00
// Even though it's a double, we can treat it like a uint64_t since
// we're just moving the bits around.
* + + sval = * tk . u64 + + ;
2017-10-26 15:24:25 +03:00
* + + sattr = ABS | DEFINED | FLOAT ; // Push simple attribs
break ;
2018-01-21 16:25:06 +02:00
2012-01-18 04:06:46 +02:00
case ACONST :
2017-11-21 15:54:55 +02:00
* + + sval = * tk . u32 + + ; // Push value
* + + sattr = ( WORD ) * tk . u32 + + ; // Push attribs
2012-01-18 04:06:46 +02:00
break ;
// Binary "+" and "-" matrix:
2017-04-14 23:52:31 +03:00
//
2012-01-18 04:06:46 +02:00
// ABS Sect Other
// ----------------------------
// ABS | ABS | Sect | Other |
// Sect | Sect | [1] | Error |
// Other | Other | Error | [1] |
// ----------------------------
2017-04-14 23:52:31 +03:00
//
2012-01-18 04:06:46 +02:00
// [1] + : Error
// - : ABS
2018-01-21 16:25:06 +02:00
2012-01-18 04:06:46 +02:00
case ' + ' :
2012-11-24 21:48:52 +02:00
- - sval ; // Pop value
2017-04-14 23:52:31 +03:00
- - sattr ; // Pop attrib
2018-01-21 16:25:06 +02:00
// Get FLOAT attribute, if any
attr = ( sattr [ 0 ] | sattr [ 1 ] ) & FLOAT ;
2017-10-26 15:24:25 +03:00
2018-01-21 16:25:06 +02:00
// Since adding an int to a fp value promotes it to a fp value, we
// don't care whether it's first or second; we cast to to a double
// regardless.
if ( attr = = FLOAT )
2017-10-26 15:24:25 +03:00
{
2018-01-21 16:25:06 +02:00
PTR p ;
p . u64 = sval ;
double fpval1 = ( sattr [ 0 ] & FLOAT ? * p . dp : ( double ) * p . i64 ) ;
p . u64 + + ;
double fpval2 = ( sattr [ 1 ] & FLOAT ? * p . dp : ( double ) * p . i64 ) ;
* ( double * ) sval = fpval1 + fpval2 ;
2017-10-26 15:24:25 +03:00
}
else
{
2017-11-21 15:54:55 +02:00
* sval + = sval [ 1 ] ; // Compute value
2017-10-26 15:24:25 +03:00
}
2012-01-18 04:06:46 +02:00
2015-02-19 16:56:14 +02:00
if ( ! ( * sattr & TDB ) )
2018-01-21 16:25:06 +02:00
* sattr = sattr [ 1 ] | attr ;
2015-02-19 16:56:14 +02:00
else if ( sattr [ 1 ] & TDB )
2012-01-18 04:06:46 +02:00
return error ( seg_error ) ;
break ;
2018-01-21 16:25:06 +02:00
2012-01-18 04:06:46 +02:00
case ' - ' :
2012-11-24 21:48:52 +02:00
- - sval ; // Pop value
2017-04-14 23:52:31 +03:00
- - sattr ; // Pop attrib
2018-01-21 16:25:06 +02:00
// Get FLOAT attribute, if any
attr = ( sattr [ 0 ] | sattr [ 1 ] ) & FLOAT ;
2017-10-26 15:24:25 +03:00
2018-01-21 16:25:06 +02:00
// Since subtracting an int to a fp value promotes it to a fp
// value, we don't care whether it's first or second; we cast to to
// a double regardless.
if ( attr = = FLOAT )
2017-10-26 15:24:25 +03:00
{
2018-01-21 16:25:06 +02:00
PTR p ;
p . u64 = sval ;
double fpval1 = ( sattr [ 0 ] & FLOAT ? * p . dp : ( double ) * p . i64 ) ;
p . u64 + + ;
double fpval2 = ( sattr [ 1 ] & FLOAT ? * p . dp : ( double ) * p . i64 ) ;
* ( double * ) sval = fpval1 - fpval2 ;
2017-10-26 15:24:25 +03:00
}
else
{
2018-01-21 16:25:06 +02:00
* sval - = sval [ 1 ] ;
2017-10-26 15:24:25 +03:00
}
2012-01-18 04:06:46 +02:00
2018-01-21 16:25:06 +02:00
* sattr | = attr ; // Inherit FLOAT attribute
2015-02-19 16:56:14 +02:00
attr = ( WORD ) ( * sattr & TDB ) ;
// If symbol1 is ABS, take attributes from symbol2
2012-01-18 04:06:46 +02:00
if ( ! attr )
* sattr = sattr [ 1 ] ;
2015-02-19 16:56:14 +02:00
// Otherwise, they're both TDB and so attributes cancel out
else if ( sattr [ 1 ] & TDB )
* sattr & = ~ TDB ;
2012-01-18 04:06:46 +02:00
break ;
2018-01-21 16:25:06 +02:00
2012-11-24 21:48:52 +02:00
// Unary operators only work on ABS items
2012-01-18 04:06:46 +02:00
case UNMINUS :
2015-02-19 16:56:14 +02:00
if ( * sattr & TDB )
2017-10-26 15:24:25 +03:00
return error ( seg_error ) ;
2012-01-18 04:06:46 +02:00
2017-10-26 15:24:25 +03:00
if ( * sattr & FLOAT )
{
2018-01-21 16:25:06 +02:00
double * dst = ( double * ) sval ;
2017-10-26 15:24:25 +03:00
* dst = - * dst ;
* sattr = ABS | DEFINED | FLOAT ; // Expr becomes absolute
}
else
{
2018-01-21 16:25:06 +02:00
* sval = - ( int64_t ) * sval ;
2017-11-21 15:54:55 +02:00
* sattr = ABS | DEFINED ; // Expr becomes absolute
2017-10-26 15:24:25 +03:00
}
2018-01-21 16:25:06 +02:00
2012-01-18 04:06:46 +02:00
break ;
2018-01-21 16:25:06 +02:00
2018-06-23 19:57:21 +03:00
case UNLT : // Unary < (get the low byte of a word)
if ( * sattr & TDB )
return error ( seg_error ) ;
if ( * sattr & FLOAT )
return error ( noflt_error ) ;
* sval = ( int64_t ) ( ( * sval ) & 0x00FF ) ;
* sattr = ABS | DEFINED ; // Expr becomes absolute
break ;
case UNGT : // Unary > (get the high byte of a word)
if ( * sattr & TDB )
return error ( seg_error ) ;
if ( * sattr & FLOAT )
return error ( noflt_error ) ;
* sval = ( int64_t ) ( ( ( * sval ) > > 8 ) & 0x00FF ) ;
* sattr = ABS | DEFINED ; // Expr becomes absolute
break ;
2012-01-18 04:06:46 +02:00
case ' ! ' :
2015-02-19 16:56:14 +02:00
if ( * sattr & TDB )
2017-10-26 15:24:25 +03:00
return error ( seg_error ) ;
if ( * sattr & FLOAT )
return error ( " floating point numbers not allowed with operator '!'. " ) ;
2012-01-18 04:06:46 +02:00
* sval = ! * sval ;
2012-11-24 21:48:52 +02:00
* sattr = ABS | DEFINED ; // Expr becomes absolute
2012-01-18 04:06:46 +02:00
break ;
2018-01-21 16:25:06 +02:00
2012-01-18 04:06:46 +02:00
case ' ~ ' :
2015-02-19 16:56:14 +02:00
if ( * sattr & TDB )
2017-10-26 15:24:25 +03:00
return error ( seg_error ) ;
if ( * sattr & FLOAT )
return error ( " floating point numbers not allowed with operator '~'. " ) ;
2012-01-18 04:06:46 +02:00
* sval = ~ * sval ;
2012-11-24 21:48:52 +02:00
* sattr = ABS | DEFINED ; // Expr becomes absolute
2012-01-18 04:06:46 +02:00
break ;
2018-01-21 16:25:06 +02:00
2012-11-24 21:48:52 +02:00
// Comparison operators must have two values that
// are in the same segment, but that's the only requirement.
2012-01-18 04:06:46 +02:00
case LE :
2017-04-14 23:52:31 +03:00
sattr - - ;
sval - - ;
2012-01-18 04:06:46 +02:00
if ( ( * sattr & TDB ) ! = ( sattr [ 1 ] & TDB ) )
2017-10-26 15:24:25 +03:00
return error ( seg_error ) ;
2012-01-18 04:06:46 +02:00
2018-01-21 16:25:06 +02:00
// Get FLOAT attribute, if any
attr = ( sattr [ 0 ] | sattr [ 1 ] ) & FLOAT ;
2017-10-26 15:24:25 +03:00
2018-01-21 16:25:06 +02:00
// Cast any ints in the comparison to double, if there's at least
// one double in the comparison.
if ( attr = = FLOAT )
2017-10-26 15:24:25 +03:00
{
2018-01-21 16:25:06 +02:00
PTR p ;
p . u64 = sval ;
double fpval1 = ( sattr [ 0 ] & FLOAT ? * p . dp : ( double ) * p . i64 ) ;
p . u64 + + ;
double fpval2 = ( sattr [ 1 ] & FLOAT ? * p . dp : ( double ) * p . i64 ) ;
* sval = ( fpval1 < = fpval2 ) ;
2017-10-26 15:24:25 +03:00
}
else
{
2018-01-21 16:25:06 +02:00
* sval = ( * sval < = sval [ 1 ] ) ;
2017-10-26 15:24:25 +03:00
}
* sattr = ABS | DEFINED ;
2012-01-18 04:06:46 +02:00
break ;
2018-01-21 16:25:06 +02:00
2012-01-18 04:06:46 +02:00
case GE :
2017-04-14 23:52:31 +03:00
sattr - - ;
sval - - ;
2012-01-18 04:06:46 +02:00
if ( ( * sattr & TDB ) ! = ( sattr [ 1 ] & TDB ) )
2017-10-26 15:24:25 +03:00
return error ( seg_error ) ;
2012-01-18 04:06:46 +02:00
2018-01-21 16:25:06 +02:00
// Get FLOAT attribute, if any
attr = ( sattr [ 0 ] | sattr [ 1 ] ) & FLOAT ;
2017-10-26 15:24:25 +03:00
2018-01-21 16:25:06 +02:00
// Cast any ints in the comparison to double, if there's at least
// one double in the comparison.
if ( attr = = FLOAT )
2017-10-26 15:24:25 +03:00
{
2018-01-21 16:25:06 +02:00
PTR p ;
p . u64 = sval ;
double fpval1 = ( sattr [ 0 ] & FLOAT ? * p . dp : ( double ) * p . i64 ) ;
p . u64 + + ;
double fpval2 = ( sattr [ 1 ] & FLOAT ? * p . dp : ( double ) * p . i64 ) ;
* sval = ( fpval1 > = fpval2 ) ;
2017-10-26 15:24:25 +03:00
}
2018-01-21 16:25:06 +02:00
else
2017-10-26 15:24:25 +03:00
{
2018-01-21 16:25:06 +02:00
* sval = ( * sval > = sval [ 1 ] ) ;
2017-10-26 15:24:25 +03:00
}
2018-01-21 16:25:06 +02:00
* sattr = ABS | DEFINED ;
2012-01-18 04:06:46 +02:00
break ;
2018-01-21 16:25:06 +02:00
2012-01-18 04:06:46 +02:00
case ' > ' :
2017-04-14 23:52:31 +03:00
sattr - - ;
sval - - ;
2012-01-18 04:06:46 +02:00
if ( ( * sattr & TDB ) ! = ( sattr [ 1 ] & TDB ) )
2017-10-26 15:24:25 +03:00
return error ( seg_error ) ;
2012-01-18 04:06:46 +02:00
2018-01-21 16:25:06 +02:00
// Get FLOAT attribute, if any
attr = ( sattr [ 0 ] | sattr [ 1 ] ) & FLOAT ;
2017-10-26 15:24:25 +03:00
2018-01-21 16:25:06 +02:00
// Cast any ints in the comparison to double, if there's at least
// one double in the comparison.
if ( attr = = FLOAT )
2017-10-26 15:24:25 +03:00
{
2018-01-21 16:25:06 +02:00
PTR p ;
p . u64 = sval ;
double fpval1 = ( sattr [ 0 ] & FLOAT ? * p . dp : ( double ) * p . i64 ) ;
p . u64 + + ;
double fpval2 = ( sattr [ 1 ] & FLOAT ? * p . dp : ( double ) * p . i64 ) ;
* sval = ( fpval1 > fpval2 ) ;
2017-10-26 15:24:25 +03:00
}
else
2017-11-21 15:54:55 +02:00
{
2018-01-21 16:25:06 +02:00
* sval = ( * sval > sval [ 1 ] ) ;
2017-10-26 15:24:25 +03:00
}
* sattr = ABS | DEFINED ;
2012-01-18 04:06:46 +02:00
break ;
2018-01-21 16:25:06 +02:00
2012-01-18 04:06:46 +02:00
case ' < ' :
2017-04-14 23:52:31 +03:00
sattr - - ;
sval - - ;
2012-01-18 04:06:46 +02:00
if ( ( * sattr & TDB ) ! = ( sattr [ 1 ] & TDB ) )
2017-10-26 15:24:25 +03:00
return error ( seg_error ) ;
2012-01-18 04:06:46 +02:00
2018-01-21 16:25:06 +02:00
// Get FLOAT attribute, if any
attr = ( sattr [ 0 ] | sattr [ 1 ] ) & FLOAT ;
2017-10-26 15:24:25 +03:00
2018-01-21 16:25:06 +02:00
// Cast any ints in the comparison to double, if there's at least
// one double in the comparison.
if ( attr = = FLOAT )
2017-10-26 15:24:25 +03:00
{
2018-01-21 16:25:06 +02:00
PTR p ;
p . u64 = sval ;
double fpval1 = ( sattr [ 0 ] & FLOAT ? * p . dp : ( double ) * p . i64 ) ;
p . u64 + + ;
double fpval2 = ( sattr [ 1 ] & FLOAT ? * p . dp : ( double ) * p . i64 ) ;
* sval = ( fpval1 < fpval2 ) ;
2017-10-26 15:24:25 +03:00
}
else
{
2018-01-21 16:25:06 +02:00
* sval = ( * sval < sval [ 1 ] ) ;
2017-10-26 15:24:25 +03:00
}
2018-01-21 16:25:06 +02:00
* sattr = ABS | DEFINED ; // Expr forced to ABS
2012-01-18 04:06:46 +02:00
break ;
2018-01-21 16:25:06 +02:00
2012-01-18 04:06:46 +02:00
case NE :
2017-04-14 23:52:31 +03:00
sattr - - ;
sval - - ;
2012-01-18 04:06:46 +02:00
if ( ( * sattr & TDB ) ! = ( sattr [ 1 ] & TDB ) )
2017-10-26 15:24:25 +03:00
return error ( seg_error ) ;
2012-01-18 04:06:46 +02:00
2018-01-21 16:25:06 +02:00
// Get FLOAT attribute, if any
attr = ( sattr [ 0 ] | sattr [ 1 ] ) & FLOAT ;
2017-10-26 15:24:25 +03:00
2018-01-21 16:25:06 +02:00
// Cast any ints in the comparison to double, if there's at least
// one double in the comparison.
if ( attr = = FLOAT )
2017-10-26 15:24:25 +03:00
{
2018-01-21 16:25:06 +02:00
PTR p ;
p . u64 = sval ;
double fpval1 = ( sattr [ 0 ] & FLOAT ? * p . dp : ( double ) * p . i64 ) ;
p . u64 + + ;
double fpval2 = ( sattr [ 1 ] & FLOAT ? * p . dp : ( double ) * p . i64 ) ;
* sval = ( fpval1 ! = fpval2 ) ;
2017-10-26 15:24:25 +03:00
}
else
{
2018-01-21 16:25:06 +02:00
* sval = ( * sval ! = sval [ 1 ] ) ;
2017-10-26 15:24:25 +03:00
}
2018-01-21 16:25:06 +02:00
* sattr = ABS | DEFINED ; // Expr forced to ABS
2012-01-18 04:06:46 +02:00
break ;
2018-01-21 16:25:06 +02:00
2012-01-18 04:06:46 +02:00
case ' = ' :
2017-04-14 23:52:31 +03:00
sattr - - ;
sval - - ;
2012-01-18 04:06:46 +02:00
if ( ( * sattr & TDB ) ! = ( sattr [ 1 ] & TDB ) )
2017-10-26 15:24:25 +03:00
return error ( seg_error ) ;
2012-01-18 04:06:46 +02:00
2018-01-21 16:25:06 +02:00
// Get FLOAT attribute, if any
attr = ( sattr [ 0 ] | sattr [ 1 ] ) & FLOAT ;
2017-10-26 15:24:25 +03:00
2018-01-21 16:25:06 +02:00
// Cast any ints in the comparison to double, if there's at least
// one double in the comparison.
if ( attr = = FLOAT )
2017-10-26 15:24:25 +03:00
{
2018-01-21 16:25:06 +02:00
PTR p ;
p . u64 = sval ;
double fpval1 = ( sattr [ 0 ] & FLOAT ? * p . dp : ( double ) * p . i64 ) ;
p . u64 + + ;
double fpval2 = ( sattr [ 1 ] & FLOAT ? * p . dp : ( double ) * p . i64 ) ;
* sval = ( fpval1 = = fpval2 ) ;
2017-10-26 15:24:25 +03:00
}
else
{
2018-01-21 16:25:06 +02:00
* sval = ( * sval = = sval [ 1 ] ) ;
2017-10-26 15:24:25 +03:00
}
2018-01-21 16:25:06 +02:00
* sattr = ABS | DEFINED ; // Expr forced to ABS
2017-10-26 15:24:25 +03:00
2012-01-18 04:06:46 +02:00
break ;
2018-01-21 16:25:06 +02:00
2017-11-21 15:54:55 +02:00
// All other binary operators must have two ABS items to work with.
// They all produce an ABS value.
2018-02-24 18:27:31 +02:00
// Shamus: Is this true? There's at least one counterexample of legit
// code where this assumption fails to produce correct code.
2012-01-18 04:06:46 +02:00
default :
2017-11-21 15:54:55 +02:00
switch ( ( int ) tk . u32 [ - 1 ] )
2012-01-18 04:06:46 +02:00
{
case ' * ' :
2017-04-14 23:52:31 +03:00
sval - - ;
2018-01-21 16:25:06 +02:00
sattr - - ;
// Get FLOAT attribute, if any
attr = ( sattr [ 0 ] | sattr [ 1 ] ) & FLOAT ;
2017-10-26 15:24:25 +03:00
2018-01-21 16:25:06 +02:00
// Since multiplying an int to a fp value promotes it to a fp
// value, we don't care whether it's first or second; it will
// be cast to a double regardless.
/*
An open question here is do we promote ints to floats as signed or unsigned ? It makes a difference if , say , the int is put in as - 1 but is promoted to a double as $ FFFFFFFFFFFFFFFF - - you get very different results that way ! For now , we promote as signed until proven detrimental otherwise .
*/
if ( attr = = FLOAT )
2017-10-26 15:24:25 +03:00
{
2018-01-21 16:25:06 +02:00
PTR p ;
p . u64 = sval ;
double fpval1 = ( sattr [ 0 ] & FLOAT ? * p . dp : ( double ) * p . i64 ) ;
p . u64 + + ;
double fpval2 = ( sattr [ 1 ] & FLOAT ? * p . dp : ( double ) * p . i64 ) ;
* ( double * ) sval = fpval1 * fpval2 ;
2017-10-26 15:24:25 +03:00
}
else
{
2017-11-21 15:54:55 +02:00
* sval * = sval [ 1 ] ;
2017-10-26 15:24:25 +03:00
}
2012-01-18 04:06:46 +02:00
break ;
2018-01-21 16:25:06 +02:00
2012-01-18 04:06:46 +02:00
case ' / ' :
2017-04-14 23:52:31 +03:00
sval - - ;
2018-01-21 16:25:06 +02:00
sattr - - ;
// Get FLOAT attribute, if any
attr = ( sattr [ 0 ] | sattr [ 1 ] ) & FLOAT ;
2017-11-21 15:54:55 +02:00
2018-01-21 16:25:06 +02:00
if ( attr = = FLOAT )
2017-10-26 15:24:25 +03:00
{
2018-01-21 16:25:06 +02:00
PTR p ;
p . u64 = sval ;
double fpval1 = ( sattr [ 0 ] & FLOAT ? * p . dp : ( double ) * p . i64 ) ;
p . u64 + + ;
double fpval2 = ( sattr [ 1 ] & FLOAT ? * p . dp : ( double ) * p . i64 ) ;
2017-11-21 15:54:55 +02:00
2018-01-21 16:25:06 +02:00
if ( fpval2 = = 0 )
2017-10-26 15:24:25 +03:00
return error ( " divide by zero " ) ;
2017-11-21 15:54:55 +02:00
2018-01-21 16:25:06 +02:00
* ( double * ) sval = fpval1 / fpval2 ;
2017-10-26 15:24:25 +03:00
}
else
{
if ( sval [ 1 ] = = 0 )
return error ( " divide by zero " ) ;
2017-11-21 15:54:55 +02:00
// Compiler is picky here: Without casting these, it
// discards the sign if dividing a negative # by a
// positive one, creating a bad result. :-/
// Definitely a side effect of using uint32_ts intead of
// ints.
* sval = ( int32_t ) sval [ 0 ] / ( int32_t ) sval [ 1 ] ;
2017-10-26 15:24:25 +03:00
}
2018-01-21 16:25:06 +02:00
2012-01-18 04:06:46 +02:00
break ;
2018-01-21 16:25:06 +02:00
2012-01-18 04:06:46 +02:00
case ' % ' :
2017-04-14 23:52:31 +03:00
sval - - ;
2018-01-21 16:25:06 +02:00
sattr - - ;
2017-11-21 15:54:55 +02:00
2017-10-26 15:24:25 +03:00
if ( ( * sattr | sattr [ 1 ] ) & FLOAT )
return error ( " floating point numbers not allowed with operator '%'. " ) ;
2012-01-18 04:06:46 +02:00
if ( sval [ 1 ] = = 0 )
return error ( " mod (%) by zero " ) ;
* sval % = sval [ 1 ] ;
break ;
2018-01-21 16:25:06 +02:00
2012-01-18 04:06:46 +02:00
case SHL :
2017-04-14 23:52:31 +03:00
sval - - ;
sattr - - ; // Pop attrib
2017-11-21 15:54:55 +02:00
2017-10-26 15:24:25 +03:00
if ( ( * sattr | sattr [ 1 ] ) & FLOAT )
return error ( " floating point numbers not allowed with operator '<<'. " ) ;
2017-11-21 15:54:55 +02:00
2012-01-18 04:06:46 +02:00
* sval < < = sval [ 1 ] ;
break ;
2018-01-21 16:25:06 +02:00
2012-01-18 04:06:46 +02:00
case SHR :
2017-04-14 23:52:31 +03:00
sval - - ;
sattr - - ; // Pop attrib
2017-11-21 15:54:55 +02:00
2017-10-26 15:24:25 +03:00
if ( ( * sattr | sattr [ 1 ] ) & FLOAT )
return error ( " floating point numbers not allowed with operator '>>'. " ) ;
2017-11-21 15:54:55 +02:00
2012-01-18 04:06:46 +02:00
* sval > > = sval [ 1 ] ;
break ;
2018-01-21 16:25:06 +02:00
2012-01-18 04:06:46 +02:00
case ' & ' :
2017-04-14 23:52:31 +03:00
sval - - ;
sattr - - ; // Pop attrib
2017-11-21 15:54:55 +02:00
2017-10-26 15:24:25 +03:00
if ( ( * sattr | sattr [ 1 ] ) & FLOAT )
return error ( " floating point numbers not allowed with operator '&'. " ) ;
2017-11-21 15:54:55 +02:00
2012-01-18 04:06:46 +02:00
* sval & = sval [ 1 ] ;
break ;
2018-01-21 16:25:06 +02:00
2012-01-18 04:06:46 +02:00
case ' ^ ' :
2017-04-14 23:52:31 +03:00
sval - - ;
sattr - - ; // Pop attrib
2017-11-21 15:54:55 +02:00
2017-10-26 15:24:25 +03:00
if ( ( * sattr | sattr [ 1 ] ) & FLOAT )
return error ( " floating point numbers not allowed with operator '^'. " ) ;
2017-11-21 15:54:55 +02:00
2012-01-18 04:06:46 +02:00
* sval ^ = sval [ 1 ] ;
break ;
2018-01-21 16:25:06 +02:00
2012-01-18 04:06:46 +02:00
case ' | ' :
2017-04-14 23:52:31 +03:00
sval - - ;
2018-01-21 16:25:06 +02:00
sattr - - ;
2017-11-21 15:54:55 +02:00
2017-10-26 15:24:25 +03:00
if ( ( * sattr | sattr [ 1 ] ) & FLOAT )
return error ( " floating point numbers not allowed with operator '|'. " ) ;
2017-11-21 15:54:55 +02:00
2012-01-18 04:06:46 +02:00
* sval | = sval [ 1 ] ;
break ;
2018-01-21 16:25:06 +02:00
2012-01-18 04:06:46 +02:00
default :
2018-01-21 16:25:06 +02:00
// Bad operator in expression stream (this should never happen!)
interror ( 5 ) ;
2012-01-18 04:06:46 +02:00
}
}
}
if ( esym ! = NULL )
* sattr & = ~ DEFINED ;
if ( a_esym ! = NULL )
* a_esym = esym ;
2018-01-21 16:25:06 +02:00
// Copy value + attrib into return variables
2012-01-18 04:06:46 +02:00
* a_value = * sval ;
2018-01-21 16:25:06 +02:00
* a_attr = * sattr ;
2012-01-18 04:06:46 +02:00
return OK ;
2011-12-27 00:50:27 +02:00
}
2015-01-13 19:06:11 +02:00
2018-02-10 07:08:47 +02:00
//
// Count the # of tokens in the passed in expression
// N.B.: 64-bit constants count as two tokens each
//
uint16_t ExpressionLength ( TOKEN * tk )
{
uint16_t length ;
for ( length = 0 ; tk [ length ] ! = ENDEXPR ; length + + )
{
// Add one to length for 2X tokens, two for 3X tokens
if ( tk [ length ] = = SYMBOL )
length + + ;
else if ( ( tk [ length ] = = CONST ) | | ( tk [ length ] = = FCONST ) )
length + = 2 ;
}
// Add 1 for ENDEXPR
length + + ;
return length ;
}