FUNCTION simplify_generic_expression
(expr : generic_expression) : maths_value;
FUNCTION restore_unary(expr : unary_generic_expression; opnd : generic_expression) : generic_expression; expr.operand := opnd; RETURN (expr); END_FUNCTION; -- restore_unary FUNCTION restore_binary(expr : binary_generic_expression; opd1, opd2 : generic_expression) : generic_expression; expr.operands[1] := opd1; expr.operands[2] := opd2; RETURN (expr); END_FUNCTION; -- restore_binary FUNCTION restore_mulary(expr : multiple_arity_generic_expression; ops : LIST OF generic_expression) : generic_expression; expr.operands := ops; RETURN (expr); END_FUNCTION; -- restore_mulary FUNCTION make_number_literal(nmb : NUMBER) : generic_literal; IF 'INTEGER' IN TYPEOF (nmb) THEN RETURN (make_int_literal(nmb)); END_IF; RETURN (make_real_literal(nmb)); END_FUNCTION; -- make_number_literal; LOCAL types : SET OF STRING := stripped_typeof (expr); v1, v2 : maths_value; vlist : LIST OF maths_value := []; op1, op2 : generic_expression; oplist : LIST OF generic_expression := []; opnds : LIST [2:?] OF generic_expression; n, m : INTEGER; finfun : maths_function_select; boo : BOOLEAN; str : STRING; nmb : NUMBER; END_LOCAL; -- Unwrap the elementary kinds OF literals IF 'INT_LITERAL' IN types THEN RETURN (convert_to_maths_value (expr\int_literal.the_value)); END_IF; IF 'REAL_LITERAL' IN types THEN RETURN (convert_to_maths_value (expr\real_literal.the_value)); END_IF; IF 'BOOLEAN_LITERAL' IN types THEN RETURN (convert_to_maths_value (expr\boolean_literal.the_value)); END_IF; IF 'STRING_LITERAL' IN types THEN RETURN (convert_to_maths_value (expr\string_literal.the_value)); END_IF; IF 'COMPLEX_NUMBER_LITERAL' IN types THEN RETURN (expr); -- No simpler expression available END_IF; IF 'LOGICAL_LITERAL' IN types THEN RETURN (convert_to_maths_value (expr\logical_literal.lit_value)); END_IF; IF 'BINARY_LITERAL' IN types THEN RETURN (convert_to_maths_value (expr\binary_literal.lit_value)); END_IF; IF 'MATHS_ENUM_LITERAL' IN types THEN RETURN (expr\maths_enum_literal.lit_value); END_IF; IF 'REAL_TUPLE_LITERAL' IN types THEN RETURN (convert_to_maths_value (expr\real_tuple_literal.lit_value)); END_IF; IF 'INTEGER_TUPLE_LITERAL' IN types THEN RETURN (convert_to_maths_value (expr\integer_tuple_literal.lit_value)); END_IF; IF 'ATOM_BASED_LITERAL' IN types THEN RETURN (expr\atom_based_literal.lit_value); END_IF; IF 'MATHS_TUPLE_LITERAL' IN types THEN RETURN (convert_to_maths_value (expr\maths_tuple_literal.lit_value)); END_IF; -- Simplify one special class OF literals IF 'MATHS_SPACE' IN types THEN RETURN (simplify_maths_space(expr)); END_IF; -- Simplify one special kind OF expression IF 'FUNCTION_APPLICATION' IN types THEN RETURN (simplify_function_application(expr)); END_IF; -- Separate AND simplify the operands IF 'UNARY_GENERIC_EXPRESSION' IN types THEN v1 := simplify_generic_expression(expr\unary_generic_expression.operand); op1 := convert_to_operand(v1); END_IF; IF 'BINARY_GENERIC_EXPRESSION' IN types THEN v1 := simplify_generic_expression(expr\binary_generic_expression.operands[1]); op1 := convert_to_operand(v1); v2 := simplify_generic_expression(expr\binary_generic_expression.operands[2]); op2 := convert_to_operand(v2); END_IF; IF 'MULTIPLE_ARITY_GENERIC_EXPRESSION' IN types THEN opnds := expr\multiple_arity_generic_expression.operands; REPEAT i := 1 TO SIZEOF (opnds); v1 := simplify_generic_expression(opnds[i]); INSERT (vlist, v1, i-1); INSERT (oplist, convert_to_operand(v1), i-1); END_REPEAT; END_IF; -- Simplify the one kind OF maths_function which derives its operands. IF 'PARALLEL_COMPOSED_FUNCTION' IN types THEN v1 := vlist[1]; n := SIZEOF (vlist); finfun := vlist[n]; REMOVE (vlist, n); REMOVE (vlist, 1); RETURN (make_parallel_composed_function(v1,vlist,finfun)); END_IF; -- Simplify individual kinds OF expressions. It is NOT necessary TO cover all cases. IF ('ABS_EXPRESSION' IN types) AND ('NUMBER' IN TYPEOF (v1)) THEN RETURN (convert_to_maths_value (ABS(v1))); END_IF; IF ('ACOS_EXPRESSION' IN types) AND ('NUMBER' IN TYPEOF (v1)) THEN RETURN (convert_to_maths_value (ACOS(v1))); END_IF; IF 'AND_EXPRESSION' IN types THEN REPEAT i := SIZEOF (vlist) TO 1 BY -1; IF 'BOOLEAN' IN TYPEOF (vlist[i]) THEN boo := vlist[i]; IF NOT boo THEN RETURN (convert_to_maths_value(FALSE)); END_IF; REMOVE (oplist, i); END_IF; END_REPEAT; IF SIZEOF (oplist) = 0 THEN RETURN (convert_to_maths_value(TRUE)); END_IF; IF SIZEOF (oplist) = 1 THEN RETURN (oplist[1]); END_IF; END_IF; IF ('ASIN_EXPRESSION' IN types) AND ('NUMBER' IN TYPEOF (v1)) THEN RETURN (convert_to_maths_value (ASIN(v1))); END_IF; IF ('ATAN_EXPRESSION' IN types) AND ('NUMBER' IN TYPEOF (v1)) AND ('NUMBER' IN TYPEOF (v2)) THEN RETURN (convert_to_maths_value (ATAN(v1,v2))); END_IF; IF ('COMPARISON_EXPRESSION' IN types) AND ( (('NUMBER' IN TYPEOF (v1)) AND ('NUMBER' IN TYPEOF (v2))) OR (('STRING' IN TYPEOF (v1)) AND ('STRING' IN TYPEOF (v2))) OR (('BOOLEAN' IN TYPEOF (v1)) AND ('BOOLEAN' IN TYPEOF (v2))) ) THEN IF 'COMPARISON_EQUAL' IN types THEN boo := bool(v1 = v2); ELSE IF 'COMPARISON_GREATER' IN types THEN boo := bool(v1 > v2); ELSE IF 'COMPARISON_GREATER_EQUAL' IN types THEN boo := bool(v1 >= v2); ELSE IF 'COMPARISON_LESS' IN types THEN boo := bool(v1 < v2); ELSE IF 'COMPARISON_LESS_EQUAL' IN types THEN boo := bool(v1 <= v2); ELSE IF 'COMPARISON_NOT_EQUAL' IN types THEN boo := bool(v1 <> v2); ELSE IF 'LIKE_EXPRESSION' IN types THEN boo := bool(v1 LIKE v2); ELSE RETURN (?); -- Unreachable END_IF; END_IF; END_IF; END_IF; END_IF; END_IF; END_IF; RETURN (convert_to_maths_value (boo)); END_IF; IF 'CONCAT_EXPRESSION' IN types THEN str := ''; REPEAT i := SIZEOF (vlist) TO 1 BY -1; IF 'STRING' IN TYPEOF (vlist[i]) THEN str := vlist[i] + str; REMOVE (oplist, i); ELSE IF LENGTH(str) > 0 THEN INSERT (oplist, make_string_literal(str), i); str := ''; END_IF; END_IF; END_REPEAT; IF SIZEOF (oplist) = 0 THEN RETURN (convert_to_maths_value(str)); END_IF; IF LENGTH(str) > 0 THEN INSERT (oplist, make_string_literal(str), 0); END_IF; IF SIZEOF (oplist) = 1 THEN RETURN (oplist[1]); END_IF; END_IF; IF ('COS_EXPRESSION' IN types) AND ('NUMBER' IN TYPEOF (v1)) THEN RETURN (convert_to_maths_value (COS(v1))); END_IF; IF ('DIV_EXPRESSION' IN types) AND ('NUMBER' IN TYPEOF (v1)) AND ('NUMBER' IN TYPEOF (v2)) THEN RETURN (convert_to_maths_value (v1 DIV v2)); END_IF; IF 'EQUALS_EXPRESSION' IN types THEN opnds := expr\binary_generic_expression.operands; RETURN (convert_to_maths_value (opnds[1] :=: opnds[2])); END_IF; IF ('EXP_EXPRESSION' IN types) AND ('NUMBER' IN TYPEOF (v1)) THEN RETURN (convert_to_maths_value (EXP(v1))); END_IF; IF ('FORMAT_EXPRESSION' IN types) AND ('NUMBER' IN TYPEOF (v1)) AND ('STRING' IN TYPEOF (v2)) THEN RETURN (convert_to_maths_value (FORMAT(v1,v2))); END_IF; IF ('INDEX_EXPRESSION' IN types) AND ('STRING' IN TYPEOF (v1)) AND ('NUMBER' IN TYPEOF (v2)) THEN str := v1; n := v2; RETURN (convert_to_maths_value (str[n])); END_IF; IF ('INT_VALUE_EXPRESSION' IN types) AND ('STRING' IN TYPEOF (v1)) THEN RETURN (convert_to_maths_value (VALUE(v1))); END_IF; IF 'INTERVAL_EXPRESSION' IN types THEN str := ''; IF 'NUMBER' IN TYPEOF (vlist[1]) THEN str := 'NUMBER'; END_IF; IF 'STRING' IN TYPEOF (vlist[1]) THEN str := 'STRING'; END_IF; IF 'BOOLEAN' IN TYPEOF (vlist[1]) THEN str := 'BOOLEAN'; END_IF; IF (LENGTH (str) > 0) AND (str IN TYPEOF (vlist[2])) AND (str IN TYPEOF (vlist[3])) THEN RETURN (convert_to_maths_value ({vlist[1] <= vlist[2] <= vlist[3]})); END_IF; END_IF; IF ('LENGTH_EXPRESSION' IN types) AND ('STRING' IN TYPEOF (v1)) THEN RETURN (convert_to_maths_value (LENGTH(v1))); END_IF; IF ('LOG_EXPRESSION' IN types) AND ('NUMBER' IN TYPEOF (v1)) THEN RETURN (convert_to_maths_value (LOG(v1))); END_IF; IF ('LOG10_EXPRESSION' IN types) AND ('NUMBER' IN TYPEOF (v1)) THEN RETURN (convert_to_maths_value (LOG10(v1))); END_IF; IF ('LOG2_EXPRESSION' IN types) AND ('NUMBER' IN TYPEOF (v1)) THEN RETURN (convert_to_maths_value (LOG2(v1))); END_IF; IF 'MAXIMUM_EXPRESSION' IN types THEN boo := FALSE; REPEAT i := SIZEOF (vlist) TO 1 BY -1; IF 'NUMBER' IN TYPEOF (vlist[i]) THEN IF boo THEN IF nmb < vlist[i] THEN nmb := vlist[i]; END_IF; ELSE nmb := vlist[i]; boo := TRUE; END_IF; REMOVE (oplist, i); END_IF; END_REPEAT; IF SIZEOF (oplist) = 0 THEN RETURN (convert_to_maths_value(nmb)); END_IF; IF boo THEN INSERT (oplist, make_number_literal(nmb), 0); END_IF; END_IF; IF 'MINIMUM_EXPRESSION' IN types THEN boo := FALSE; REPEAT i := SIZEOF (vlist) TO 1 BY -1; IF 'NUMBER' IN TYPEOF (vlist[i]) THEN IF boo THEN IF nmb > vlist[i] THEN nmb := vlist[i]; END_IF; ELSE nmb := vlist[i]; boo := TRUE; END_IF; REMOVE (oplist, i); END_IF; END_REPEAT; IF SIZEOF (oplist) = 0 THEN RETURN (convert_to_maths_value(nmb)); END_IF; IF boo THEN INSERT (oplist, make_number_literal(nmb), 0); END_IF; END_IF; IF ('MINUS_EXPRESSION' IN types) AND ('NUMBER' IN TYPEOF (v1)) AND ('NUMBER' IN TYPEOF (v2)) THEN RETURN (convert_to_maths_value (v1 - v2)); END_IF; IF ('MOD_EXPRESSION' IN types) AND ('NUMBER' IN TYPEOF (v1)) AND ('NUMBER' IN TYPEOF (v2)) THEN RETURN (convert_to_maths_value (v1 MOD v2)); END_IF; IF 'MULT_EXPRESSION' IN types THEN nmb := 1; REPEAT i := SIZEOF (vlist) TO 1 BY -1; IF 'NUMBER' IN TYPEOF (vlist[i]) THEN nmb := nmb * vlist[i]; REMOVE (oplist, i); END_IF; END_REPEAT; IF SIZEOF (oplist) = 0 THEN RETURN (convert_to_maths_value(nmb)); END_IF; IF nmb <> 1 THEN INSERT (oplist, make_number_literal(nmb), 0); END_IF; IF SIZEOF (oplist) = 1 THEN RETURN (oplist[1]); END_IF; END_IF; IF ('NOT_EXPRESSION' IN types) AND ('BOOLEAN' IN TYPEOF (v1)) THEN boo := v1; RETURN (convert_to_maths_value (NOT(boo))); END_IF; IF ('ODD_EXPRESSION' IN types) AND ('INTEGER' IN TYPEOF (v1)) THEN RETURN (convert_to_maths_value (ODD(v1))); END_IF; IF 'OR_EXPRESSION' IN types THEN REPEAT i := SIZEOF (vlist) TO 1 BY -1; IF 'BOOLEAN' IN TYPEOF (vlist[i]) THEN boo := vlist[i]; IF boo THEN RETURN (convert_to_maths_value(TRUE)); END_IF; REMOVE (oplist, i); END_IF; END_REPEAT; IF SIZEOF (oplist) = 0 THEN RETURN (convert_to_maths_value(FALSE)); END_IF; IF SIZEOF (oplist) = 1 THEN RETURN (oplist[1]); END_IF; END_IF; IF 'PLUS_EXPRESSION' IN types THEN nmb := 0; REPEAT i := SIZEOF (vlist) TO 1 BY -1; IF 'NUMBER' IN TYPEOF (vlist[i]) THEN nmb := nmb + vlist[i]; REMOVE (oplist, i); END_IF; END_REPEAT; IF SIZEOF (oplist) = 0 THEN RETURN (convert_to_maths_value(nmb)); END_IF; IF nmb <> 0 THEN INSERT (oplist, make_number_literal(nmb), 0); END_IF; IF SIZEOF (oplist) = 1 THEN RETURN (oplist[1]); END_IF; END_IF; IF ('POWER_EXPRESSION' IN types) AND ('NUMBER' IN TYPEOF (v1)) AND ('NUMBER' IN TYPEOF (v2)) THEN RETURN (convert_to_maths_value (v1 ** v2)); END_IF; IF ('SIN_EXPRESSION' IN types) AND ('NUMBER' IN TYPEOF (v1)) THEN RETURN (convert_to_maths_value (SIN(v1))); END_IF; IF ('SLASH_EXPRESSION' IN types) AND ('NUMBER' IN TYPEOF (v1)) AND ('NUMBER' IN TYPEOF (v2)) THEN RETURN (convert_to_maths_value (v1 / v2)); END_IF; IF ('SQUARE_ROOT_EXPRESSION' IN types) AND ('NUMBER' IN TYPEOF (v1)) THEN RETURN (convert_to_maths_value (SQRT(v1))); END_IF; IF ('SUBSTRING_EXPRESSION' IN types) AND ('STRING' IN TYPEOF (vlist[1])) AND ('NUMBER' IN TYPEOF (vlist[2])) AND ('NUMBER' IN TYPEOF (vlist[3])) THEN str := vlist[1]; n := vlist[2]; m := vlist[3]; RETURN (convert_to_maths_value (str[n:m])); END_IF; IF ('TAN_EXPRESSION' IN types) AND ('NUMBER' IN TYPEOF (v1)) THEN RETURN (convert_to_maths_value (TAN(v1))); END_IF; IF ('UNARY_MINUS_EXPRESSION' IN types) AND ('NUMBER' IN TYPEOF (v1)) THEN nmb := v1; RETURN (convert_to_maths_value (-nmb)); END_IF; IF ('VALUE_EXPRESSION' IN types) AND ('STRING' IN TYPEOF (v1)) THEN RETURN (convert_to_maths_value (VALUE(v1))); END_IF; IF ('XOR_EXPRESSION' IN types) AND ('BOOLEAN' IN TYPEOF (v1)) AND ('BOOLEAN' IN TYPEOF (v2)) THEN RETURN (convert_to_maths_value (v1 XOR v2)); END_IF; -- No special simplification defined, RETURN same WITH simplified operands. IF 'UNARY_GENERIC_EXPRESSION' IN types THEN RETURN (restore_unary(expr,op1)); END_IF; IF 'BINARY_GENERIC_EXPRESSION' IN types THEN RETURN (restore_binary(expr,op1,op2)); END_IF; IF 'MULTIPLE_ARITY_GENERIC_EXPRESSION' IN types THEN RETURN (restore_mulary(expr,oplist)); END_IF; -- Should be unreachable, but FOR safety, RETURN unsimplified expression. RETURN (expr); END_FUNCTION; -- simplify_generic_expression
|