mirror of
https://github.com/QB64-Phoenix-Edition/QB64pe.git
synced 2024-09-20 03:14:45 +00:00
871da4fc12
The regular division symbol always converts its arguments to floating point before dividing, similar to how integer division converts its arguments to integers before dividing.
1134 lines
42 KiB
QBasic
1134 lines
42 KiB
QBasic
|
|
TYPE ParserState
|
|
index AS LONG
|
|
strIndex AS LONG
|
|
num AS ParseNum
|
|
errStr AS STRING
|
|
result AS STRING
|
|
END TYPE
|
|
|
|
'Steve Subs/Functins for _MATH support with CONST
|
|
FUNCTION Evaluate_Expression$ (e$, num AS ParseNum)
|
|
t$ = e$ 'So we preserve our original data, we parse a temp copy of it
|
|
|
|
PreParse t$
|
|
|
|
IF CONST_EVAL_DEBUG THEN _Echo "t$: " + t$
|
|
IF LEFT$(t$, 5) = "ERROR" THEN Evaluate_Expression$ = t$: EXIT FUNCTION
|
|
|
|
'Deal with brackets first
|
|
exp$ = "(" + sp + t$ + sp + ")" 'Starting and finishing brackets for our parse routine.
|
|
IF CONST_EVAL_DEBUG THEN _Echo "exp$: " + exp$
|
|
|
|
DIM Eval_E AS LONG, c AS LONG
|
|
DO
|
|
FindInnerParens exp$, C, Eval_E
|
|
|
|
IF Eval_E > 0 THEN
|
|
IF c = 0 THEN Evaluate_Expression$ = "ERROR - BAD () Count": EXIT FUNCTION
|
|
eval$ = getelements$(exp$, c + 1, Eval_E - 1)
|
|
|
|
ParseExpression2 eval$
|
|
|
|
eval$ = LTRIM$(RTRIM$(eval$))
|
|
IF LEFT$(eval$, 5) = "ERROR" THEN Evaluate_Expression$ = eval$: EXIT FUNCTION
|
|
|
|
' Check if element preceding the parens is a known function name
|
|
' If so, evaluate it now using the argument list we have
|
|
funcOp& = IsFunctionIdentifier(getelement$(exp$, c - 1))
|
|
IF funcOp& > 0 THEN
|
|
eval$ = EvaluateFunction$(funcOp&, eval$)
|
|
IF LEFT$(eval$, 5) = "ERROR" THEN Evaluate_Expression$ = eval$: EXIT FUNCTION
|
|
|
|
c = c - 1
|
|
END IF
|
|
|
|
IF CONST_EVAL_DEBUG THEN _Echo "eval$: " + eval$
|
|
leftele$ = getelements$(exp$, 1, c - 1)
|
|
rightele$ = getelements$(exp$, Eval_E + 1, numelements(exp$))
|
|
|
|
exp$ = leftele$
|
|
IF exp$ <> "" THEN exp$ = exp$ + sp
|
|
exp$ = exp$ + eval$
|
|
IF rightele$ <> "" THEN exp$ = exp$ + sp + rightele$
|
|
END IF
|
|
LOOP UNTIL Eval_E = 0
|
|
|
|
IF CONST_EVAL_DEBUG THEN _Echo "resulting exp$: " + exp$ + ", numelements: " + str$(numelements(exp$))
|
|
IF numelements(exp$) <> 1 THEN
|
|
Evaluate_Expression$ = "ERROR - Invalid characters in expression": EXIT FUNCTION
|
|
END IF
|
|
|
|
IF elementIsString&(exp$) THEN
|
|
num.typ = STRINGTYPE
|
|
num.s = exp$
|
|
ELSE
|
|
num.typ = elementGetNumericValue&(exp$, num.f, num.i, num.ui)
|
|
END IF
|
|
|
|
Evaluate_Expression$ = exp$
|
|
END FUNCTION
|
|
|
|
' Finds an innermost set of parens, returns the element indexes of the parens
|
|
'
|
|
' Gives 0 as startParen if there are no matching parens
|
|
SUB FindInnerParens (exp$, startParen AS LONG, endParen AS LONG)
|
|
startParen = 0
|
|
endParen = 0
|
|
|
|
strIndex = 0
|
|
paren = 0
|
|
DO
|
|
ele$ = getnextelement$(exp$, paren, strIndex)
|
|
|
|
IF paren = -1 THEN EXIT SUB
|
|
IF ele$ = ")" THEN endParen = paren: EXIT DO
|
|
IF paren > 1000 THEN EXIT SUB
|
|
LOOP
|
|
|
|
strIndex = 0
|
|
paren = 0
|
|
DO
|
|
ele$ = getprevelement$(exp$, paren, strIndex)
|
|
|
|
' Skip parens until we reach the ")" we found in the previous search
|
|
IF paren > endParen THEN _CONTINUE
|
|
|
|
IF paren = -1 THEN EXIT SUB
|
|
IF ele$ = "(" THEN startParen = paren: EXIT DO
|
|
IF paren > 1000 THEN EXIT SUB
|
|
LOOP
|
|
END SUB
|
|
|
|
' Grammar (excludes parens)
|
|
'
|
|
' comma_expression := expression ',' expression
|
|
' | expression
|
|
'
|
|
' expression := imp_logical
|
|
' | str_add
|
|
'
|
|
' str_add := primary_str '+' primary_str
|
|
' | primary_str
|
|
'
|
|
' imp_logical := eqv_logical 'IMP' eqv_logical
|
|
' | eqv_logical
|
|
'
|
|
' eqv_logical := xor_logical 'EQV' xor_logical
|
|
' | xor_logical
|
|
'
|
|
' xor_logical := or_logical 'XOR' or_logical
|
|
' | or_logical
|
|
'
|
|
' or_logical := and_logical 'OR' and_logical
|
|
' | and_logical
|
|
'
|
|
' and_logical := not_logical 'AND' not_logical
|
|
' | not_logical
|
|
'
|
|
' not_logical := 'NOT' relation
|
|
' | relation
|
|
'
|
|
' relation := term '<>' term
|
|
' | term '><' term
|
|
' | term '<=' term
|
|
' | term '>=' term
|
|
' | term '=<' term
|
|
' | term '=>' term
|
|
' | term '>' term
|
|
' | term '<' term
|
|
' | term '=' term
|
|
' | term
|
|
'
|
|
' term := mod '+' mod | mod '-' mod | mod
|
|
'
|
|
' mod := int_div 'MOD' int_div | int_div
|
|
'
|
|
' int_div := factor '\' factor | factor
|
|
'
|
|
' factor := unary '*' unary
|
|
' | unary '/' unary
|
|
' | unary
|
|
'
|
|
' unary := '-' exponent | exponent
|
|
'
|
|
' ' Note: NOT is a special case here similar to -, but it is handled in
|
|
' ' PreParse via parenthesis insertion
|
|
' exponent := numeric '^' unary
|
|
' | numeric 'ROOT' unary
|
|
' | numeric
|
|
'
|
|
' numeric := NUMBER | CONST_VAR
|
|
'
|
|
' string := STRING | CONST_VAR
|
|
|
|
FUNCTION CommaExpression&(exp$, state AS ParserState)
|
|
IF CONST_EVAL_DEBUG THEN _Echo "CommaExpression"
|
|
DO
|
|
ele$ = peeknextelement$(exp$, state.index, state.strIndex)
|
|
|
|
DIM tmpIndex AS LONG
|
|
tmpIndex = state.index
|
|
|
|
IF StrExpression&(exp$, state) = 0 THEN
|
|
' If StrExpression consumed any tokens and failed, then it's a real error
|
|
IF state.index <> tmpIndex THEN EXIT FUNCTION
|
|
IF NumericExpression&(exp$, state) = 0 THEN EXIT FUNCTION
|
|
END IF
|
|
|
|
IF state.result <> "" THEN pushelement state.result, ","
|
|
|
|
IF (state.num.typ AND ISSTRING) THEN
|
|
pushelement state.result, state.num.s
|
|
ELSEIF (state.num.typ AND ISFLOAT) THEN
|
|
pushelement state.result, _TRIM$(STR$(state.num.f))
|
|
ELSEIF (state.num.typ AND ISUNSIGNED) THEN
|
|
pushelement state.result, _TRIM$(STR$(state.num.ui)) + "~&&"
|
|
ELSE
|
|
pushelement state.result, _TRIM$(STR$(state.num.i)) + "&&"
|
|
END IF
|
|
|
|
ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
IF ele$ = "," THEN _CONTINUE
|
|
|
|
' If we parsed all the tokens in the string, state.index should be -1
|
|
'
|
|
' If there are still tokens left and it's not a comma, then something
|
|
' is broken
|
|
IF state.index = -1 THEN
|
|
CommaExpression& = -1
|
|
ELSE
|
|
state.errStr = "ERROR - Unexpected element '" + ele$ + "'"
|
|
END IF
|
|
EXIT FUNCTION
|
|
LOOP
|
|
END FUNCTION
|
|
|
|
FUNCTION StrExpression&(exp$, state AS ParserState)
|
|
IF ParseString&(exp$, state) = 0 THEN EXIT FUNCTION
|
|
|
|
DIM s AS STRING
|
|
s = state.num.s
|
|
|
|
DO
|
|
ele$ = peeknextelement$(exp$, state.index, state.strIndex)
|
|
IF ele$ = "+" THEN
|
|
ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
IF ParseString&(exp$, state) = 0 THEN FixupErrorMessage state, "+": EXIT FUNCTION
|
|
|
|
s = elementStringConcat$(s, state.num.s)
|
|
ELSE
|
|
state.num.s = s
|
|
StrExpression& = -1
|
|
EXIT FUNCTION
|
|
END IF
|
|
LOOP
|
|
END FUNCTION
|
|
|
|
FUNCTION ParseString&(exp$, state AS ParserState)
|
|
IF CONST_EVAL_DEBUG THEN _Echo "ParseString"
|
|
ele$ = peeknextelement$(exp$, state.index, state.strIndex)
|
|
|
|
IF elementIsString(ele$) THEN
|
|
ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
|
|
ParseNumSetS state.num, ele$
|
|
|
|
ParseString& = -1
|
|
ELSE
|
|
IF ParseNumHashLookup&(ele$, state) THEN
|
|
IF (state.num.typ AND ISSTRING) = 0 THEN state.errStr = "ERROR - Expecting a string value": EXIT FUNCTION
|
|
|
|
ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
ParseString& = -1
|
|
EXIT FUNCTION
|
|
END IF
|
|
|
|
state.errStr = "ERROR - Unexpected element '" + ele$ + "'"
|
|
END IF
|
|
END FUNCTION
|
|
|
|
FUNCTION NumericExpression&(exp$, state AS ParserState)
|
|
NumericExpression& = LogicalImp&(exp$, state)
|
|
END FUNCTION
|
|
|
|
FUNCTION LogicalImp&(exp$, state AS ParserState)
|
|
IF CONST_EVAL_DEBUG THEN _Echo "LogicalImp"
|
|
IF LogicalEqv&(exp$, state) = 0 THEN EXIT FUNCTION
|
|
|
|
DIM num AS ParseNum
|
|
num = state.num
|
|
|
|
DO
|
|
ele$ = peeknextelement$(exp$, state.index, state.strIndex)
|
|
IF ele$ = "IMP" THEN
|
|
ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
IF LogicalEqv&(exp$, state) = 0 THEN FixupErrorMessage state, "IMP": EXIT FUNCTION
|
|
|
|
IF (num.typ AND ISUNSIGNED) OR (state.num.typ AND ISUNSIGNED) THEN
|
|
ParseNumSetUI num, UINTEGER64TYPE - ISPOINTER, num.ui IMP state.num.ui
|
|
ELSE
|
|
ParseNumSetI num, INTEGER64TYPE - ISPOINTER, num.i IMP state.num.i
|
|
END IF
|
|
ELSE
|
|
state.num = num
|
|
LogicalImp& = -1
|
|
EXIT FUNCTION
|
|
END IF
|
|
LOOP
|
|
END FUNCTION
|
|
|
|
FUNCTION LogicalEqv&(exp$, state AS ParserState)
|
|
IF CONST_EVAL_DEBUG THEN _Echo "LogicalEqv"
|
|
IF LogicalXor&(exp$, state) = 0 THEN EXIT FUNCTION
|
|
|
|
DIM num AS ParseNum
|
|
num = state.num
|
|
|
|
DO
|
|
ele$ = peeknextelement$(exp$, state.index, state.strIndex)
|
|
IF ele$ = "EQV" THEN
|
|
ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
IF LogicalXor&(exp$, state) = 0 THEN FixupErrorMessage state, "EQV": EXIT FUNCTION
|
|
|
|
IF (num.typ AND ISUNSIGNED) OR (state.num.typ AND ISUNSIGNED) THEN
|
|
ParseNumSetUI num, UINTEGER64TYPE - ISPOINTER, num.ui EQV state.num.ui
|
|
ELSE
|
|
ParseNumSetI num, INTEGER64TYPE - ISPOINTER, num.i EQV state.num.i
|
|
END IF
|
|
ELSE
|
|
state.num = num
|
|
LogicalEqv& = -1
|
|
EXIT FUNCTION
|
|
END IF
|
|
LOOP
|
|
END FUNCTION
|
|
|
|
FUNCTION LogicalXor&(exp$, state AS ParserState)
|
|
IF CONST_EVAL_DEBUG THEN _Echo "LogicalXor"
|
|
IF LogicalOr&(exp$, state) = 0 THEN EXIT FUNCTION
|
|
|
|
DIM num AS ParseNum
|
|
num = state.num
|
|
|
|
DO
|
|
ele$ = peeknextelement$(exp$, state.index, state.strIndex)
|
|
IF ele$ = "XOR" THEN
|
|
ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
IF LogicalOr&(exp$, state) = 0 THEN FixupErrorMessage state, "XOR": EXIT FUNCTION
|
|
|
|
IF (num.typ AND ISUNSIGNED) OR (state.num.typ AND ISUNSIGNED) THEN
|
|
ParseNumSetUI num, UINTEGER64TYPE - ISPOINTER, num.ui XOR state.num.ui
|
|
ELSE
|
|
ParseNumSetI num, INTEGER64TYPE - ISPOINTER, num.i XOR state.num.i
|
|
END IF
|
|
ELSE
|
|
state.num = num
|
|
LogicalXor& = -1
|
|
EXIT FUNCTION
|
|
END IF
|
|
LOOP
|
|
END FUNCTION
|
|
|
|
FUNCTION LogicalOr&(exp$, state AS ParserState)
|
|
IF CONST_EVAL_DEBUG THEN _Echo "LogicalOr"
|
|
IF LogicalAnd&(exp$, state) = 0 THEN EXIT FUNCTION
|
|
|
|
DIM num AS ParseNum
|
|
num = state.num
|
|
|
|
DO
|
|
ele$ = peeknextelement$(exp$, state.index, state.strIndex)
|
|
IF ele$ = "OR" THEN
|
|
ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
IF LogicalAnd&(exp$, state) = 0 THEN FixupErrorMessage state, "OR": EXIT FUNCTION
|
|
|
|
IF (num.typ AND ISUNSIGNED) OR (state.num.typ AND ISUNSIGNED) THEN
|
|
ParseNumSetUI num, UINTEGER64TYPE - ISPOINTER, num.ui OR state.num.ui
|
|
ELSE
|
|
ParseNumSetI num, INTEGER64TYPE - ISPOINTER, num.i OR state.num.i
|
|
END IF
|
|
ELSE
|
|
state.num = num
|
|
LogicalOr& = -1
|
|
EXIT FUNCTION
|
|
END IF
|
|
LOOP
|
|
END FUNCTION
|
|
|
|
FUNCTION LogicalAnd&(exp$, state AS ParserState)
|
|
IF CONST_EVAL_DEBUG THEN _Echo "LogicalAnd"
|
|
IF LogicalNot&(exp$, state) = 0 THEN EXIT FUNCTION
|
|
|
|
DIM num AS ParseNum
|
|
num = state.num
|
|
|
|
DO
|
|
ele$ = peeknextelement$(exp$, state.index, state.strIndex)
|
|
IF ele$ = "AND" THEN
|
|
ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
IF LogicalNot&(exp$, state) = 0 THEN FixupErrorMessage state, "AND": EXIT FUNCTION
|
|
|
|
IF (num.typ AND ISUNSIGNED) OR (state.num.typ AND ISUNSIGNED) THEN
|
|
ParseNumSetUI num, UINTEGER64TYPE - ISPOINTER, num.ui AND state.num.ui
|
|
ELSE
|
|
ParseNumSetI num, INTEGER64TYPE - ISPOINTER, num.i AND state.num.i
|
|
END IF
|
|
ELSE
|
|
state.num = num
|
|
LogicalAnd& = -1
|
|
EXIT FUNCTION
|
|
END IF
|
|
LOOP
|
|
END FUNCTION
|
|
|
|
FUNCTION LogicalNot&(exp$, state AS ParserState)
|
|
IF CONST_EVAL_DEBUG THEN _Echo "LogicalNot"
|
|
ele$ = peeknextelement$(exp$, state.index, state.strIndex)
|
|
IF ele$ = "NOT" THEN ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
|
|
IF Relation&(exp$, state) = 0 THEN FixupErrorMessage state, "NOT": EXIT FUNCTION
|
|
|
|
IF ele$ = "NOT" THEN
|
|
IF (num.typ AND ISUNSIGNED) OR (state.num.typ AND ISUNSIGNED) THEN
|
|
ParseNumSetUI state.num, UINTEGER64TYPE - ISPOINTER, NOT state.num.ui
|
|
ELSE
|
|
ParseNumSetI state.num, INTEGER64TYPE - ISPOINTER, NOT state.num.i
|
|
END IF
|
|
END IF
|
|
|
|
LogicalNot& = -1
|
|
END FUNCTION
|
|
|
|
FUNCTION Relation&(exp$, state AS ParserState)
|
|
IF CONST_EVAL_DEBUG THEN _Echo "Relation"
|
|
IF Term&(exp$, state) = 0 THEN EXIT FUNCTION
|
|
|
|
DIM num AS ParseNum
|
|
num = state.num
|
|
|
|
DO
|
|
ele$ = peeknextelement$(exp$, state.index, state.strIndex)
|
|
IF ele$ = "<>" OR ele$ = "><" THEN
|
|
ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
IF Term&(exp$, state) = 0 THEN FixupErrorMessage state, "<>": EXIT FUNCTION
|
|
|
|
IF (num.typ AND ISFLOAT) OR (state.num.typ AND ISFLOAT) THEN
|
|
ParseNumSetF num, FLOATTYPE - ISPOINTER, num.f <> state.num.f
|
|
ELSEIF (num.typ AND ISUNSIGNED) OR (state.num.typ AND ISUNSIGNED) THEN
|
|
ParseNumSetUI num, UINTEGER64TYPE - ISPOINTER, num.ui <> state.num.ui
|
|
ELSE
|
|
ParseNumSetI num, INTEGER64TYPE - ISPOINTER, num.i <> state.num.i
|
|
END IF
|
|
ELSEIF ele$ = ">=" OR ele$ = "=>" THEN
|
|
ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
IF Term&(exp$, state) = 0 THEN FixupErrorMessage state, ">=": EXIT FUNCTION
|
|
|
|
IF (num.typ AND ISFLOAT) OR (state.num.typ AND ISFLOAT) THEN
|
|
ParseNumSetF num, FLOATTYPE - ISPOINTER, num.f >= state.num.f
|
|
ELSEIF (num.typ AND ISUNSIGNED) OR (state.num.typ AND ISUNSIGNED) THEN
|
|
ParseNumSetUI num, UINTEGER64TYPE - ISPOINTER, num.ui >= state.num.ui
|
|
ELSE
|
|
ParseNumSetI num, INTEGER64TYPE - ISPOINTER, num.i >= state.num.i
|
|
END IF
|
|
ELSEIF ele$ = "<=" OR ele$ = "=<" THEN
|
|
ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
IF Term&(exp$, state) = 0 THEN FixupErrorMessage state, "<=": EXIT FUNCTION
|
|
|
|
IF (num.typ AND ISFLOAT) OR (state.num.typ AND ISFLOAT) THEN
|
|
ParseNumSetF num, FLOATTYPE - ISPOINTER, num.f <= state.num.f
|
|
ELSEIF (num.typ AND ISUNSIGNED) OR (state.num.typ AND ISUNSIGNED) THEN
|
|
ParseNumSetUI num, UINTEGER64TYPE - ISPOINTER, num.ui <= state.num.ui
|
|
ELSE
|
|
ParseNumSetI num, INTEGER64TYPE - ISPOINTER, num.i <= state.num.i
|
|
END IF
|
|
ELSEIF ele$ = "<" THEN
|
|
ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
IF Term&(exp$, state) = 0 THEN FixupErrorMessage state, "<": EXIT FUNCTION
|
|
|
|
IF (num.typ AND ISFLOAT) OR (state.num.typ AND ISFLOAT) THEN
|
|
ParseNumSetF num, FLOATTYPE - ISPOINTER, num.f < state.num.f
|
|
ELSEIF (num.typ AND ISUNSIGNED) OR (state.num.typ AND ISUNSIGNED) THEN
|
|
ParseNumSetUI num, UINTEGER64TYPE - ISPOINTER, num.ui < state.num.ui
|
|
ELSE
|
|
ParseNumSetI num, INTEGER64TYPE - ISPOINTER, num.i < state.num.i
|
|
END IF
|
|
ELSEIF ele$ = ">" THEN
|
|
ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
IF Term&(exp$, state) = 0 THEN FixupErrorMessage state, ">": EXIT FUNCTION
|
|
|
|
IF (num.typ AND ISFLOAT) OR (state.num.typ AND ISFLOAT) THEN
|
|
ParseNumSetF num, FLOATTYPE - ISPOINTER, num.f > state.num.f
|
|
ELSEIF (num.typ AND ISUNSIGNED) OR (state.num.typ AND ISUNSIGNED) THEN
|
|
ParseNumSetUI num, UINTEGER64TYPE - ISPOINTER, num.ui > state.num.ui
|
|
ELSE
|
|
ParseNumSetI num, INTEGER64TYPE - ISPOINTER, num.i > state.num.i
|
|
END IF
|
|
ELSEIF ele$ = "=" THEN
|
|
ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
IF Term&(exp$, state) = 0 THEN FixupErrorMessage state, "=": EXIT FUNCTION
|
|
|
|
IF (num.typ AND ISFLOAT) OR (state.num.typ AND ISFLOAT) THEN
|
|
ParseNumSetF num, FLOATTYPE - ISPOINTER, num.f = state.num.f
|
|
ELSEIF (num.typ AND ISUNSIGNED) OR (state.num.typ AND ISUNSIGNED) THEN
|
|
ParseNumSetUI num, UINTEGER64TYPE - ISPOINTER, num.ui = state.num.ui
|
|
ELSE
|
|
ParseNumSetI num, INTEGER64TYPE - ISPOINTER, num.i = state.num.i
|
|
END IF
|
|
ELSE
|
|
state.num = num
|
|
Relation& = -1
|
|
EXIT FUNCTION
|
|
END IF
|
|
LOOP
|
|
END FUNCTION
|
|
|
|
FUNCTION Term&(exp$, state AS ParserState)
|
|
IF CONST_EVAL_DEBUG THEN _Echo "Term"
|
|
IF ParseMod&(exp$, state) = 0 THEN EXIT FUNCTION
|
|
|
|
DIM num AS ParseNum
|
|
num = state.num
|
|
|
|
DO
|
|
ele$ = peeknextelement$(exp$, state.index, state.strIndex)
|
|
IF ele$ = "+" THEN
|
|
ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
IF ParseMod&(exp$, state) = 0 THEN FixupErrorMessage state, "+": EXIT FUNCTION
|
|
|
|
IF (num.typ AND ISFLOAT) OR (state.num.typ AND ISFLOAT) THEN
|
|
ParseNumSetF num, FLOATTYPE - ISPOINTER, num.f + state.num.f
|
|
ELSEIF (num.typ AND ISUNSIGNED) OR (state.num.typ AND ISUNSIGNED) THEN
|
|
ParseNumSetUI num, UINTEGER64TYPE - ISPOINTER, num.ui + state.num.ui
|
|
ELSE
|
|
ParseNumSetI num, INTEGER64TYPE - ISPOINTER, num.i + state.num.i
|
|
END IF
|
|
ELSEIF ele$ = "-" THEN
|
|
ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
IF ParseMod&(exp$, state) = 0 THEN FixupErrorMessage state, "-": EXIT FUNCTION
|
|
|
|
IF (num.typ AND ISFLOAT) OR (state.num.typ AND ISFLOAT) THEN
|
|
ParseNumSetF num, FLOATTYPE - ISPOINTER, num.f - state.num.f
|
|
ELSEIF (num.typ AND ISUNSIGNED) OR (state.num.typ AND ISUNSIGNED) THEN
|
|
ParseNumSetUI num, UINTEGER64TYPE - ISPOINTER, num.ui - state.num.ui
|
|
ELSE
|
|
ParseNumSetI num, INTEGER64TYPE - ISPOINTER, num.i - state.num.i
|
|
END IF
|
|
ELSE
|
|
state.num = num
|
|
Term& = -1
|
|
EXIT FUNCTION
|
|
END IF
|
|
LOOP
|
|
END FUNCTION
|
|
|
|
FUNCTION ParseMod&(exp$, state AS ParserState)
|
|
IF CONST_EVAL_DEBUG THEN _Echo "ParseMod"
|
|
IF IntDiv&(exp$, state) = 0 THEN EXIT FUNCTION
|
|
|
|
DIM num AS ParseNum
|
|
num = state.num
|
|
|
|
DO
|
|
ele$ = peeknextelement$(exp$, state.index, state.strIndex)
|
|
IF ele$ = "MOD" THEN
|
|
ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
IF IntDiv&(exp$, state) = 0 THEN FixupErrorMessage state, "MOD": EXIT FUNCTION
|
|
|
|
IF (num.typ AND ISUNSIGNED) OR (state.num.typ AND ISUNSIGNED) THEN
|
|
ParseNumSetUI num, UINTEGER64TYPE - ISPOINTER, num.ui MOD state.num.ui
|
|
ELSE
|
|
ParseNumSetI num, INTEGER64TYPE - ISPOINTER, num.i MOD state.num.i
|
|
END IF
|
|
ELSE
|
|
IF CONST_EVAL_DEBUG THEN _Echo "ParseMod done!"
|
|
state.num = num
|
|
ParseMod& = -1
|
|
EXIT FUNCTION
|
|
END IF
|
|
LOOP
|
|
END FUNCTIOn
|
|
|
|
FUNCTION IntDiv&(exp$, state AS ParserState)
|
|
IF CONST_EVAL_DEBUG THEN _Echo "IntDiv"
|
|
IF Factor&(exp$, state) = 0 THEN EXIT FUNCTION
|
|
|
|
DIM num AS ParseNum
|
|
num = state.num
|
|
|
|
DO
|
|
ele$ = peeknextelement$(exp$, state.index, state.strIndex)
|
|
IF ele$ = "\" THEN
|
|
ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
IF Factor&(exp$, state) = 0 THEN FixupErrorMessage state, "\": EXIT FUNCTION
|
|
|
|
IF (num.typ AND ISUNSIGNED) OR (state.num.typ AND ISUNSIGNED) THEN
|
|
ParseNumSetUI num, UINTEGER64TYPE - ISPOINTER, num.ui \ state.num.ui
|
|
ELSE
|
|
ParseNumSetI num, INTEGER64TYPE - ISPOINTER, num.i \ state.num.i
|
|
END IF
|
|
ELSE
|
|
IF CONST_EVAL_DEBUG THEN _Echo "IntDiv done!"
|
|
state.num = num
|
|
IntDiv& = -1
|
|
EXIT FUNCTION
|
|
END IF
|
|
LOOP
|
|
END FUNCTION
|
|
|
|
FUNCTION Factor&(exp$, state AS ParserState)
|
|
IF CONST_EVAL_DEBUG THEN _Echo "Factor"
|
|
IF Unary&(exp$, state) = 0 THEN EXIT FUNCTION
|
|
|
|
DIM num As ParseNum
|
|
num = state.num
|
|
|
|
DO
|
|
ele$ = peeknextelement$(exp$, state.index, state.strIndex)
|
|
IF ele$ = "*" THEN
|
|
ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
IF Unary&(exp$, state) = 0 THEN FixupErrorMessage state, "*": EXIT FUNCTION
|
|
|
|
IF (num.typ AND ISFLOAT) OR (state.num.typ AND ISFLOAT) THEN
|
|
ParseNumSetF num, FLOATTYPE - ISPOINTER, num.f * state.num.f
|
|
ELSEIF (num.typ AND ISUNSIGNED) OR (state.num.typ AND ISUNSIGNED) THEN
|
|
ParseNumSetUI num, UINTEGER64TYPE - ISPOINTER, num.ui * state.num.ui
|
|
ELSE
|
|
ParseNumSetI num, INTEGER64TYPE - ISPOINTER, num.i * state.num.i
|
|
END IF
|
|
ELSEIF ele$ = "/" THEN
|
|
ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
IF Unary&(exp$, state) = 0 THEN FixupErrorMessage state, "/": EXIT FUNCTION
|
|
|
|
' Regular division is always done as floating-point
|
|
ParseNumSetF num, FLOATTYPE - ISPOINTER, num.f / state.num.f
|
|
ELSE
|
|
IF CONST_EVAL_DEBUG THEN _Echo "Factor done!"
|
|
state.num = num
|
|
Factor& = -1
|
|
EXIT FUNCTION
|
|
END IF
|
|
LOOP
|
|
END FUNCTION
|
|
|
|
FUNCTION Unary&(exp$, state AS ParserState)
|
|
IF CONST_EVAL_DEBUG THEN _Echo "Unary"
|
|
ele$ = peeknextelement$(exp$, state.index, state.strIndex)
|
|
IF ele$ = "-" THEN ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
|
|
IF Exponent&(exp$, state) = 0 THEN FixupErrorMessage state, "-": EXIT FUNCTION
|
|
|
|
IF ele$ = "-" THEN ParseNumSetI state.num, INTEGER64TYPE - ISPOINTER, -state.num.i
|
|
Unary& = -1
|
|
IF CONST_EVAL_DEBUG THEN _Echo "Unary done!"
|
|
END FUNCTION
|
|
|
|
FUNCTION Exponent&(exp$, state AS ParserState)
|
|
IF CONST_EVAL_DEBUG THEN _Echo "Exponent"
|
|
IF Numeric&(exp$, state) = 0 THEN EXIT FUNCTION
|
|
IF CONST_EVAL_DEBUG THEN _Echo "Check exponent"
|
|
|
|
DIM num AS ParseNum
|
|
num = state.num
|
|
|
|
DO
|
|
ele$ = peeknextelement$(exp$, state.index, state.strIndex)
|
|
IF CONST_EVAL_DEBUG THEN _Echo "Exponent ele! " + ele$
|
|
IF ele$ = "^" THEN
|
|
ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
|
|
' Right associative - 2 ^ 3 ^ 6 is (2 ^ (3 ^ 6))
|
|
'
|
|
' Unary accounts for the special case of `2 ^ -6`, where negative
|
|
' applies before the exponent
|
|
IF Unary&(exp$, state) = 0 THEN FixupErrorMessage state, "^": EXIT FUNCTION
|
|
|
|
IF (num.typ AND ISFLOAT) OR (state.num.typ AND ISFLOAT) THEN
|
|
ParseNumSetF num, FLOATTYPE - ISPOINTER, num.f ^ state.num.f
|
|
ELSEIF (num.typ AND ISUNSIGNED) OR (state.num.typ AND ISUNSIGNED) THEN
|
|
ParseNumSetUI num, UINTEGER64TYPE - ISPOINTER, num.ui ^ state.num.ui
|
|
ELSE
|
|
ParseNumSetI num, INTEGER64TYPE - ISPOINTER, num.i ^ state.num.i
|
|
END IF
|
|
ELSEIF ele$ = "ROOT" THEN
|
|
ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
|
|
' Right associative - 2 ROOT 3 ROOT 6 is (2 ROOT (3 ROOT 6))
|
|
'
|
|
' Unary accounts for the special case of `2 ROOT -6`, where negative
|
|
' applies before the exponent
|
|
IF Unary&(exp$, state) = 0 THEN FixupErrorMessage state, "ROOT": EXIT FUNCTION
|
|
|
|
IF num.f < 0 AND state.num.f >= 1 THEN sig = -1: num.f = -num.f ELSE sig = 1
|
|
expon## = (1## / state.num.f)
|
|
IF expon## <> INT(expon##) AND state.num.f < 1 THEN sig = SGN(num.f): num.f = ABS(num.f)
|
|
|
|
ParseNumSetF num, FLOATTYPE - ISPOINTER, sig * (num.f ^ expon##)
|
|
ELSE
|
|
IF CONST_EVAL_DEBUG THEN _Echo "Exponent done!"
|
|
state.num = num
|
|
Exponent& = -1
|
|
EXIT FUNCTION
|
|
END IF
|
|
LOOP
|
|
END FUNCTION
|
|
|
|
FUNCTION Numeric&(exp$, state AS ParserState)
|
|
IF CONST_EVAL_DEBUG THEN _Echo "Numeric"
|
|
ele$ = peeknextelement$(exp$, state.index, state.strIndex)
|
|
IF CONST_EVAL_DEBUG THEN _Echo "Numeric peek ele: " + ele$
|
|
|
|
IF elementIsNumber(ele$) THEN
|
|
ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
|
|
state.num.typ = elementGetNumericValue(ele$, state.num.f, state.num.i, state.num.ui)
|
|
|
|
Numeric& = -1
|
|
ELSEIF ele$ = "_PI" OR (qb64prefix_set = 1 AND ele$ = "PI") THEN
|
|
ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
|
|
ParseNumSetF state.num, FLOATTYPE - ISPOINTER, 3.14159265358979323846264338327950288##
|
|
Numeric& = -1
|
|
EXIT FUNCTION
|
|
ELSE
|
|
IF ParseNumHashLookup&(ele$, state) THEN
|
|
IF state.num.typ AND ISSTRING THEN state.errStr = "ERROR - String can not be in numeric operation": EXIT FUNCTION
|
|
|
|
ele$ = getnextelement$(exp$, state.index, state.strIndex)
|
|
IF CONST_EVAL_DEBUG THEN _Echo "Consumed ele: " + ele$
|
|
Numeric& = -1
|
|
EXIT FUNCTION
|
|
END IF
|
|
|
|
state.errStr = "ERROR - Unexpected element '" + ele$ + "'"
|
|
state.num.s = ele$
|
|
END IF
|
|
END FUNCTION
|
|
|
|
FUNCTION ParseNumHashLookup&(ele$, state AS ParserState)
|
|
' Attempt hash lookup of existing CONST name
|
|
' CONST can be global or belong to the current sub/function
|
|
hashfound = 0
|
|
|
|
hashname$ = ele$
|
|
unusedSymbol$ = tryRemoveSymbol$(hashname$)
|
|
|
|
IF CONST_EVAL_DEBUG THEN _Echo "hash lookup: " + hashname$
|
|
IF CONST_EVAL_DEBUG THEN _Echo "unused symbol: " + hashname$
|
|
hashchkflags = HASHFLAG_CONSTANT
|
|
hashres = HashFindRev(hashname$, hashchkflags, hashresflags, hashresref)
|
|
DO WHILE hashres
|
|
IF constsubfunc(hashresref) = subfuncn OR constsubfunc(hashresref) = 0 THEN
|
|
IF constdefined(hashresref) THEN
|
|
hashfound = 1
|
|
EXIT DO
|
|
END IF
|
|
END IF
|
|
IF hashres <> 1 THEN hashres = HashFindCont(hashresflags, hashresref) ELSE hashres = 0
|
|
LOOP
|
|
|
|
IF CONST_EVAL_DEBUG THEN _Echo "Hashfound: " + str$(hashfound)
|
|
IF hashfound THEN
|
|
IF CONST_EVAL_DEBUG THEN _Echo "is string: " + str$(consttype(hashresref) AND ISSTRING)
|
|
|
|
IF consttype(hashresref) AND ISSTRING THEN
|
|
ParseNumSetS state.num, conststring(hashresref)
|
|
ELSEIF consttype(hashresref) AND ISFLOAT THEN
|
|
ParseNumSetF state.num, consttype(hashresref), constfloat(hashresref)
|
|
ELSE
|
|
IF consttype(hashresref) AND ISUNSIGNED THEN
|
|
ParseNumSetUI state.num, consttype(hashresref), constuinteger(hashresref)
|
|
ELSE
|
|
ParseNumSetI state.num, consttype(hashresref), constinteger(hashresref)
|
|
END IF
|
|
END IF
|
|
|
|
IF CONST_EVAL_DEBUG THEN _Echo "Found! value: " + str$(state.num.f) + state.num.s
|
|
|
|
ParseNumHashLookup& = -1
|
|
EXIT FUNCTION
|
|
END IF
|
|
END FUNCTION
|
|
|
|
SUB ParseNumSetF (num AS ParseNum, t AS LONG, f AS _FLOAT)
|
|
num.s = ""
|
|
num.f = f
|
|
num.i = f
|
|
num.ui = f
|
|
num.typ = t
|
|
END SUB
|
|
|
|
SUB ParseNumSetI (num AS ParseNum, t AS LONG, i AS _INTEGER64)
|
|
num.s = ""
|
|
num.i = i
|
|
num.ui = i
|
|
num.f = i
|
|
num.typ = t
|
|
END SUB
|
|
|
|
SUB ParseNumSetUI (num AS ParseNum, t AS LONG, ui AS _UNSIGNED _INTEGER64)
|
|
num.ui = ui
|
|
num.i = ui
|
|
num.f = ui
|
|
num.typ = t
|
|
END SUB
|
|
|
|
SUB ParseNumSetS (num AS ParseNum, s AS STRING)
|
|
num.s = s
|
|
num.typ = STRINGTYPE
|
|
END SUB
|
|
|
|
SUB FixupErrorMessage (state AS ParserState, op AS STRING)
|
|
IF state.num.s = "" THEN state.errStr = "ERROR - Expected variable/value after '" + op + "'"
|
|
END SUB
|
|
|
|
SUB ParseExpression2 (exp$)
|
|
exp$ = DWD(exp$)
|
|
|
|
DIM state AS ParserState
|
|
state.index = 0
|
|
state.strIndex = 0
|
|
state.num.f = 0
|
|
state.num.i = 0
|
|
state.num.typ = 0
|
|
state.errStr = ""
|
|
state.result = ""
|
|
|
|
res& = CommaExpression&(exp$, state)
|
|
IF CONST_EVAL_DEBUG THEN _Echo "res: " + STR$(res&)
|
|
IF CONST_EVAL_DEBUG THEN _Echo "resulting string: " + state.result
|
|
IF CONST_EVAL_DEBUG THEN _Echo "resulting err: " + state.errStr
|
|
|
|
IF res& = 0 THEN
|
|
exp$ = state.errStr
|
|
ELSE
|
|
exp$ = state.result
|
|
END IF
|
|
END SUB
|
|
|
|
SUB Set_ConstFunctions
|
|
REDIM ConstFuncs(10000) AS ConstFunction
|
|
|
|
'Functions with PL 10
|
|
i = i + 1: ConstFuncs(i).nam = "_PI": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "_ACOS": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "_ASIN": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "_ARCSEC": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "_ARCCSC": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "_ARCCOT": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "_SECH": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "_CSCH": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "_COTH": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "COS": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "SIN": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "TAN": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "LOG": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "EXP": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "ATN": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "SQR": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "_D2R": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "_D2G": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "_R2D": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "_R2G": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "_G2D": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "_G2R": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "ABS": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "SGN": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "INT": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "_ROUND": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "_CEIL": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "FIX": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "_SEC": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "_CSC": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "_COT": ConstFuncs(i).ArgCount = 1
|
|
|
|
i = i + 1: ConstFuncs(i).nam = "_RGB32": ConstFuncs(i).ArgCount = -1
|
|
i = i + 1: ConstFuncs(i).nam = "_RGBA32": ConstFuncs(i).ArgCount = 4
|
|
i = i + 1: ConstFuncs(i).nam = "_RGBA": ConstFuncs(i).ArgCount = 5
|
|
i = i + 1: ConstFuncs(i).nam = "_RGB": ConstFuncs(i).ArgCount = 4
|
|
i = i + 1: ConstFuncs(i).nam = "_RED32": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "_GREEN32": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "_BLUE32": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "_ALPHA32": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "_RED": ConstFuncs(i).ArgCount = 2
|
|
i = i + 1: ConstFuncs(i).nam = "_GREEN": ConstFuncs(i).ArgCount = 2
|
|
i = i + 1: ConstFuncs(i).nam = "_BLUE": ConstFuncs(i).ArgCount = 2
|
|
i = i + 1: ConstFuncs(i).nam = "_ALPHA": ConstFuncs(i).ArgCount = 2
|
|
|
|
i = i + 1: ConstFuncs(i).nam = "CHR$": ConstFuncs(i).ArgCount = 1
|
|
i = i + 1: ConstFuncs(i).nam = "ASC": ConstFuncs(i).ArgCount = -1
|
|
|
|
REDIM _PRESERVE ConstFuncs(i) AS ConstFunction
|
|
END SUB
|
|
|
|
' args should be a element list of the arguments separated by commas
|
|
'
|
|
' Each argument should be a single element
|
|
FUNCTION EvaluateFunction$ (p, args AS STRING)
|
|
DIM n1 AS _FLOAT, nstr AS STRING
|
|
Dim argCount As Long, args(5) As ParseNum, origArgs(5) As String
|
|
|
|
|
|
argCount = countFunctionElements(args)
|
|
|
|
IF CONST_EVAL_DEBUG THEN _Echo "argCount: " + str$(argCount)
|
|
|
|
IF ConstFuncs(p).ArgCount > 0 AND argCount <> ConstFuncs(p).ArgCount THEN
|
|
EvaluateFunction$ = "ERROR - Wrong number of arguments provided to " + ConstFuncs(p).nam + "!"
|
|
EXIT FUNCTION
|
|
END IF
|
|
|
|
FOR i = 1 to argCount
|
|
ele$ = getelement$(args, 1 + (i - 1) * 2)
|
|
origArgs(i) = ele$
|
|
|
|
IF CONST_EVAL_DEBUG THEN _Echo "arg is string: " + STR$(elementIsString(ele$)) + ", argCount: " + STR$(ConstFuncs(p).ArgCount)
|
|
|
|
IF elementIsNumber(ele$) THEN
|
|
' skip the commas
|
|
args(i).typ = elementGetNumericValue&(ele$, args(i).f, args(i).i, args(i).ui)
|
|
ELSEIF elementIsString(ele$) AND ConstFuncs(p).ArgCount < 0 THEN ' positive arg count means arguments are all numbers
|
|
args(i).typ = elementGetStringValue&(ele$, args(i).s)
|
|
ELSE
|
|
EvaluateFunction$ = "ERROR - Unexpected argument: " + ele$
|
|
EXIT FUNCTION
|
|
END IF
|
|
|
|
IF CONST_EVAL_DEBUG THEN _Echo "Argument: " + str$(args(i).f) + ", str: " + getelement$(args, 1 + (i - 1) * 2)
|
|
NEXT
|
|
|
|
' Default type, some functions return different types
|
|
typ& = FLOATTYPE - ISPOINTER
|
|
|
|
SELECT CASE ConstFuncs(p).nam 'Depending on our operator..
|
|
CASE "_PI"
|
|
'Future compatible in case something ever stores extra digits for PI
|
|
n1 = 3.14159265358979323846264338327950288## * args(1).f
|
|
|
|
CASE "_ACOS": n1 = _ACOS(args(1).f)
|
|
CASE "_ASIN": n1 = _ASIN(args(1).f)
|
|
CASE "_ARCSEC"
|
|
IF ABS(args(1).f) < 1 THEN EvaluateFunction$ = "ERROR - ABS(_ARCSEC) value < 1": EXIT FUNCTION
|
|
n1 = _ARCSEC(args(1).f)
|
|
|
|
CASE "_ARCCSC"
|
|
IF ABS(args(1).f) < 1 THEN EvaluateFunction$ = "ERROR - ABS(_ARCCSC) value < 1": EXIT FUNCTION
|
|
n1 = _ARCCSC(args(1).f)
|
|
|
|
CASE "_ARCCOT": n1 = _ARCCOT(args(1).f)
|
|
CASE "_SECH": n1 = _SECH(args(1).f)
|
|
CASE "_CSCH": n1 = _CSCH(args(1).f)
|
|
CASE "_COTH": n1 = _COTH(args(1).f)
|
|
CASE "_RGB32"
|
|
typ& = INTEGER64TYPE - ISPOINTER
|
|
SELECT CASE argCount
|
|
CASE 1
|
|
n1 = _RGB32(args(1).ui, args(1).ui, args(1).ui)
|
|
|
|
CASE 2
|
|
n1 = _RGB32(args(1).ui, args(1).ui, args(1).ui, args(2).ui)
|
|
|
|
CASE 3
|
|
n1 = _RGB32(args(1).ui, args(2).ui, args(3).ui)
|
|
|
|
CASE 4
|
|
n1 = _RGB32(args(1).ui, args(2).ui, args(3).ui, args(4).ui)
|
|
|
|
CASE ELSE
|
|
EvaluateFunction$ = "ERROR - Invalid comma count (" + args + ")"
|
|
EXIT FUNCTION
|
|
END SELECT
|
|
|
|
CASE "_RGBA32"
|
|
typ& = INTEGER64TYPE - ISPOINTER
|
|
'we have to have 3 commas; not more, not less.
|
|
n1 = _RGBA32(args(1).ui, args(2).ui, args(3).ui, args(4).ui)
|
|
|
|
CASE "_RGB"
|
|
typ& = INTEGER64TYPE - ISPOINTER
|
|
'we have to have 3 commas; not more, not less.
|
|
SELECT CASE args(4).ui
|
|
CASE 0 TO 2, 7 TO 13, 256, 32 'these are the good screen values
|
|
CASE ELSE
|
|
EvaluateFunction$ = "ERROR - Invalid Screen Mode (" + STR$(args(4).ui) + ")": EXIT FUNCTION
|
|
END SELECT
|
|
t = _NEWIMAGE(1, 1, args(4).ui)
|
|
n1 = _RGB(args(1).ui, args(2).ui, args(3).ui, t)
|
|
_FREEIMAGE t
|
|
|
|
CASE "_RGBA"
|
|
typ& = INTEGER64TYPE - ISPOINTER
|
|
'we have to have 4 commas; not more, not less.
|
|
SELECT CASE args(5).ui
|
|
CASE 0 TO 2, 7 TO 13, 256, 32 'these are the good screen values
|
|
CASE ELSE
|
|
EvaluateFunction$ = "ERROR - Invalid Screen Mode (" + STR$(args(5).ui) + ")": EXIT FUNCTION
|
|
END SELECT
|
|
t = _NEWIMAGE(1, 1, args(5).ui)
|
|
n1 = _RGBA(args(1).ui, args(2).ui, args(3).ui, args(4).ui, t)
|
|
_FREEIMAGE t
|
|
|
|
CASE "_RED", "_GREEN", "_BLUE", "_ALPHA"
|
|
typ& = INTEGER64TYPE - ISPOINTER
|
|
SELECT CASE args(2).i
|
|
CASE 0 TO 2, 7 TO 13, 256, 32 'these are the good screen values
|
|
CASE ELSE
|
|
EvaluateNumbers$ = "ERROR - Invalid Screen Mode (" + STR$(args(2).i) + ")": EXIT FUNCTION
|
|
END SELECT
|
|
t = _NEWIMAGE(1, 1, args(2).i)
|
|
SELECT CASE ConstFuncs(p).nam
|
|
CASE "_RED": n1 = _RED(args(1).i, t)
|
|
CASE "_BLUE": n1 = _BLUE(args(1).i, t)
|
|
CASE "_GREEN": n1 = _GREEN(args(1).i, t)
|
|
CASE "_ALPHA": n1 = _ALPHA(args(1).i, t)
|
|
END SELECT
|
|
_FREEIMAGE t
|
|
|
|
CASE "_RED32", "_GREEN32", "_BLUE32", "_ALPHA32"
|
|
typ& = INTEGER64TYPE - ISPOINTER
|
|
SELECT CASE ConstFuncs(p).nam
|
|
CASE "_RED32": n1 = _RED32(args(1).i)
|
|
CASE "_BLUE32": n1 = _BLUE32(args(1).i)
|
|
CASE "_GREEN32": n1 = _GREEN32(args(1).i)
|
|
CASE "_ALPHA32": n1 = _ALPHA32(args(1).i)
|
|
END SELECT
|
|
|
|
CASE "COS": n1 = COS(args(1).f)
|
|
CASE "SIN": n1 = SIN(args(1).f)
|
|
CASE "TAN": n1 = TAN(args(1).f)
|
|
CASE "LOG": n1 = LOG(args(1).f)
|
|
CASE "EXP": n1 = EXP(args(1).f)
|
|
CASE "ATN": n1 = ATN(args(1).f)
|
|
CASE "SQR": n1 = SQR(args(1).f)
|
|
CASE "_D2R": n1 = 0.0174532925 * args(1).f
|
|
CASE "_D2G": n1 = 1.1111111111 * args(1).f
|
|
CASE "_R2D": n1 = 57.2957795 * args(1).f
|
|
CASE "_R2G": n1 = 0.015707963 * args(1).f
|
|
CASE "_G2D": n1 = 0.9 * args(1).f
|
|
CASE "_G2R": n1 = 63.661977237 * args(1).f
|
|
CASE "ABS": n1 = ABS(args(1).f): typ& = INTEGER64TYPE - ISPOINTER
|
|
CASE "SGN": n1 = SGN(args(1).f): typ& = INTEGER64TYPE - ISPOINTER
|
|
CASE "INT": n1 = INT(args(1).f): typ& = INTEGER64TYPE - ISPOINTER
|
|
CASE "_ROUND": n1 = _ROUND(args(1).f): typ& = INTEGER64TYPE - ISPOINTER
|
|
CASE "_CEIL": n1 = _CEIL(args(1).f): typ& = INTEGER64TYPE - ISPOINTER
|
|
CASE "FIX": n1 = FIX(args(1).f): typ& = INTEGER64TYPE - ISPOINTER
|
|
CASE "_SEC": n1 = _SEC(args(1).f)
|
|
CASE "_CSC": n1 = _CSC(args(1).f)
|
|
CASE "_COT": n1 = _COT(args(1).f)
|
|
|
|
CASE "CHR$":
|
|
IF args(1).ui > 255 THEN EvaluateFunction$ = "ERROR - Invalid argument to CHR$, valid range is 0-255: " + origArgs(1): EXIT FUNCTION
|
|
|
|
nstr = CHR$(args(1).ui)
|
|
typ& = STRINGTYPE
|
|
|
|
CASE "ASC":
|
|
IF argCount < 1 OR argCount > 2 THEN EvaluateNumbers$ = "ERROR - Wrong number of arguments provided to ASC$": EXIT FUNCTION
|
|
IF (args(1).typ AND ISSTRING) = 0 THEN EvaluateFunction$ = "ERROR - Unexpected argument: '" + origArgs(1) + "'": EXIT FUNCTION
|
|
|
|
IF argCount = 1 THEN
|
|
n1 = ASC(args(1).s)
|
|
ELSE
|
|
IF args(2).typ AND ISSTRING THEN EvaluateFunction$ = "ERROR - Expected integer argument: '" + origArgs(2) + "'": EXIT FUNCTION
|
|
|
|
n1 = ASC(args(1).s, args(2).i)
|
|
END IF
|
|
|
|
typ& = INTEGER64TYPE - ISPOINTER
|
|
END SELECT
|
|
|
|
IF typ& AND ISSTRING THEN
|
|
EvaluateFunction$ = createElementString$(nstr)
|
|
ELSEIF typ& AND ISFLOAT THEN
|
|
EvaluateFunction$ = _TRIM$(STR$(n1))
|
|
ELSE
|
|
n&& = n1
|
|
EvaluateFunction$ = _TRIM$(STR$(n&&)) + "&&"
|
|
END IF
|
|
END FUNCTION
|
|
|
|
FUNCTION DWD$ (exp$) 'Deal With Duplicates
|
|
'To deal with duplicate operators in our code.
|
|
'Such as -- becomes a +
|
|
'++ becomes a +
|
|
'+- becomes a -
|
|
'-+ becomes a -
|
|
t$ = exp$
|
|
FOR l = 1 TO numelements(t$) - 1
|
|
ele$ = getelement$(t$, l)
|
|
nextele$ = getelement$(t$, l + 1)
|
|
|
|
IF ele$ = "+" AND nextele$ = "+" THEN
|
|
removeelement t$, l
|
|
l = l - 1
|
|
ELSEIF ele$ = "-" AND nextele$ = "-" THEN
|
|
removeelements t$, l, l + 1, 0
|
|
insertelements t$, l - 1, "+"
|
|
l = l - 1
|
|
ELSEIF ele$ = "-" AND nextele$ = "+" THEN
|
|
removeelement t$, l + 1
|
|
l = l - 1
|
|
ELSEIF ele$ = "+" AND nextele$ = "-" THEN
|
|
removeelement t$, l
|
|
l = l - 1
|
|
END IF
|
|
NEXT
|
|
DWD$ = t$
|
|
END FUNCTION
|
|
|
|
SUB PreParse (e$)
|
|
t$ = e$ 'preserve the original string
|
|
|
|
t$ = eleucase$(t$)
|
|
IF t$ = "" THEN e$ = "ERROR - NULL string; nothing to evaluate": EXIT SUB
|
|
|
|
'ERROR CHECK by counting our brackets
|
|
count = numelements(t$)
|
|
FOR l = 1 to count
|
|
ele$ = getelement$(t$, l)
|
|
IF ele$ = "(" THEN c = c + 1
|
|
IF ele$ = ")" THEN c = c - 1
|
|
|
|
IF c < 0 THEN e$ = "ERROR - Bad Parenthesis, too many )": EXIT SUB
|
|
NEXT
|
|
IF c <> 0 THEN e$ = "ERROR - Bad Parenthesis": EXIT SUB
|
|
|
|
'Modify so that NOT will process properly
|
|
FOR l = 1 to numelements(t$)
|
|
'FIXME: This doesn't account for `x ^ NOT y + 2`, where it evaluates as `x ^ (NOT y) + 2`
|
|
IF getelement$(t$, l) = "NOT" THEN
|
|
FOR l2 = l to numelements(t$)
|
|
ele$ = getelement$(t$, l2)
|
|
IF ele$ = "AND" OR ele$ = "OR" OR ele$ = "XOR" OR ele$ = "EQV" OR ele$ = "IMP" OR ele$ = ")" THEN
|
|
EXIT FOR
|
|
END IF
|
|
NEXT
|
|
|
|
insertelements t$, l2 - 1, ")"
|
|
insertelements t$, l - 1, "("
|
|
l = l + 1
|
|
END IF
|
|
NEXT
|
|
|
|
e$ = t$
|
|
END SUB
|
|
|
|
|
|
' Returns 0 if given element is not the name of a function
|
|
' If it is a function, the ConstFuncs() array index of the function is returned
|
|
FUNCTION IsFunctionIdentifier&(ele$)
|
|
FOR i = 1 TO UBOUND(ConstFuncs)
|
|
IF ele$ = ConstFuncs(i).nam THEN
|
|
IsFunctionIdentifier& = i
|
|
EXIT FUNCTION
|
|
ELSE
|
|
IF LEFT$(ConstFuncs(i).nam, 1) = "_" AND qb64prefix_set = 1 THEN
|
|
'try without prefix
|
|
IF ele$ = MID$(ConstFuncs(i).nam, 2) THEN
|
|
IsFunctionIdentifier& = i
|
|
EXIT FUNCTION
|
|
END IF
|
|
END IF
|
|
END IF
|
|
NEXT
|
|
END FUNCTION
|