I hope Daniel is not upset, but Ingo and I have written a new parser:
* it supports white spaces * it supports , and . for the decimal point * it gives parse errors and where the error occured * it supports more functions I also added evaluating an expression given on the command line, it doesn't show the UI then. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@17774 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -27,8 +27,8 @@
|
|||||||
|
|
||||||
#include "CalcApplication.h"
|
#include "CalcApplication.h"
|
||||||
#include "CalcOptionsWindow.h"
|
#include "CalcOptionsWindow.h"
|
||||||
|
#include "ExpressionParser.h"
|
||||||
#include "ExpressionTextView.h"
|
#include "ExpressionTextView.h"
|
||||||
#include "Parser.h"
|
|
||||||
|
|
||||||
|
|
||||||
const uint8 K_COLOR_OFFSET = 32;
|
const uint8 K_COLOR_OFFSET = 32;
|
||||||
@@ -701,7 +701,6 @@ CalcView::Evaluate()
|
|||||||
const double EXP_SWITCH_LO = 1e-12;
|
const double EXP_SWITCH_LO = 1e-12;
|
||||||
|
|
||||||
BString expression = fExpressionTextView->Text();
|
BString expression = fExpressionTextView->Text();
|
||||||
expression << "\n";
|
|
||||||
|
|
||||||
if (expression.Length() == 0) {
|
if (expression.Length() == 0) {
|
||||||
beep();
|
beep();
|
||||||
@@ -719,22 +718,18 @@ CalcView::Evaluate()
|
|||||||
//printf("evaluate: %s\n", expression.String());
|
//printf("evaluate: %s\n", expression.String());
|
||||||
|
|
||||||
// evaluate expression
|
// evaluate expression
|
||||||
Expression parser;
|
|
||||||
|
|
||||||
char* tmpstr = strdup(expression.String());
|
|
||||||
char* start = tmpstr;
|
|
||||||
char* end = start + expression.Length() - 1;
|
|
||||||
double value = 0.0;
|
double value = 0.0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
value = parser.Evaluate(start, end, true);
|
ExpressionParser parser;
|
||||||
} catch (const char* error) {
|
value = parser.Evaluate(expression.String());
|
||||||
fExpressionTextView->SetText(error);
|
} catch (ParseException e) {
|
||||||
|
BString error(e.message.String());
|
||||||
|
error << " at " << (e.position + 1);
|
||||||
|
fExpressionTextView->SetText(error.String());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(tmpstr);
|
|
||||||
|
|
||||||
//printf(" -> value: %f\n", value);
|
//printf(" -> value: %f\n", value);
|
||||||
|
|
||||||
// beautify the expression
|
// beautify the expression
|
||||||
|
|||||||
@@ -8,15 +8,37 @@
|
|||||||
* Stephan Aßmus <[email protected]>
|
* Stephan Aßmus <[email protected]>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "CalcApplication.h"
|
#include "CalcApplication.h"
|
||||||
|
#include "ExpressionParser.h"
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char* argv[])
|
main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
CalcApplication* app = new CalcApplication();
|
if (argc == 1) {
|
||||||
|
// run GUI
|
||||||
app->Run();
|
CalcApplication* app = new CalcApplication();
|
||||||
delete app;
|
|
||||||
|
app->Run();
|
||||||
|
delete app;
|
||||||
|
} else {
|
||||||
|
// evaluate expression from command line
|
||||||
|
BString expression;
|
||||||
|
int32 i = 1;
|
||||||
|
while (i < argc) {
|
||||||
|
expression << argv[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ExpressionParser parser;
|
||||||
|
printf("%f\n", parser.Evaluate(expression.String()));
|
||||||
|
} catch (ParseException e) {
|
||||||
|
printf("%s at %ld\n", e.message.String(), e.position + 1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,281 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2006 Haiku, Inc. All Rights Reserved.
|
|
||||||
* Copyright 2004 Daniel Wallner. All Rights Reserved.
|
|
||||||
* Copyright 1997, 1998 R3 Software Ltd. All Rights Reserved.
|
|
||||||
* Distributed under the terms of the MIT License.
|
|
||||||
*
|
|
||||||
* Authors:
|
|
||||||
* Daniel Wallner <[email protected]>
|
|
||||||
* Timothy Wayper <[email protected]>
|
|
||||||
* Stephan Aßmus <[email protected]>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <iostream.h>
|
|
||||||
#include <fstream.h>
|
|
||||||
#include <complex>
|
|
||||||
#include <vector>
|
|
||||||
#include <math.h>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
//#include <libxlds/xlds.h>
|
|
||||||
//#include <libdsph/getopt.h>
|
|
||||||
//#include <libdsph/const.h>
|
|
||||||
|
|
||||||
#include "CalcApplication.h"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
//using namespace xlds;
|
|
||||||
|
|
||||||
void Usage()
|
|
||||||
{
|
|
||||||
cerr << "Expression calculator" << endl << endl;
|
|
||||||
cerr << " usage: expcalc [expression] ... [options and arguments]" << endl << endl;
|
|
||||||
cerr << " -h print this message" << endl;
|
|
||||||
cerr << " -e even thousands exponent output" << endl;
|
|
||||||
cerr << " -p SI prefix output" << endl;
|
|
||||||
cerr << " -n newline after output" << endl << endl;
|
|
||||||
cerr << " If no arguments are given, expcalc enters interactive mode." << endl;
|
|
||||||
cerr << " You can combine short flags, so `-e -n' means the same as -en or -ne." << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GetString(string &instring)
|
|
||||||
{
|
|
||||||
instring.assign("");
|
|
||||||
|
|
||||||
char cchar;
|
|
||||||
|
|
||||||
cchar = getc(stdin);
|
|
||||||
|
|
||||||
while (cchar != EOF && cchar != 10)
|
|
||||||
{
|
|
||||||
instring.append(1, cchar);
|
|
||||||
cchar = getc(stdin);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
if (argc == 1) {
|
|
||||||
CalcApplication* app = new CalcApplication();
|
|
||||||
|
|
||||||
app->Run();
|
|
||||||
delete app;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
char *expression = NULL;
|
|
||||||
char outputMode = 0;
|
|
||||||
bool newline = false;
|
|
||||||
|
|
||||||
while (doptind < argc)
|
|
||||||
{
|
|
||||||
if (argv[doptind][0] != '-' || strlen(argv[doptind]) <= 1)
|
|
||||||
{
|
|
||||||
// File argument
|
|
||||||
if (expression)
|
|
||||||
throw "Multiple expressions not supported";
|
|
||||||
|
|
||||||
expression = argv[doptind];
|
|
||||||
|
|
||||||
doptind++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Option
|
|
||||||
int opt = dgetopt(argc, argv, ":hepn");
|
|
||||||
if (opt != -1)
|
|
||||||
{
|
|
||||||
switch (opt)
|
|
||||||
{
|
|
||||||
case 'h':
|
|
||||||
Usage();
|
|
||||||
return 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'e':
|
|
||||||
outputMode = 1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'p':
|
|
||||||
outputMode = 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'n':
|
|
||||||
newline = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ':': // No argument
|
|
||||||
cerr << "Option -" << (char)doptopt << " requires an argument" << endl;
|
|
||||||
throw "";
|
|
||||||
|
|
||||||
case '?':
|
|
||||||
default:
|
|
||||||
cerr << "Unknown option -" << (char)doptopt << endl;
|
|
||||||
throw "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string instring;
|
|
||||||
string laststring;
|
|
||||||
string stored;
|
|
||||||
|
|
||||||
Expression exp;
|
|
||||||
|
|
||||||
if (expression)
|
|
||||||
{
|
|
||||||
double temp = exp.Eval(expression, expression + strlen(expression));
|
|
||||||
|
|
||||||
if (!exp.Error())
|
|
||||||
{
|
|
||||||
cout << exp.dtostr(temp, 14, outputMode).c_str();
|
|
||||||
if (newline)
|
|
||||||
cout << endl;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
char *i;
|
|
||||||
cout << expression << endl;
|
|
||||||
for (i = expression; i < exp.Error(); i++)
|
|
||||||
cout << " ";
|
|
||||||
cout << "^\nError in input\n\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cout << "Expression Calculator\n";
|
|
||||||
cout << "Copyright (c) Daniel Wallner 2004.\n";
|
|
||||||
cout << "Type exit to end program or ? for help.\n\n";
|
|
||||||
|
|
||||||
cout << "ec> ";
|
|
||||||
|
|
||||||
if (GetString(instring))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
bool rec = false;
|
|
||||||
|
|
||||||
while (strcmp(instring.c_str(), "exit"))
|
|
||||||
{
|
|
||||||
if (!strcmp(instring.c_str(), "?"))
|
|
||||||
{
|
|
||||||
cout << "\nCommands l : repeat last calculation (used with ans)\n";
|
|
||||||
cout << " sto : store last expression\n";
|
|
||||||
cout << " rec : recall stored expression\n";
|
|
||||||
cout << " d : set trigonometric functions to degrees\n";
|
|
||||||
cout << " r : set trigonometric functions to radians (default)\n";
|
|
||||||
cout << " e : toggle exponent output mode\n";
|
|
||||||
cout << " p : set prefix output mode\n";
|
|
||||||
cout << " exit : exit program\n";
|
|
||||||
cout << "\nFunctions sin( : sinus\n";
|
|
||||||
cout << " cos( : cosinus\n";
|
|
||||||
cout << " tan( : tangens\n";
|
|
||||||
cout << " asin( : arcsin\n";
|
|
||||||
cout << " acos( : arccos\n";
|
|
||||||
cout << " atan( : arctan\n";
|
|
||||||
cout << " lg( : logarithm with base 10\n";
|
|
||||||
cout << " ln( : logarithm with base e\n";
|
|
||||||
cout << " sqrt( : sqare root\n";
|
|
||||||
cout << " ans : last answer\n";
|
|
||||||
cout << " ^,*,+,-,/ : as usual :-)\n";
|
|
||||||
cout << "\nConstants e : the constant e\n";
|
|
||||||
cout << " pi : the constant pi\n\n";
|
|
||||||
|
|
||||||
rec=1;
|
|
||||||
instring = laststring;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strcmp(instring.c_str(), "l"))
|
|
||||||
{
|
|
||||||
instring = laststring;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strcmp(instring.c_str(), "sto"))
|
|
||||||
{
|
|
||||||
stored = laststring;
|
|
||||||
cout << "\nLast expression stored!\n\n";
|
|
||||||
rec = 1;
|
|
||||||
instring = laststring;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strcmp(instring.c_str(), "rec"))
|
|
||||||
{
|
|
||||||
instring = stored;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strcmp(instring.c_str(), "d"))
|
|
||||||
{
|
|
||||||
exp.SetAglf(M_PI / 180.);
|
|
||||||
rec = 1;
|
|
||||||
cout << "\nDegree mode!\n\n";
|
|
||||||
instring = laststring;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strcmp(instring.c_str(), "r"))
|
|
||||||
{
|
|
||||||
exp.SetAglf(1.);
|
|
||||||
rec = 1;
|
|
||||||
cout << "\nRadian mode!\n\n";
|
|
||||||
instring = laststring;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strcmp(instring.c_str(), "e"))
|
|
||||||
{
|
|
||||||
outputMode = (outputMode + 1) % 2;
|
|
||||||
cout << "\nExponent output mode" << outputMode << "!\n\n";
|
|
||||||
instring = laststring;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strcmp(instring.c_str(), "p"))
|
|
||||||
{
|
|
||||||
outputMode = 2;
|
|
||||||
cout << "\nPrefix output mode!\n\n";
|
|
||||||
instring = laststring;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!instring.size())
|
|
||||||
rec = 1;
|
|
||||||
|
|
||||||
if (rec == 0)
|
|
||||||
{
|
|
||||||
double temp = exp.Eval(instring.c_str(), instring.c_str() + instring.size());
|
|
||||||
|
|
||||||
if (!exp.Error())
|
|
||||||
{
|
|
||||||
cout << "\n" << instring << " = ";
|
|
||||||
cout << exp.dtostr(temp, 14, outputMode).c_str();
|
|
||||||
cout << "\n\n";
|
|
||||||
exp.SetConstant("ans", temp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const char *i;
|
|
||||||
for (i = instring.c_str(); i < exp.Error(); i++)
|
|
||||||
cout << " ";
|
|
||||||
cout << " ";
|
|
||||||
cout << "^\nError in input\n\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cout << "ec> ";
|
|
||||||
laststring = instring;
|
|
||||||
if (GetString(instring))
|
|
||||||
return 0;
|
|
||||||
rec = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (const char * str)
|
|
||||||
{
|
|
||||||
cerr << str << endl;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,474 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2006 Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Ingo Weinhold <[email protected]>
|
||||||
|
* Stephan Aßmus <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "ExpressionParser.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
TOKEN_IDENTIFIER = 'a',
|
||||||
|
|
||||||
|
TOKEN_CONSTANT = '0',
|
||||||
|
|
||||||
|
TOKEN_PLUS = '+',
|
||||||
|
TOKEN_MINUS = '-',
|
||||||
|
|
||||||
|
TOKEN_STAR = '*',
|
||||||
|
TOKEN_SLASH = '/',
|
||||||
|
TOKEN_MODULO = '%',
|
||||||
|
|
||||||
|
TOKEN_POWER = '^',
|
||||||
|
|
||||||
|
TOKEN_OPENING_BRACKET = '(',
|
||||||
|
TOKEN_CLOSING_BRACKET = ')',
|
||||||
|
|
||||||
|
TOKEN_AND = '&',
|
||||||
|
TOKEN_OR = '|',
|
||||||
|
TOKEN_NOT = '~',
|
||||||
|
|
||||||
|
TOKEN_NONE = ' ',
|
||||||
|
TOKEN_END_OF_LINE = '\n',
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Token {
|
||||||
|
Token()
|
||||||
|
: string(""),
|
||||||
|
type(TOKEN_NONE),
|
||||||
|
value(0.0),
|
||||||
|
position(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Token(const Token& other)
|
||||||
|
: string(other.string),
|
||||||
|
type(other.type),
|
||||||
|
value(other.value),
|
||||||
|
position(other.position)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Token(const char* string, int32 length, int32 position, int32 type)
|
||||||
|
: string(string, length),
|
||||||
|
type(type),
|
||||||
|
value(0.0),
|
||||||
|
position(position)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Token& operator=(const Token& other)
|
||||||
|
{
|
||||||
|
string = other.string;
|
||||||
|
type = other.type;
|
||||||
|
value = other.value;
|
||||||
|
position = other.position;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
BString string;
|
||||||
|
int32 type;
|
||||||
|
double value;
|
||||||
|
|
||||||
|
int32 position;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Tokenizer {
|
||||||
|
public:
|
||||||
|
Tokenizer()
|
||||||
|
: fString(""),
|
||||||
|
fCurrentChar(NULL),
|
||||||
|
fCurrentToken(),
|
||||||
|
fReuseToken(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetTo(const char* string)
|
||||||
|
{
|
||||||
|
fString = string;
|
||||||
|
fCurrentChar = fString.String();
|
||||||
|
fCurrentToken = Token();
|
||||||
|
fReuseToken = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Token& NextToken()
|
||||||
|
{
|
||||||
|
if (fCurrentToken.type == TOKEN_END_OF_LINE)
|
||||||
|
return fCurrentToken;
|
||||||
|
|
||||||
|
if (fReuseToken) {
|
||||||
|
fReuseToken = false;
|
||||||
|
//printf("next token (recycled): '%s'\n", fCurrentToken.string.String());
|
||||||
|
return fCurrentToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*fCurrentChar != 0 && isspace(*fCurrentChar))
|
||||||
|
fCurrentChar++;
|
||||||
|
|
||||||
|
if (*fCurrentChar == 0)
|
||||||
|
return fCurrentToken = Token("", 0, _CurrentPos(), TOKEN_END_OF_LINE);
|
||||||
|
|
||||||
|
bool decimal = *fCurrentChar == '.' || *fCurrentChar == ',';
|
||||||
|
|
||||||
|
if (decimal || isdigit(*fCurrentChar)) {
|
||||||
|
|
||||||
|
BString temp;
|
||||||
|
|
||||||
|
const char* begin = fCurrentChar;
|
||||||
|
while (*fCurrentChar != 0) {
|
||||||
|
if (!isdigit(*fCurrentChar)) {
|
||||||
|
if (!(*fCurrentChar == '.' || *fCurrentChar == ','
|
||||||
|
|| *fCurrentChar == 'e' || *fCurrentChar == 'E'))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (*fCurrentChar == ',')
|
||||||
|
temp << '.';
|
||||||
|
else
|
||||||
|
temp << *fCurrentChar;
|
||||||
|
fCurrentChar++;
|
||||||
|
}
|
||||||
|
int32 length = fCurrentChar - begin;
|
||||||
|
temp << "&_";
|
||||||
|
double value;
|
||||||
|
char t[2];
|
||||||
|
int32 matches = sscanf(temp.String(), "%lf&%s", &value, t);
|
||||||
|
if (matches != 2)
|
||||||
|
throw ParseException("error in constant", _CurrentPos() - length);
|
||||||
|
|
||||||
|
fCurrentToken = Token(begin, length, _CurrentPos() - length, TOKEN_CONSTANT);
|
||||||
|
fCurrentToken.value = value;;
|
||||||
|
|
||||||
|
} else if (isalpha(*fCurrentChar)) {
|
||||||
|
|
||||||
|
const char* begin = fCurrentChar;
|
||||||
|
while (*fCurrentChar != 0 && (isalpha(*fCurrentChar) || isdigit(*fCurrentChar)))
|
||||||
|
fCurrentChar++;
|
||||||
|
int32 length = fCurrentChar - begin;
|
||||||
|
fCurrentToken = Token(begin, length, _CurrentPos() - length, TOKEN_IDENTIFIER);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
switch (*fCurrentChar) {
|
||||||
|
case '+':
|
||||||
|
case '-':
|
||||||
|
case '*':
|
||||||
|
case '/':
|
||||||
|
|
||||||
|
case '^':
|
||||||
|
case '%':
|
||||||
|
|
||||||
|
case '(':
|
||||||
|
case ')':
|
||||||
|
|
||||||
|
case '&':
|
||||||
|
case '|':
|
||||||
|
case '~':
|
||||||
|
fCurrentToken = Token(fCurrentChar, 1, _CurrentPos(), *fCurrentChar);
|
||||||
|
fCurrentChar++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw ParseException("unexpected character", _CurrentPos());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//printf("next token: '%s'\n", fCurrentToken.string.String());
|
||||||
|
return fCurrentToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RewindToken()
|
||||||
|
{
|
||||||
|
fReuseToken = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int32 _CurrentPos() const
|
||||||
|
{
|
||||||
|
return fCurrentChar - fString.String();
|
||||||
|
}
|
||||||
|
|
||||||
|
BString fString;
|
||||||
|
const char* fCurrentChar;
|
||||||
|
Token fCurrentToken;
|
||||||
|
bool fReuseToken;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
ExpressionParser::ExpressionParser()
|
||||||
|
: fTokenizer(new Tokenizer())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ExpressionParser::~ExpressionParser()
|
||||||
|
{
|
||||||
|
delete fTokenizer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double
|
||||||
|
ExpressionParser::Evaluate(const char* expressionString)
|
||||||
|
{
|
||||||
|
fTokenizer->SetTo(expressionString);
|
||||||
|
|
||||||
|
double value = _ParseBinary();
|
||||||
|
Token token = fTokenizer->NextToken();
|
||||||
|
if (token.type != TOKEN_END_OF_LINE)
|
||||||
|
throw ParseException("parse error", token.position);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double
|
||||||
|
ExpressionParser::_ParseBinary()
|
||||||
|
{
|
||||||
|
double value = _ParseSum();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
Token token = fTokenizer->NextToken();
|
||||||
|
switch (token.type) {
|
||||||
|
case TOKEN_AND:
|
||||||
|
value = (uint64)value & (uint64)_ParseSum();
|
||||||
|
break;
|
||||||
|
case TOKEN_OR:
|
||||||
|
value = (uint64)value | (uint64)_ParseSum();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fTokenizer->RewindToken();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double
|
||||||
|
ExpressionParser::_ParseSum()
|
||||||
|
{
|
||||||
|
// TODO: check isnan()...
|
||||||
|
double value = _ParseProduct();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
Token token = fTokenizer->NextToken();
|
||||||
|
switch (token.type) {
|
||||||
|
case TOKEN_PLUS:
|
||||||
|
value = value + _ParseProduct();
|
||||||
|
break;
|
||||||
|
case TOKEN_MINUS:
|
||||||
|
value = value - _ParseProduct();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fTokenizer->RewindToken();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double
|
||||||
|
ExpressionParser::_ParseProduct()
|
||||||
|
{
|
||||||
|
// TODO: check isnan()...
|
||||||
|
double value = _ParsePower();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
Token token = fTokenizer->NextToken();
|
||||||
|
switch (token.type) {
|
||||||
|
case TOKEN_STAR:
|
||||||
|
value = value * _ParsePower();
|
||||||
|
break;
|
||||||
|
case TOKEN_SLASH: {
|
||||||
|
double rhs = _ParsePower();
|
||||||
|
if (rhs == 0.0)
|
||||||
|
throw ParseException("division by zero", token.position);
|
||||||
|
value = value / rhs;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TOKEN_MODULO: {
|
||||||
|
double rhs = _ParsePower();
|
||||||
|
if (rhs == 0.0)
|
||||||
|
throw ParseException("modulo by zero", token.position);
|
||||||
|
value = fmod(value, rhs);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
fTokenizer->RewindToken();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double
|
||||||
|
ExpressionParser::_ParsePower()
|
||||||
|
{
|
||||||
|
double value = _ParseUnary();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
Token token = fTokenizer->NextToken();
|
||||||
|
if (token.type != TOKEN_POWER) {
|
||||||
|
fTokenizer->RewindToken();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
value = pow(value, _ParseUnary());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double
|
||||||
|
ExpressionParser::_ParseUnary()
|
||||||
|
{
|
||||||
|
Token token = fTokenizer->NextToken();
|
||||||
|
if (token.type == TOKEN_END_OF_LINE)
|
||||||
|
throw ParseException("unexpected end of expression", token.position);
|
||||||
|
|
||||||
|
switch (token.type) {
|
||||||
|
case TOKEN_PLUS:
|
||||||
|
return _ParseUnary();
|
||||||
|
case TOKEN_MINUS:
|
||||||
|
return -_ParseUnary();
|
||||||
|
case TOKEN_NOT:
|
||||||
|
return ~(uint64)_ParseUnary();
|
||||||
|
|
||||||
|
case TOKEN_IDENTIFIER:
|
||||||
|
return _ParseFunction(token);
|
||||||
|
|
||||||
|
default:
|
||||||
|
fTokenizer->RewindToken();
|
||||||
|
return _ParseAtom();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct Function {
|
||||||
|
const char* name;
|
||||||
|
int argumentCount;
|
||||||
|
void* function;
|
||||||
|
double value;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const Function kFunctions[] = {
|
||||||
|
{ "e", 0, NULL, M_E },
|
||||||
|
{ "pi", 0, NULL, M_PI },
|
||||||
|
|
||||||
|
{ "abs", 1, &fabs },
|
||||||
|
{ "acos", 1, &acos },
|
||||||
|
{ "asin", 1, &asin },
|
||||||
|
{ "atan", 1, &atan },
|
||||||
|
{ "atan2", 2, &atan2 },
|
||||||
|
{ "ceil", 1, &ceil },
|
||||||
|
{ "cos", 1, &cos },
|
||||||
|
{ "cosh", 1, &cosh },
|
||||||
|
{ "exp", 1, &exp },
|
||||||
|
{ "fabs", 1, &fabs },
|
||||||
|
{ "floor", 1, &floor },
|
||||||
|
{ "fmod", 2, &fmod },
|
||||||
|
{ "log", 1, &log },
|
||||||
|
{ "log10", 1, &log10 },
|
||||||
|
{ "pow", 2, &pow },
|
||||||
|
{ "sin", 1, &sin },
|
||||||
|
{ "sinh", 1, &sinh },
|
||||||
|
{ "sqrt", 1, &sqrt },
|
||||||
|
{ "tan", 1, &tan },
|
||||||
|
{ "tanh", 1, &tanh },
|
||||||
|
{ "hypot", 2, &hypot },
|
||||||
|
|
||||||
|
{ NULL },
|
||||||
|
};
|
||||||
|
|
||||||
|
double
|
||||||
|
ExpressionParser::_ParseFunction(const Token& token)
|
||||||
|
{
|
||||||
|
const Function* function = _FindFunction(token.string.String());
|
||||||
|
if (!function)
|
||||||
|
throw ParseException("unknown identifier", token.position);
|
||||||
|
|
||||||
|
if (function->argumentCount == 0)
|
||||||
|
return function->value;
|
||||||
|
|
||||||
|
_EatToken(TOKEN_OPENING_BRACKET);
|
||||||
|
|
||||||
|
double values[function->argumentCount];
|
||||||
|
for (int32 i = 0; i < function->argumentCount; i++) {
|
||||||
|
values[i] = _ParseBinary();
|
||||||
|
}
|
||||||
|
|
||||||
|
_EatToken(TOKEN_CLOSING_BRACKET);
|
||||||
|
|
||||||
|
// hard coded cases for different count of arguments
|
||||||
|
switch (function->argumentCount) {
|
||||||
|
case 1:
|
||||||
|
return ((double (*)(double))function->function)(values[0]);
|
||||||
|
case 2:
|
||||||
|
return ((double (*)(double, double))function->function)(values[0],
|
||||||
|
values[1]);
|
||||||
|
case 3:
|
||||||
|
return ((double (*)(double, double, double))function->function)(
|
||||||
|
values[0], values[1], values[2]);
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw ParseException("unsupported function argument count",
|
||||||
|
token.position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double
|
||||||
|
ExpressionParser::_ParseAtom()
|
||||||
|
{
|
||||||
|
Token token = fTokenizer->NextToken();
|
||||||
|
if (token.type == TOKEN_END_OF_LINE)
|
||||||
|
throw ParseException("unexpected end of expression", token.position);
|
||||||
|
|
||||||
|
if (token.type == TOKEN_CONSTANT)
|
||||||
|
return token.value;
|
||||||
|
|
||||||
|
fTokenizer->RewindToken();
|
||||||
|
|
||||||
|
_EatToken(TOKEN_OPENING_BRACKET);
|
||||||
|
|
||||||
|
double value = _ParseBinary();
|
||||||
|
|
||||||
|
_EatToken(TOKEN_CLOSING_BRACKET);
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ExpressionParser::_EatToken(int32 type)
|
||||||
|
{
|
||||||
|
Token token = fTokenizer->NextToken();
|
||||||
|
if (token.type != type) {
|
||||||
|
BString temp("expected '");
|
||||||
|
temp << (char)type << "' got '" << token.string << "'";
|
||||||
|
throw ParseException(temp.String(), token.position);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const Function*
|
||||||
|
ExpressionParser::_FindFunction(const char* name) const
|
||||||
|
{
|
||||||
|
for (int32 i = 0; kFunctions[i].name; i++) {
|
||||||
|
if (strcasecmp(kFunctions[i].name, name) == 0)
|
||||||
|
return &kFunctions[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2006 Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Ingo Weinhold <[email protected]>
|
||||||
|
* Stephan Aßmus <[email protected]>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EXPRESSION_PARSER_H
|
||||||
|
#define EXPRESSION_PARSER_H
|
||||||
|
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
class Tokenizer;
|
||||||
|
|
||||||
|
class ParseException {
|
||||||
|
public:
|
||||||
|
ParseException(const char* message, int32 position)
|
||||||
|
: message(message),
|
||||||
|
position(position)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ParseException(const ParseException& other)
|
||||||
|
: message(other.message),
|
||||||
|
position(other.position)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
BString message;
|
||||||
|
int32 position;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Function;
|
||||||
|
struct Token;
|
||||||
|
|
||||||
|
class ExpressionParser {
|
||||||
|
public:
|
||||||
|
ExpressionParser();
|
||||||
|
~ExpressionParser();
|
||||||
|
|
||||||
|
double Evaluate(const char* expressionString);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
double _ParseBinary();
|
||||||
|
double _ParseSum();
|
||||||
|
double _ParseProduct();
|
||||||
|
double _ParsePower();
|
||||||
|
double _ParseUnary();
|
||||||
|
double _ParseFunction(const Token& token);
|
||||||
|
double _ParseAtom();
|
||||||
|
|
||||||
|
void _EatToken(int32 type);
|
||||||
|
const Function* _FindFunction(const char* name) const;
|
||||||
|
|
||||||
|
Tokenizer* fTokenizer;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // EXPRESSION_PARSER_H
|
||||||
@@ -10,9 +10,9 @@ Application DeskCalc :
|
|||||||
CalcView.cpp
|
CalcView.cpp
|
||||||
CalcWindow.cpp
|
CalcWindow.cpp
|
||||||
DeskCalc.cpp
|
DeskCalc.cpp
|
||||||
|
ExpressionParser.cpp
|
||||||
ExpressionTextView.cpp
|
ExpressionTextView.cpp
|
||||||
InputTextView.cpp
|
InputTextView.cpp
|
||||||
Parser.cpp
|
|
||||||
: be $(TARGET_LIBSTDC++) media
|
: be $(TARGET_LIBSTDC++) media
|
||||||
: DeskCalc.rdef
|
: DeskCalc.rdef
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -1,919 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2006 Haiku, Inc. All Rights Reserved.
|
|
||||||
* Copyright 2004 Daniel Wallner. All Rights Reserved.
|
|
||||||
* Distributed under the terms of the MIT License.
|
|
||||||
*
|
|
||||||
* Authors:
|
|
||||||
* Daniel Wallner <[email protected]>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "Parser.h"
|
|
||||||
|
|
||||||
#include <iostream.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
#define NOLLF 5e-16
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
//LineParser::LineParser(istream *stream):
|
|
||||||
// m_stream(stream),
|
|
||||||
// m_currentLine(0)
|
|
||||||
//{
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//void LineParser::AddSeparator(const char c)
|
|
||||||
//{
|
|
||||||
// m_separators.push_back(c);
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//size_t LineParser::SetToNext(bool toUpperCase)
|
|
||||||
//{
|
|
||||||
// m_line.erase(m_line.begin(), m_line.end());
|
|
||||||
// m_unparsed.assign("");
|
|
||||||
//
|
|
||||||
// // Skip newlines
|
|
||||||
// while (m_stream->peek() == 0xA || m_stream->peek() == 0xD)
|
|
||||||
// m_stream->get();
|
|
||||||
//
|
|
||||||
// while (!m_stream->eof() && !m_stream->fail() && m_stream->peek() != 0xA && m_stream->peek() != 0xD)
|
|
||||||
// {
|
|
||||||
// string param;
|
|
||||||
//
|
|
||||||
// // Skip whitespaces
|
|
||||||
// while (m_stream->peek() == ' ' || m_stream->peek() == '\t')
|
|
||||||
// m_unparsed.append(1, char(m_stream->get()));
|
|
||||||
//// m_separators.push_back(c); add check for separators !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
||||||
//
|
|
||||||
// if (m_stream->peek() == '"')
|
|
||||||
// {
|
|
||||||
// // Skip first "
|
|
||||||
// m_unparsed.append(1, char(m_stream->get()));
|
|
||||||
//
|
|
||||||
// int c;
|
|
||||||
// // Read until "
|
|
||||||
// while (!m_stream->fail() && m_stream->peek() != 0xA && m_stream->peek() != 0xD &&
|
|
||||||
// (c = m_stream->get()) != '"' && !m_stream->eof())
|
|
||||||
// {
|
|
||||||
// m_unparsed.append(1, char(c));
|
|
||||||
// if (toUpperCase)
|
|
||||||
// param.append(1, char(toupper(c)));
|
|
||||||
// else
|
|
||||||
// param.append(1, char(c));
|
|
||||||
// }
|
|
||||||
// if (c == '"')
|
|
||||||
// m_unparsed.append(1, char(c));
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// int c;
|
|
||||||
// // Read until whitespace
|
|
||||||
//// m_separators.push_back(c); add check for separators !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
||||||
// while (!m_stream->fail() && m_stream->peek() != 0xA && m_stream->peek() != 0xD &&
|
|
||||||
// (c = m_stream->get()) != ' ' && c != '\t' && !m_stream->eof())
|
|
||||||
// {
|
|
||||||
// m_unparsed.append(1, char(c));
|
|
||||||
// if (toUpperCase)
|
|
||||||
// param.append(1, char(toupper(c)));
|
|
||||||
// else
|
|
||||||
// param.append(1, char(c));
|
|
||||||
// }
|
|
||||||
// if (c == ' ')
|
|
||||||
// m_unparsed.append(1, char(c));
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Store parameter
|
|
||||||
// if (param.size())
|
|
||||||
// m_line.push_back(param);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Skip newlines
|
|
||||||
// while (m_stream->peek() == 0xA || m_stream->peek() == 0xD)
|
|
||||||
// m_stream->get();
|
|
||||||
//
|
|
||||||
// return m_line.size();
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//void LineParser::WriteCompressed(string *s) const
|
|
||||||
//{
|
|
||||||
// size_t i;
|
|
||||||
// for (i = 0; i < m_line.size(); i++)
|
|
||||||
// {
|
|
||||||
// if (i != 0)
|
|
||||||
// {
|
|
||||||
// *s += " ";
|
|
||||||
// }
|
|
||||||
// *s += m_line[i];
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//void LineParser::WriteCompressed(ostream *stream) const
|
|
||||||
//{
|
|
||||||
// size_t i;
|
|
||||||
// for (i = 0; i < m_line.size(); i++)
|
|
||||||
// {
|
|
||||||
// if (i != 0)
|
|
||||||
// {
|
|
||||||
// *stream << " ";
|
|
||||||
// }
|
|
||||||
// *stream << m_line[i];
|
|
||||||
// }
|
|
||||||
// *stream << endl;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//size_t LineParser::ParsedLines() const
|
|
||||||
//{
|
|
||||||
// return m_currentLine;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//const char *LineParser::Param(const size_t param) const
|
|
||||||
//{
|
|
||||||
// return m_line[param].c_str();
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//const char *LineParser::Line() const
|
|
||||||
//{
|
|
||||||
// return m_unparsed.c_str();
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
// NOTE: commented because unused
|
|
||||||
|
|
||||||
//template<class T>
|
|
||||||
//class MemBlock {
|
|
||||||
// public:
|
|
||||||
// MemBlock()
|
|
||||||
// : fSize(0),
|
|
||||||
// fBuffer(NULL)
|
|
||||||
// {}
|
|
||||||
//
|
|
||||||
// MemBlock(const MemBlock<T>& src)
|
|
||||||
// : fSize(0),
|
|
||||||
// fBuffer(NULL)
|
|
||||||
// {
|
|
||||||
// if (src.fBuffer) {
|
|
||||||
// SetSize(src.fSize);
|
|
||||||
// memcpy(fBuffer, src.fBuffer, src.fSize);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// MemBlock<T>& operator=(const MemBlock<T>& src)
|
|
||||||
// {
|
|
||||||
// if (this != &src) {
|
|
||||||
// SetSize(src.fSize);
|
|
||||||
// if (fBuffer)
|
|
||||||
// memcpy(fBuffer, src.fBuffer, src.fSize);
|
|
||||||
// }
|
|
||||||
// return (*this);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// ~MemBlock()
|
|
||||||
// {
|
|
||||||
// free(fBuffer);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// void SetSize(const size_t size)
|
|
||||||
// {
|
|
||||||
// size_t oldsize = Size();
|
|
||||||
// if (oldsize != size) {
|
|
||||||
// if (!fBuffer && size) {
|
|
||||||
// fBuffer = malloc(size);
|
|
||||||
// if (!fBuffer)
|
|
||||||
// throw "Out of memory";
|
|
||||||
// } else if (fBuffer && size) {
|
|
||||||
// void *newBuf = realloc(fBuffer, size);
|
|
||||||
// if (newBuf)
|
|
||||||
// fBuffer = newBuf;
|
|
||||||
// else
|
|
||||||
// throw "Out of memory";
|
|
||||||
// } else if (fBuffer && !size) {
|
|
||||||
// free(fBuffer);
|
|
||||||
// fBuffer = 0;
|
|
||||||
// }
|
|
||||||
// fSize = size;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// void* Buffer() const { return fBuffer; }
|
|
||||||
// T* Access() const { return (T*)fBuffer; }
|
|
||||||
// T& operator[](size_t i) const
|
|
||||||
// {
|
|
||||||
// return Access()[i];
|
|
||||||
// }
|
|
||||||
// size_t Size() const { return fSize; }
|
|
||||||
//
|
|
||||||
// protected:
|
|
||||||
// size_t fSize;
|
|
||||||
// void* fBuffer;
|
|
||||||
//};
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//static int
|
|
||||||
//strprintf(string &str, const char * format, ...)
|
|
||||||
//{
|
|
||||||
// va_list argptr;
|
|
||||||
//
|
|
||||||
// char strfix[128];
|
|
||||||
//
|
|
||||||
// va_start(argptr, format);
|
|
||||||
// int ret = vsnprintf(strfix, 128, format, argptr);
|
|
||||||
// va_end(argptr);
|
|
||||||
//
|
|
||||||
// if (ret == -1) {
|
|
||||||
// MemBlock<char> strbuf;
|
|
||||||
// strbuf.SetSize(128);
|
|
||||||
// while (ret == -1) {
|
|
||||||
// strbuf.SetSize(strbuf.Size() * 2);
|
|
||||||
// va_start(argptr, format);
|
|
||||||
// ret = vsnprintf(strbuf.Access(), strbuf.Size(), format, argptr);
|
|
||||||
// va_end(argptr);
|
|
||||||
// }
|
|
||||||
// str.assign(strbuf.Access());
|
|
||||||
// } else if (ret >= 128) {
|
|
||||||
// MemBlock<char> strbuf;
|
|
||||||
// strbuf.SetSize(ret + 1);
|
|
||||||
// va_start(argptr, format);
|
|
||||||
// ret = vsnprintf(strbuf.Access(), ret + 1, format, argptr);
|
|
||||||
// va_end(argptr);
|
|
||||||
// str.assign(strbuf.Access());
|
|
||||||
// } else {
|
|
||||||
// str.assign(strfix);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return ret;
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
static double
|
|
||||||
valtod(const char* exp, const char** end)
|
|
||||||
{
|
|
||||||
// http://en.wikipedia.org/wiki/SI_prefix
|
|
||||||
|
|
||||||
char *endptr;
|
|
||||||
double temp = strtod(exp, &endptr);
|
|
||||||
if (endptr == exp || !*endptr) {
|
|
||||||
if (end)
|
|
||||||
*end = endptr;
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (end)
|
|
||||||
*end = endptr + 1;
|
|
||||||
|
|
||||||
switch (*endptr) {
|
|
||||||
/* case 'Y': // yotta
|
|
||||||
return temp * 1.E24;
|
|
||||||
case 'Z': // zetta
|
|
||||||
return temp * 1.E21;
|
|
||||||
case 'E': // exa, incompatible with exponent!
|
|
||||||
return temp * 1.E18;*/
|
|
||||||
case 'P': // peta
|
|
||||||
return temp * 1.E15;
|
|
||||||
case 'T': // tera
|
|
||||||
return temp * 1.E12;
|
|
||||||
case 'G': // giga
|
|
||||||
return temp * 1.E9;
|
|
||||||
case 'M': // mega
|
|
||||||
return temp * 1.E6;
|
|
||||||
case 'k': // kilo
|
|
||||||
return temp * 1.E3;
|
|
||||||
case 'h': // hecto
|
|
||||||
return temp * 1.E2;
|
|
||||||
case 'd':
|
|
||||||
if (endptr[1] == 'a') {
|
|
||||||
if (end)
|
|
||||||
*end = endptr + 2;
|
|
||||||
return temp * 1.E1; // deca
|
|
||||||
} else
|
|
||||||
return temp * 1.E-1; // deci
|
|
||||||
case 'c': // centi
|
|
||||||
return temp * 1.E-2;
|
|
||||||
case 'm': // milli
|
|
||||||
return temp * 1.E-3;
|
|
||||||
case 'u': // micro
|
|
||||||
return temp * 1.E-6;
|
|
||||||
case 'n': // nano
|
|
||||||
return temp * 1.E-9;
|
|
||||||
case 'p': // pico
|
|
||||||
return temp * 1.E-12;
|
|
||||||
case 'f': // femto
|
|
||||||
return temp * 1.E-15;
|
|
||||||
case 'a': // atto
|
|
||||||
return temp * 1.E-18;
|
|
||||||
case 'z': // zepto
|
|
||||||
return temp * 1.E-21;
|
|
||||||
case 'y': // yocto
|
|
||||||
return temp * 1.E-24;
|
|
||||||
}
|
|
||||||
if (end)
|
|
||||||
*end = endptr;
|
|
||||||
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: commented because unused
|
|
||||||
|
|
||||||
//static double
|
|
||||||
//exptod(const char* str, const char** end)
|
|
||||||
//{
|
|
||||||
// Expression exp;
|
|
||||||
//
|
|
||||||
// const char* evalEnd = str + strlen(str);
|
|
||||||
// double temp = exp.Evaluate(str, evalEnd);
|
|
||||||
//
|
|
||||||
// const char* err = exp.Error();
|
|
||||||
// if (end)
|
|
||||||
// *end = err ? err : evalEnd;
|
|
||||||
//
|
|
||||||
// return temp;
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//static string
|
|
||||||
//dtostr(const double value, const unsigned int precision, const char mode)
|
|
||||||
//{
|
|
||||||
// if (value == 0.0)
|
|
||||||
// return "0";
|
|
||||||
//
|
|
||||||
// string str;
|
|
||||||
// char prefix[2];
|
|
||||||
// prefix[0] = 0;
|
|
||||||
// prefix[1] = 0;
|
|
||||||
//
|
|
||||||
// if (mode == 1) {
|
|
||||||
// // exp3
|
|
||||||
// double exp = floor(log10(fabs(value)) / 3.) * 3;
|
|
||||||
// string format;
|
|
||||||
// strprintf(format, "%%.%dGE%%ld", precision);
|
|
||||||
// strprintf(str, format.c_str(), value / pow(10., exp), exp);
|
|
||||||
// } else if (mode == 2) {
|
|
||||||
// // prefix
|
|
||||||
// double exp = floor(log10(fabs(value)) / 3.) * 3;
|
|
||||||
// string format;
|
|
||||||
// strprintf(format, "%%.%dG", precision);
|
|
||||||
// strprintf(str, format.c_str(), value / pow(10., exp));
|
|
||||||
// switch (int(exp)) {
|
|
||||||
// case 24: // yotta
|
|
||||||
// prefix[0] = 'Y';
|
|
||||||
// break;
|
|
||||||
// case 21: // zetta
|
|
||||||
// prefix[0] = 'Z';
|
|
||||||
// break;
|
|
||||||
// case 18: // exa
|
|
||||||
// prefix[0] = 'E';
|
|
||||||
// break;
|
|
||||||
// case 15: // peta
|
|
||||||
// prefix[0] = 'P';
|
|
||||||
// break;
|
|
||||||
// case 12: // tera
|
|
||||||
// prefix[0] = 'T';
|
|
||||||
// break;
|
|
||||||
// case 9: // giga
|
|
||||||
// prefix[0] = 'G';
|
|
||||||
// break;
|
|
||||||
// case 6: // mega
|
|
||||||
// prefix[0] = 'M';
|
|
||||||
// break;
|
|
||||||
// case 3: // kilo
|
|
||||||
// prefix[0] = 'k';
|
|
||||||
// break;
|
|
||||||
// case -3: // milli
|
|
||||||
// prefix[0] = 'm';
|
|
||||||
// break;
|
|
||||||
// case -6: // micro
|
|
||||||
// prefix[0] = 'u';
|
|
||||||
// break;
|
|
||||||
// case -9: // nano
|
|
||||||
// prefix[0] = 'n';
|
|
||||||
// break;
|
|
||||||
// case -12: // pico
|
|
||||||
// prefix[0] = 'p';
|
|
||||||
// break;
|
|
||||||
// case -15: // femto
|
|
||||||
// prefix[0] = 'f';
|
|
||||||
// break;
|
|
||||||
// case -18: // atto
|
|
||||||
// prefix[0] = 'a';
|
|
||||||
// break;
|
|
||||||
// case -21: // zepto
|
|
||||||
// prefix[0] = 'z';
|
|
||||||
// break;
|
|
||||||
// case -24: // yocto
|
|
||||||
// prefix[0] = 'y';
|
|
||||||
// break;
|
|
||||||
// default:
|
|
||||||
// if (exp) {
|
|
||||||
// strprintf(format, "%%.%dGE%%ld", precision);
|
|
||||||
// strprintf(str, format.c_str(), value / pow(10., exp), exp);
|
|
||||||
// } else {
|
|
||||||
// strprintf(format, "%%.%dG", precision);
|
|
||||||
// strprintf(str, format.c_str(), value);
|
|
||||||
// }
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
// // exp
|
|
||||||
// string format;
|
|
||||||
// strprintf(format, "%%.%dG", precision);
|
|
||||||
// strprintf(str, format.c_str(), value);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// return string(str) + prefix;
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
|
||||||
|
|
||||||
|
|
||||||
Expression::Expression()
|
|
||||||
: fAglf(1.),
|
|
||||||
fErrorPtr(NULL),
|
|
||||||
fTrig(false)
|
|
||||||
{
|
|
||||||
// NOTE: these seem to be hard coded anyways...
|
|
||||||
fFunctionNames.push_back("sin("); // 0
|
|
||||||
fFunctionTypes.push_back(1);
|
|
||||||
fFunctionNames.push_back("asin("); // 1
|
|
||||||
fFunctionTypes.push_back(2);
|
|
||||||
fFunctionNames.push_back("cos("); // 2
|
|
||||||
fFunctionTypes.push_back(1);
|
|
||||||
fFunctionNames.push_back("acos("); // 3
|
|
||||||
fFunctionTypes.push_back(2);
|
|
||||||
fFunctionNames.push_back("tan("); // 4
|
|
||||||
fFunctionTypes.push_back(1);
|
|
||||||
fFunctionNames.push_back("atan("); // 5
|
|
||||||
fFunctionTypes.push_back(2);
|
|
||||||
fFunctionNames.push_back("ln("); // 6
|
|
||||||
fFunctionTypes.push_back(0);
|
|
||||||
fFunctionNames.push_back("lg("); // 7
|
|
||||||
fFunctionTypes.push_back(0);
|
|
||||||
fFunctionNames.push_back("sqrt("); // 8
|
|
||||||
fFunctionTypes.push_back(0);
|
|
||||||
fFunctionNames.push_back("("); // 9
|
|
||||||
fFunctionTypes.push_back(0);
|
|
||||||
|
|
||||||
SetConstant("e", M_E);
|
|
||||||
SetConstant("pi", M_PI);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
Expression::SetAglf(const double value)
|
|
||||||
{
|
|
||||||
fAglf = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
Expression::SetConstant(const char* name, const double value)
|
|
||||||
{
|
|
||||||
for (size_t i = 0; name[i]; i++) {
|
|
||||||
if (!isalnum(name[i])) {
|
|
||||||
throw "Illegal character in constant name";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (size_t i = 0; i < fConstantNames.size(); i++) {
|
|
||||||
if (!strcmp(name, fConstantNames[i].c_str())) {
|
|
||||||
fConstantValues[i] = value;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fConstantNames.push_back(name);
|
|
||||||
fConstantValues.push_back(value);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
double
|
|
||||||
Expression::Evaluate(const char* exp)
|
|
||||||
{
|
|
||||||
const char* evalEnd = exp + strlen(exp);
|
|
||||||
return Evaluate(exp, evalEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
double
|
|
||||||
Expression::Evaluate(const char* begin, const char* end, const bool allowWhiteSpaces)
|
|
||||||
{
|
|
||||||
const char* curptr = begin;
|
|
||||||
int state = 1;
|
|
||||||
double operand;
|
|
||||||
double sum = 0.;
|
|
||||||
double prod = 0.0;
|
|
||||||
double power = 0.0;
|
|
||||||
|
|
||||||
if (begin[0] == 0) {
|
|
||||||
fErrorPtr = begin;
|
|
||||||
return 0.;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fErrorPtr) {
|
|
||||||
return 0.;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
const char *operandEnd;
|
|
||||||
bool minusBeforeOperand = false;
|
|
||||||
bool numberOperand = true;
|
|
||||||
|
|
||||||
if (allowWhiteSpaces) {
|
|
||||||
while (curptr < end && isspace(curptr[0]))
|
|
||||||
curptr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (curptr[0] == '-')
|
|
||||||
minusBeforeOperand = true;
|
|
||||||
|
|
||||||
operand = valtod(curptr, &operandEnd);
|
|
||||||
|
|
||||||
if (operandEnd == curptr) {
|
|
||||||
// operand not a number
|
|
||||||
const char *operandStart = curptr;
|
|
||||||
double operandSign = 1.;
|
|
||||||
|
|
||||||
numberOperand = false;
|
|
||||||
|
|
||||||
if (curptr[0] == '+') {
|
|
||||||
++operandStart;
|
|
||||||
} else if (curptr[0] == '-') {
|
|
||||||
++operandStart;
|
|
||||||
operandSign = -1.;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate through functions
|
|
||||||
size_t i;
|
|
||||||
for (i = 0; i < fFunctionNames.size(); i++) {
|
|
||||||
if (!strncmp(operandStart, fFunctionNames[i].c_str(), fFunctionNames[i].size())) {
|
|
||||||
const char *functionArg = operandStart + fFunctionNames[i].size();
|
|
||||||
const char *chptr = functionArg - 1;
|
|
||||||
const char *prptr = functionArg - 1;
|
|
||||||
|
|
||||||
if (fFunctionTypes[i])
|
|
||||||
fTrig = true;
|
|
||||||
|
|
||||||
// Find closing paranthesis
|
|
||||||
while (prptr) {
|
|
||||||
chptr = strchr(chptr + 1, ')');
|
|
||||||
prptr = strchr(prptr + 1, '(');
|
|
||||||
if (prptr > chptr)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chptr) {
|
|
||||||
// Closing paranthesis
|
|
||||||
if (fFunctionTypes[i] == 1) {
|
|
||||||
// Trig
|
|
||||||
operand = operandSign * _ApplyFunction(fAglf * Evaluate(functionArg, chptr), i);
|
|
||||||
if (fabs(operand) < NOLLF)
|
|
||||||
operand = 0;
|
|
||||||
} else if (fFunctionTypes[i] == 2) {
|
|
||||||
// Inv trig
|
|
||||||
operand = operandSign / fAglf * _ApplyFunction(Evaluate(functionArg, chptr), i);
|
|
||||||
} else {
|
|
||||||
// Normal
|
|
||||||
operand = operandSign * _ApplyFunction(Evaluate(functionArg, chptr), i);
|
|
||||||
}
|
|
||||||
operandEnd = chptr + 1;
|
|
||||||
} else {
|
|
||||||
// No closing paranthesis
|
|
||||||
if (fFunctionTypes[i] == 1) {
|
|
||||||
operand = operandSign * _ApplyFunction(fAglf * Evaluate(functionArg, end), i);
|
|
||||||
if (fabs(operand) < NOLLF)
|
|
||||||
operand = 0;
|
|
||||||
} else if (fFunctionTypes[i] == 2) {
|
|
||||||
operand = operandSign / fAglf * _ApplyFunction(Evaluate(functionArg, end), i);
|
|
||||||
} else {
|
|
||||||
operand = operandSign * _ApplyFunction(Evaluate(functionArg, end), i);
|
|
||||||
}
|
|
||||||
operandEnd = end;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fErrorPtr) {
|
|
||||||
return 0.;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate through constants
|
|
||||||
if (i == fFunctionNames.size()) {
|
|
||||||
// Only search if no function found
|
|
||||||
for (i = 0; i < fConstantNames.size(); i++) {
|
|
||||||
if (!strncmp(operandStart, fConstantNames[i].c_str(), fConstantNames[i].size()) && !isalnum(operandStart[fConstantNames[i].size()])) {
|
|
||||||
operandEnd = operandStart + fConstantNames[i].size();
|
|
||||||
operand = operandSign * fConstantValues[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (operandEnd > end) {
|
|
||||||
fErrorPtr = end;
|
|
||||||
return 0.;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate expression in correct order
|
|
||||||
|
|
||||||
// state == 1 => term => sum + operand
|
|
||||||
// state == 2 => product => sum + prod * operand
|
|
||||||
// state == 3 => quotient => sum + prod / operand
|
|
||||||
// state == 4 => plus & power => sum + power ^ operand
|
|
||||||
// state == 5 => minus & power => sum - power ^ operand
|
|
||||||
// state == 6 => product & power => sum + prod * power ^ operand
|
|
||||||
// state == 7 => quotient & power => sum + prod / power ^ operand
|
|
||||||
|
|
||||||
if (curptr != operandEnd) {
|
|
||||||
// number?
|
|
||||||
switch (state) {
|
|
||||||
case 1: // term
|
|
||||||
if (operandEnd == end) {
|
|
||||||
return sum + operand;
|
|
||||||
}
|
|
||||||
switch (operandEnd[0]) {
|
|
||||||
// Check next
|
|
||||||
case '+':
|
|
||||||
case '-':
|
|
||||||
curptr = operandEnd;
|
|
||||||
sum = sum + operand;
|
|
||||||
break;
|
|
||||||
case '*':
|
|
||||||
curptr = operandEnd + 1;
|
|
||||||
prod = operand;
|
|
||||||
state = 2;
|
|
||||||
break;
|
|
||||||
case '/':
|
|
||||||
curptr = operandEnd + 1;
|
|
||||||
prod = operand;
|
|
||||||
state = 3;
|
|
||||||
break;
|
|
||||||
case '^':
|
|
||||||
curptr = operandEnd + 1;
|
|
||||||
power = operand;
|
|
||||||
if (minusBeforeOperand) {
|
|
||||||
power = power * -1.;
|
|
||||||
state = 5;
|
|
||||||
} else {
|
|
||||||
state = 4;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (numberOperand && isalpha(operandEnd[0])) {
|
|
||||||
// Assume multiplication of function/constant without *
|
|
||||||
curptr = operandEnd;
|
|
||||||
prod = operand;
|
|
||||||
state = 2;
|
|
||||||
} else {
|
|
||||||
fErrorPtr = operandEnd;
|
|
||||||
return 0.;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2: // product
|
|
||||||
if (operandEnd == end) {
|
|
||||||
return sum + prod * operand;
|
|
||||||
}
|
|
||||||
switch (operandEnd[0]) {
|
|
||||||
// Check next
|
|
||||||
case '+':
|
|
||||||
case '-':
|
|
||||||
curptr = operandEnd;
|
|
||||||
sum = sum + prod * operand;
|
|
||||||
state = 1;
|
|
||||||
break;
|
|
||||||
case '*':
|
|
||||||
curptr = operandEnd + 1;
|
|
||||||
prod = prod * operand;
|
|
||||||
break;
|
|
||||||
case '/':
|
|
||||||
curptr = operandEnd + 1;
|
|
||||||
prod = prod * operand;
|
|
||||||
state = 3;
|
|
||||||
break;
|
|
||||||
case '^':
|
|
||||||
curptr = operandEnd + 1;
|
|
||||||
power = operand;
|
|
||||||
state = 6;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fErrorPtr = operandEnd;
|
|
||||||
return 0.;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3: // quotient
|
|
||||||
if (operandEnd == end) {
|
|
||||||
return sum + prod / operand;
|
|
||||||
}
|
|
||||||
switch (operandEnd[0]) {
|
|
||||||
// Check next
|
|
||||||
case '+':
|
|
||||||
case '-':
|
|
||||||
curptr = operandEnd;
|
|
||||||
sum = sum + prod / operand;
|
|
||||||
state = 1;
|
|
||||||
break;
|
|
||||||
case '*':
|
|
||||||
curptr = operandEnd + 1;
|
|
||||||
prod = prod / operand;
|
|
||||||
state = 2;
|
|
||||||
break;
|
|
||||||
case '/':
|
|
||||||
curptr = operandEnd + 1;
|
|
||||||
prod = prod / operand;
|
|
||||||
break;
|
|
||||||
case '^':
|
|
||||||
curptr = operandEnd + 1;
|
|
||||||
power = operand;
|
|
||||||
state = 7;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fErrorPtr = operandEnd;
|
|
||||||
return 0.;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 4: // plus&power
|
|
||||||
if (operandEnd == end) {
|
|
||||||
return sum + pow(power, operand);
|
|
||||||
}
|
|
||||||
switch (operandEnd[0]) {
|
|
||||||
// Check next
|
|
||||||
case '+':
|
|
||||||
case '-':
|
|
||||||
curptr = operandEnd;
|
|
||||||
sum = sum + pow(power, operand);
|
|
||||||
state = 1;
|
|
||||||
break;
|
|
||||||
case '*':
|
|
||||||
curptr = operandEnd + 1;
|
|
||||||
prod = pow(power, operand);
|
|
||||||
state = 2;
|
|
||||||
break;
|
|
||||||
case '/':
|
|
||||||
curptr = operandEnd + 1;
|
|
||||||
prod = pow(power, operand);
|
|
||||||
state = 3;
|
|
||||||
break;
|
|
||||||
case '^':
|
|
||||||
curptr = operandEnd + 1;
|
|
||||||
power = pow(power, operand);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fErrorPtr = operandEnd;
|
|
||||||
return 0.;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 5: // minus&power
|
|
||||||
if (operandEnd == end) {
|
|
||||||
return sum - pow(power, operand);
|
|
||||||
}
|
|
||||||
switch (operandEnd[0]) {
|
|
||||||
// Check next
|
|
||||||
case '+':
|
|
||||||
case '-':
|
|
||||||
curptr = operandEnd;
|
|
||||||
sum = sum - pow(power, operand);
|
|
||||||
state = 1;
|
|
||||||
break;
|
|
||||||
case '*':
|
|
||||||
curptr = operandEnd + 1;
|
|
||||||
prod = pow(power, operand);
|
|
||||||
state = 2;
|
|
||||||
break;
|
|
||||||
case '/':
|
|
||||||
curptr = operandEnd + 1;
|
|
||||||
prod = pow(power, operand);
|
|
||||||
state = 3;
|
|
||||||
break;
|
|
||||||
case '^':
|
|
||||||
curptr = operandEnd + 1;
|
|
||||||
power = pow(power, operand);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fErrorPtr = operandEnd;
|
|
||||||
return 0.;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 6: // product&power
|
|
||||||
if (operandEnd == end) {
|
|
||||||
return sum + prod * pow(power, operand);
|
|
||||||
}
|
|
||||||
switch (operandEnd[0]) {
|
|
||||||
// Check next
|
|
||||||
case '+':
|
|
||||||
case '-':
|
|
||||||
curptr = operandEnd;
|
|
||||||
sum = sum + prod * pow(power, operand);
|
|
||||||
state = 1;
|
|
||||||
break;
|
|
||||||
case '*':
|
|
||||||
curptr = operandEnd + 1;
|
|
||||||
prod = prod * pow(power, operand);
|
|
||||||
state = 2;
|
|
||||||
break;
|
|
||||||
case '/':
|
|
||||||
curptr = operandEnd + 1;
|
|
||||||
prod = prod * pow(power, operand);
|
|
||||||
state = 3;
|
|
||||||
break;
|
|
||||||
case '^':
|
|
||||||
curptr = operandEnd + 1;
|
|
||||||
power = pow(power, operand);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fErrorPtr = operandEnd;
|
|
||||||
return 0.;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 7: // quotient&power
|
|
||||||
if (operandEnd == end) {
|
|
||||||
return sum + prod / pow(power, operand);
|
|
||||||
}
|
|
||||||
switch (operandEnd[0]) {
|
|
||||||
// Check next
|
|
||||||
case '+':
|
|
||||||
case '-':
|
|
||||||
curptr = operandEnd;
|
|
||||||
sum = sum + prod / pow(power, operand);
|
|
||||||
state = 1;
|
|
||||||
break;
|
|
||||||
case '*':
|
|
||||||
curptr = operandEnd + 1;
|
|
||||||
prod = prod / pow(power, operand);
|
|
||||||
state = 2;
|
|
||||||
break;
|
|
||||||
case '/':
|
|
||||||
curptr = operandEnd + 1;
|
|
||||||
prod = prod / pow(power, operand);
|
|
||||||
state = 3;
|
|
||||||
break;
|
|
||||||
case '^':
|
|
||||||
curptr = operandEnd + 1;
|
|
||||||
power = pow(power, operand);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fErrorPtr = operandEnd;
|
|
||||||
return 0.;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
fErrorPtr = operandEnd;
|
|
||||||
return 0.;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fErrorPtr = curptr;
|
|
||||||
return 0.;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const char*
|
|
||||||
Expression::Error()
|
|
||||||
{
|
|
||||||
const char *retval = fErrorPtr;
|
|
||||||
fErrorPtr = NULL;
|
|
||||||
fTrig = false;
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark -
|
|
||||||
|
|
||||||
|
|
||||||
double
|
|
||||||
Expression::_ApplyFunction(const double x, const size_t number) const
|
|
||||||
{
|
|
||||||
switch (number) {
|
|
||||||
case 0:
|
|
||||||
return sin(x);
|
|
||||||
case 1:
|
|
||||||
return asin(x);
|
|
||||||
case 2:
|
|
||||||
return cos(x);
|
|
||||||
case 3:
|
|
||||||
return acos(x);
|
|
||||||
case 4:
|
|
||||||
return tan(x);
|
|
||||||
case 5:
|
|
||||||
return atan(x);
|
|
||||||
case 6:
|
|
||||||
return log(x);
|
|
||||||
case 7:
|
|
||||||
return log10(x);
|
|
||||||
case 8:
|
|
||||||
return sqrt(x);
|
|
||||||
default:
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2006 Haiku, Inc. All Rights Reserved.
|
|
||||||
* Copyright 2004 Daniel Wallner. All Rights Reserved.
|
|
||||||
* Distributed under the terms of the MIT License.
|
|
||||||
*
|
|
||||||
* Authors:
|
|
||||||
* Daniel Wallner <[email protected]>
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef PARSER_H
|
|
||||||
#define PARSER_H
|
|
||||||
|
|
||||||
#include <vector.h>
|
|
||||||
#include <string>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
//class LineParser {
|
|
||||||
// public:
|
|
||||||
// LineParser(std::istream *stream);
|
|
||||||
//
|
|
||||||
// void AddSeparator(const char c);
|
|
||||||
//
|
|
||||||
// size_t SetToNext(bool toUpperCase = false);
|
|
||||||
// void WriteCompressed(std::string *s) const;
|
|
||||||
// void WriteCompressed(std::ostream *stream) const;
|
|
||||||
//
|
|
||||||
// size_t ParsedLines() const;
|
|
||||||
// const char *Param(const size_t param) const;
|
|
||||||
// const char *Line() const;
|
|
||||||
//
|
|
||||||
// private:
|
|
||||||
// LineParser();
|
|
||||||
//
|
|
||||||
// std::istream *m_stream;
|
|
||||||
// size_t m_currentLine;
|
|
||||||
// std::string m_unparsed;
|
|
||||||
// std::vector<std::string> m_line;
|
|
||||||
// std::vector<char> m_separators;
|
|
||||||
//};
|
|
||||||
|
|
||||||
class Expression {
|
|
||||||
public:
|
|
||||||
Expression();
|
|
||||||
|
|
||||||
void SetAglf(const double value);
|
|
||||||
bool SetConstant(const char* name,
|
|
||||||
const double value);
|
|
||||||
|
|
||||||
double Evaluate(const char* exp);
|
|
||||||
double Evaluate(const char* begin, const char* end,
|
|
||||||
const bool allowWhiteSpaces = false);
|
|
||||||
const char* Error();
|
|
||||||
|
|
||||||
private:
|
|
||||||
double _ApplyFunction(const double x,
|
|
||||||
const size_t number) const;
|
|
||||||
|
|
||||||
double fAglf;
|
|
||||||
const char* fErrorPtr;
|
|
||||||
bool fTrig;
|
|
||||||
|
|
||||||
std::vector<std::string> fFunctionNames;
|
|
||||||
std::vector<char> fFunctionTypes;
|
|
||||||
|
|
||||||
std::vector<std::string> fConstantNames;
|
|
||||||
std::vector<double> fConstantValues;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // PARSER_H
|
|
||||||
Reference in New Issue
Block a user