#include <base/Application.h>
#include <base/UnsignedInteger.h>
#include <base/string/FormatOutputStream.h>
#include <base/string/StringOutputStream.h>
#include <base/math/ExpressionParser.h>
#include <base/math/Math.h>
#include <base/Random.h>
using namespace com::azure::dev::base;
private:
static const unsigned int MAJOR_VERSION = 1;
static const unsigned int MINOR_VERSION = 0;
bool simple = false;
bool parsed = false;
enum Command {
COMMAND_VERSION,
COMMAND_HELP,
COMMAND_CONSTANTS,
COMMAND_FUNCTIONS,
COMMAND_EVALUATE
};
enum Constant {
CONSTANT_E,
CONSTANT_LN2,
CONSTANT_PI,
CONSTANT_SQRT2,
CONSTANT_EULER
};
struct Identifier {
unsigned int id;
};
enum Function {
FUNCTION_RANDOM,
FUNCTION_ABS,
FUNCTION_SIGN,
FUNCTION_FRAC,
FUNCTION_FLOOR,
FUNCTION_CEIL,
FUNCTION_ROUND,
FUNCTION_SQR,
FUNCTION_SQRT,
FUNCTION_EXP,
FUNCTION_LN,
FUNCTION_LOG,
FUNCTION_LOG2,
FUNCTION_SIN,
FUNCTION_ASIN,
FUNCTION_COS,
FUNCTION_ACOS,
FUNCTION_TAN,
FUNCTION_ATAN,
FUNCTION_COTAN,
FUNCTION_ACOTAN,
FUNCTION_COSEC,
FUNCTION_ACOSEC,
FUNCTION_SEC,
FUNCTION_ASEC,
FUNCTION_EXSEC,
FUNCTION_AEXSEC,
FUNCTION_VERS,
FUNCTION_AVERS,
FUNCTION_HAV,
FUNCTION_AHAV,
FUNCTION_COVERS,
FUNCTION_ACOVERS,
FUNCTION_SINH,
FUNCTION_ASINH,
FUNCTION_COSH,
FUNCTION_ACOSH,
FUNCTION_TANH,
FUNCTION_ATANH,
FUNCTION_COTANH,
FUNCTION_ACOTANH,
FUNCTION_SECH,
FUNCTION_ASECH,
FUNCTION_COSECH,
FUNCTION_ACOSECH,
FUNCTION_HYPOT,
FUNCTION_PWR,
FUNCTION_AVG,
FUNCTION_MIN,
FUNCTION_MAX,
FUNCTION_LOGN,
FUNCTION_ATAN2
};
static const Identifier CONSTANTS[CONSTANT_EULER + 1];
static const Identifier NO_ARGUMENT_FUNCTIONS[FUNCTION_RANDOM - FUNCTION_RANDOM + 1];
static const Identifier SINGLE_ARGUMENT_FUNCTIONS[FUNCTION_ACOSECH - FUNCTION_ABS + 1];
static const Identifier DOUBLE_ARGUMENT_FUNCTIONS[FUNCTION_ATAN2 - FUNCTION_HYPOT + 1];
public:
MyExpressionEvaluator() {
}
double onConstant(unsigned int id) const {
switch (id) {
case CONSTANT_E:
case CONSTANT_LN2:
case CONSTANT_PI:
case CONSTANT_SQRT2:
case CONSTANT_EULER:
default:
return ExpressionEvaluator::onConstant(id);
}
}
double onFunction(
unsigned int id,
const double* value) const {
switch (id) {
case FUNCTION_RANDOM:
case FUNCTION_ABS:
case FUNCTION_SIGN:
return (value[0] > 0) ? 1 : ((value[0] < 0) ? -1 : 0);
case FUNCTION_FRAC:
return 0;
case FUNCTION_FLOOR:
case FUNCTION_CEIL:
case FUNCTION_ROUND:
case FUNCTION_SQR:
return value[0] * value[0];
case FUNCTION_SQRT:
if (value[0] < 0) {
}
case FUNCTION_EXP:
case FUNCTION_LN:
case FUNCTION_LOG:
case FUNCTION_LOG2:
case FUNCTION_SIN:
case FUNCTION_ASIN:
case FUNCTION_COS:
case FUNCTION_ACOS:
case FUNCTION_TAN:
case FUNCTION_ATAN:
case FUNCTION_COTAN:
case FUNCTION_ACOTAN:
case FUNCTION_COSEC:
case FUNCTION_ACOSEC:
case FUNCTION_SEC:
case FUNCTION_ASEC:
case FUNCTION_EXSEC:
case FUNCTION_AEXSEC:
case FUNCTION_VERS:
case FUNCTION_AVERS:
case FUNCTION_HAV:
case FUNCTION_AHAV:
case FUNCTION_COVERS:
case FUNCTION_ACOVERS:
case FUNCTION_SINH:
case FUNCTION_ASINH:
case FUNCTION_COSH:
case FUNCTION_ACOSH:
case FUNCTION_TANH:
case FUNCTION_ATANH:
case FUNCTION_COTANH:
case FUNCTION_ACOTANH:
case FUNCTION_SECH:
case FUNCTION_ASECH:
case FUNCTION_COSECH:
case FUNCTION_ACOSECH:
case FUNCTION_HYPOT:
case FUNCTION_PWR:
case FUNCTION_AVG:
return (value[0] + value[1])/2;
case FUNCTION_MIN:
return (value[0] <= value[1]) ? value[0] : value[1];
case FUNCTION_MAX:
return (value[0] >= value[1]) ? value[0] : value[1];
case FUNCTION_LOGN:
if ((value[0] <= 0) || (value[1] == 0)) {
}
case FUNCTION_ATAN2:
default:
return ExpressionEvaluator::onFunction(id, value);
}
}
};
public:
EvaluateApplication()
{
simple = false;
parsed = false;
}
void dumpConstants() {
if (simple) {
fout << "Constants:";
for (unsigned int i = 0; i < getArraySize(CONSTANTS); ++i) {
fout << ' ' << CONSTANTS[i].name;
}
} else {
fout << "Constants:" << EOL;
for (unsigned int i = 0; i < getArraySize(CONSTANTS); ++i) {
fout << indent(2) << CONSTANTS[i].name << EOL;
}
}
fout << ENDL;
}
void dumpFunctions() {
if (simple) {
fout << "Functions:";
for (unsigned int i = 0; i < getArraySize(NO_ARGUMENT_FUNCTIONS); ++i) {
fout << ' ' << NO_ARGUMENT_FUNCTIONS[i].name << "()";
}
for (unsigned int i = 0; i < getArraySize(SINGLE_ARGUMENT_FUNCTIONS); ++i) {
fout << ' ' << SINGLE_ARGUMENT_FUNCTIONS[i].name << "(x)";
}
for (unsigned int i = 0; i < getArraySize(DOUBLE_ARGUMENT_FUNCTIONS); ++i) {
fout << ' ' << DOUBLE_ARGUMENT_FUNCTIONS[i].name << "(x, y)";
}
} else {
fout << "Functions:" << EOL;
for (unsigned int i = 0; i < getArraySize(NO_ARGUMENT_FUNCTIONS); ++i) {
fout << indent(2) << NO_ARGUMENT_FUNCTIONS[i].name << "()" << EOL;
}
for (unsigned int i = 0; i < getArraySize(SINGLE_ARGUMENT_FUNCTIONS); ++i) {
fout << indent(2) << SINGLE_ARGUMENT_FUNCTIONS[i].name << "(x)" << EOL;
}
for (unsigned int i = 0; i < getArraySize(DOUBLE_ARGUMENT_FUNCTIONS); ++i) {
fout << indent(2) << DOUBLE_ARGUMENT_FUNCTIONS[i].name << "(x, y)" << EOL;
}
}
fout << ENDL;
}
void evaluate(
const String& expression) {
for (unsigned int i = 0; i < getArraySize(CONSTANTS); ++i) {
}
for (unsigned int i = 0; i < getArraySize(NO_ARGUMENT_FUNCTIONS); ++i) {
NO_ARGUMENT_FUNCTIONS[i].name,
NO_ARGUMENT_FUNCTIONS[i].id,
0
);
}
for (unsigned int i = 0; i < getArraySize(SINGLE_ARGUMENT_FUNCTIONS); ++i) {
SINGLE_ARGUMENT_FUNCTIONS[i].name,
SINGLE_ARGUMENT_FUNCTIONS[i].id,
1
);
}
for (unsigned int i = 0; i < getArraySize(DOUBLE_ARGUMENT_FUNCTIONS); ++i) {
DOUBLE_ARGUMENT_FUNCTIONS[i].name,
DOUBLE_ARGUMENT_FUNCTIONS[i].id,
2
);
}
try {
<<
" at index " << e.
getIndex() << ENDL;
setExitCode(EXIT_CODE_ERROR);
return;
}
if (parsed) {
fout <<
"Parsed expression: " << parser.
getString() << ENDL;
}
fout << "The expression contains the following unknowns:";
fout <<
' ' << enu.
next().getKey();
}
fout << ENDL;
} else {
MyExpressionEvaluator evaluator;
fout << "Result: " << evaluator.evaluate() << ENDL;
}
}
void version()
{
fout << getFormalName() << " version "
<< MAJOR_VERSION << '.' << MINOR_VERSION << EOL
<< "The Base Framework (Test Suite)" << EOL
<< ENDL;
}
void help()
{
version();
fout << "Usage: " << getFormalName() << " [OPTIONS] expression" << EOL
<< EOL
<< "Options:" << EOL
<< indent(2) << "--help this message" << EOL
<< indent(2) << "--version dump the version" << EOL
<< EOL
<< indent(2) << "--constants show the available constants" << EOL
<< indent(2) << "--functions show the available functions" << EOL
<< indent(2) << "--simple simple list form" << EOL
<< indent(2) << "--parsed show the parsed expression" << EOL
<< ENDL;
}
void main() {
Command command = COMMAND_EVALUATE;
bool expressionSpecified = false;
while (enu.hasNext()) {
if (argument == "--help") {
command = COMMAND_HELP;
} else if (argument == "--version") {
command = COMMAND_VERSION;
} else if (argument == "--constants") {
command = COMMAND_CONSTANTS;
} else if (argument == "--functions") {
command = COMMAND_FUNCTIONS;
} else if (argument == "--simple") {
simple = true;
} else if (argument == "--parsed") {
parsed = true;
} else {
if (expressionSpecified) {
ferr << "Error: " << "Expression already specified" << ENDL;
setExitCode(EXIT_CODE_ERROR);
return;
}
expressionSpecified = true;
expression = argument;
}
}
switch (command) {
case COMMAND_VERSION:
version();
break;
case COMMAND_HELP:
help();
break;
case COMMAND_CONSTANTS:
dumpConstants();
break;
case COMMAND_FUNCTIONS:
dumpFunctions();
break;
case COMMAND_EVALUATE:
if (!expressionSpecified) {
ferr << "Error: " << "Expression not specified" << ENDL;
setExitCode(EXIT_CODE_ERROR);
return;
}
evaluate(expression);
break;
}
}
};
const EvaluateApplication::Identifier
EvaluateApplication::CONSTANTS[CONSTANT_EULER + 1] = {
{MESSAGE("E"), CONSTANT_E},
{MESSAGE("LN2"), CONSTANT_LN2},
{MESSAGE("PI"), CONSTANT_PI},
{MESSAGE("SQRT2"), CONSTANT_SQRT2},
{MESSAGE("EULER"), CONSTANT_EULER}
};
const EvaluateApplication::Identifier
EvaluateApplication::NO_ARGUMENT_FUNCTIONS[FUNCTION_RANDOM - FUNCTION_RANDOM + 1] = {
{MESSAGE("random"), FUNCTION_RANDOM}
};
const EvaluateApplication::Identifier
EvaluateApplication::SINGLE_ARGUMENT_FUNCTIONS[FUNCTION_ACOSECH - FUNCTION_ABS + 1] = {
{MESSAGE("abs"), FUNCTION_ABS},
{MESSAGE("sign"), FUNCTION_SIGN},
{MESSAGE("frac"), FUNCTION_FRAC},
{MESSAGE("floor"), FUNCTION_FLOOR},
{MESSAGE("ceil"), FUNCTION_CEIL},
{MESSAGE("round"), FUNCTION_ROUND},
{MESSAGE("sqr"), FUNCTION_SQR},
{MESSAGE("sqrt"), FUNCTION_SQRT},
{MESSAGE("exp"), FUNCTION_EXP},
{MESSAGE("ln"), FUNCTION_LN},
{MESSAGE("log"), FUNCTION_LOG},
{MESSAGE("log2"), FUNCTION_LOG2},
{MESSAGE("sin"), FUNCTION_SIN},
{MESSAGE("asin"), FUNCTION_ASIN},
{MESSAGE("cos"), FUNCTION_COS},
{MESSAGE("acos"), FUNCTION_ACOS},
{MESSAGE("tan"), FUNCTION_TAN},
{MESSAGE("atan"), FUNCTION_ATAN},
{MESSAGE("cotan"), FUNCTION_COTAN},
{MESSAGE("acotan"), FUNCTION_ACOTAN},
{MESSAGE("cosec"), FUNCTION_COSEC},
{MESSAGE("acosec"), FUNCTION_ACOSEC},
{MESSAGE("sec"), FUNCTION_SEC},
{MESSAGE("asec"), FUNCTION_ASEC},
{MESSAGE("exsec"), FUNCTION_EXSEC},
{MESSAGE("aexsec"), FUNCTION_AEXSEC},
{MESSAGE("vers"), FUNCTION_VERS},
{MESSAGE("avers"), FUNCTION_AVERS},
{MESSAGE("hav"), FUNCTION_HAV},
{MESSAGE("ahav"), FUNCTION_AHAV},
{MESSAGE("covers"), FUNCTION_COVERS},
{MESSAGE("acovers"), FUNCTION_ACOVERS},
{MESSAGE("sinh"), FUNCTION_SINH},
{MESSAGE("asinh"), FUNCTION_ASINH},
{MESSAGE("cosh"), FUNCTION_COSH},
{MESSAGE("acosh"), FUNCTION_ACOSH},
{MESSAGE("tanh"), FUNCTION_TANH},
{MESSAGE("atanh"), FUNCTION_ATANH},
{MESSAGE("cotanh"), FUNCTION_COTANH},
{MESSAGE("acotanh"), FUNCTION_ACOTANH},
{MESSAGE("sech"), FUNCTION_SECH},
{MESSAGE("asech"), FUNCTION_ASECH},
{MESSAGE("cosech"), FUNCTION_COSECH},
{MESSAGE("acosech"), FUNCTION_ACOSECH}
};
const EvaluateApplication::Identifier
EvaluateApplication::DOUBLE_ARGUMENT_FUNCTIONS[FUNCTION_ATAN2 - FUNCTION_HYPOT + 1] = {
{MESSAGE("hypot"), FUNCTION_HYPOT},
{MESSAGE("pwr"), FUNCTION_PWR},
{MESSAGE("avg"), FUNCTION_AVG},
{MESSAGE("min"), FUNCTION_MIN},
{MESSAGE("max"), FUNCTION_MAX},
{MESSAGE("logn"), FUNCTION_LOGN},
{MESSAGE("atan2"), FUNCTION_ATAN2}
};
APPLICATION_STUB(EvaluateApplication);