|
|
/*
|
|
|
* KmPlot - a math. function plotter for the KDE-Desktop
|
|
|
*
|
|
|
* Copyright (C) 1998, 1999 Klaus-Dieter M<>ler
|
|
|
* 2000, 2002 kd.moeller@t-online.de
|
|
|
*
|
|
|
* This file is part of the KDE Project.
|
|
|
* KmPlot is part of the KDE-EDU Project.
|
|
|
*
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
* (at your option) any later version.
|
|
|
*
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
* GNU General Public License for more details.
|
|
|
*
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Cambridge, MA 02110-1301, USA.
|
|
|
*
|
|
|
*/
|
|
|
|
|
|
// standard c(++) includes
|
|
|
#include <stdlib.h>
|
|
|
#include <stdio.h>
|
|
|
#include <math.h>
|
|
|
|
|
|
//KDE includes
|
|
|
#include <kdebug.h>
|
|
|
#include <klocale.h>
|
|
|
#include <kmessagebox.h>
|
|
|
|
|
|
// local includes
|
|
|
#include "parser.h"
|
|
|
#include "settings.h"
|
|
|
#include "xparser.h"
|
|
|
|
|
|
double Parser::m_anglemode = 0;
|
|
|
|
|
|
/// List of predefined functions.
|
|
|
Parser::Mfkt Parser::mfkttab[ FANZ ]=
|
|
|
{
|
|
|
{"tanh", ltanh}, // Tangens hyperbolicus
|
|
|
{"tan", ltan}, // Tangens
|
|
|
{"sqrt", sqrt}, // Square root
|
|
|
{"sqr", sqr}, // Square
|
|
|
{"sinh", lsinh}, // Sinus hyperbolicus
|
|
|
{"sin", lsin}, // Sinus
|
|
|
{"sign", sign}, // Signum
|
|
|
{"sech", sech}, // Secans hyperbolicus
|
|
|
{"sec", sec}, // Secans
|
|
|
{"log", llog}, // Logarithm base 10
|
|
|
{"ln", ln}, // Logarithm base e
|
|
|
{"exp", exp}, // Exponential function base e
|
|
|
{"coth", coth}, // Co-Tangens hyperbolicus
|
|
|
{"cot", cot}, // Co-Tangens = 1/tan
|
|
|
{"cosh", lcosh}, // Cosinus hyperbolicus
|
|
|
{"cosech", cosech}, // Co-Secans hyperbolicus
|
|
|
{"cosec", cosec}, // Co-Secans
|
|
|
{"cos", lcos}, // Cosinus
|
|
|
{"artanh", artanh}, // Area-tangens hyperbolicus = inverse of tanh
|
|
|
{"arsinh", arsinh}, // Area-sinus hyperbolicus = inverse of sinh
|
|
|
{"arsech", arsech}, // Area-secans hyperbolicus = invers of sech
|
|
|
{"arctanh", artanh}, // The same as artanh
|
|
|
{"arcsinh", arsinh}, // The same as arsinh
|
|
|
{"arccosh", arcosh}, // The same as arcosh
|
|
|
{"arctan", arctan}, // Arcus tangens = inverse of tan
|
|
|
{"arcsin", arcsin}, // Arcus sinus = inverse of sin
|
|
|
{"arcsec", arcsec}, // Arcus secans = inverse of sec
|
|
|
{"arcoth", arcoth}, // Area-co-tangens hyperbolicus = inverse of coth
|
|
|
{"arcosh", arcosh}, // Area-cosinus hyperbolicus = inverse of cosh
|
|
|
{"arcosech", arcosech}, // Area-co-secans hyperbolicus = inverse of cosech
|
|
|
{"arccot", arccot}, // Arcus co-tangens = inverse of cotan
|
|
|
{"arccosec", arccosec}, // Arcus co-secans = inverse of cosec
|
|
|
{"arccos", arccos}, // Arcus cosinus = inverse of cos
|
|
|
{"abs", fabs} // Absolute value
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
Ufkt::Ufkt()
|
|
|
{
|
|
|
id = 0;
|
|
|
mem = 0;
|
|
|
mptr = 0;
|
|
|
k = 0;
|
|
|
oldy = 0;
|
|
|
f_mode = true;
|
|
|
f1_mode = false;
|
|
|
f2_mode = false;
|
|
|
integral_mode = false;
|
|
|
integral_use_precision = false;
|
|
|
linewidth = 0;
|
|
|
f1_linewidth = 0;
|
|
|
f2_linewidth = 0;
|
|
|
integral_linewidth = 0;
|
|
|
double dmin = 0.0;
|
|
|
dmax = 0.0;
|
|
|
oldyprim = 0.0;
|
|
|
oldx = 0.0;
|
|
|
starty = 0.0;
|
|
|
startx = 0.0;
|
|
|
integral_precision = 0.0;
|
|
|
use_slider = -1;
|
|
|
usecustomxmin = false;
|
|
|
usecustomxmax = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
Ufkt::~Ufkt()
|
|
|
{
|
|
|
}
|
|
|
|
|
|
|
|
|
Parser::Parser()
|
|
|
{
|
|
|
ps_init();
|
|
|
}
|
|
|
|
|
|
|
|
|
void Parser::ps_init()
|
|
|
{
|
|
|
evalflg=0;
|
|
|
Ufkt temp;
|
|
|
temp.fname = temp.fvar = temp.fpar = temp.fstr = "";
|
|
|
temp.mem=new unsigned char [MEMSIZE];
|
|
|
ufkt.append(temp );
|
|
|
current_item = ufkt.begin();
|
|
|
}
|
|
|
|
|
|
|
|
|
Parser::~Parser()
|
|
|
{
|
|
|
kdDebug() << "Exiting......" << endl;
|
|
|
for( TQValueVector<Ufkt>::iterator it = ufkt.begin(); it != ufkt.end(); ++it)
|
|
|
{
|
|
|
kdDebug() << "Deleting something... :-)" << endl;
|
|
|
delete [](*it).mem;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void Parser::setAngleMode(int angle)
|
|
|
{
|
|
|
if(angle==0)
|
|
|
m_anglemode = 1;
|
|
|
else
|
|
|
m_anglemode = M_PI/180;
|
|
|
}
|
|
|
|
|
|
void Parser::setDecimalSymbol(const TQString c)
|
|
|
{
|
|
|
m_decimalsymbol = c;
|
|
|
}
|
|
|
|
|
|
double Parser::anglemode()
|
|
|
{
|
|
|
return m_anglemode;
|
|
|
}
|
|
|
|
|
|
|
|
|
uint Parser::getNewId()
|
|
|
{
|
|
|
uint i = 0;
|
|
|
bool found = false;
|
|
|
while (1 )
|
|
|
{
|
|
|
found = false;
|
|
|
for( TQValueVector<Ufkt>::iterator it = ufkt.begin(); it != ufkt.end(); ++it)
|
|
|
{
|
|
|
if (it->id == i && !it->fname.isEmpty())
|
|
|
{
|
|
|
found = true;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
if (!found)
|
|
|
return i;
|
|
|
++i;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
double Parser::eval(TQString str)
|
|
|
{
|
|
|
stack=new double [STACKSIZE];
|
|
|
stkptr=stack;
|
|
|
evalflg=1;
|
|
|
|
|
|
fix_expression(str,0);
|
|
|
|
|
|
if ( str.contains('y')!=0)
|
|
|
{
|
|
|
err=9;
|
|
|
delete []stack;
|
|
|
return 0;
|
|
|
}
|
|
|
for (uint i=0;i<str.length();i++ )
|
|
|
if (str.at(i).category() == TQChar::Letter_Uppercase)
|
|
|
{
|
|
|
err=14;
|
|
|
delete []stack;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
lptr=str.latin1();
|
|
|
err=0;
|
|
|
heir1();
|
|
|
if(*lptr!=0 && err==0) err=1;
|
|
|
evalflg=0;
|
|
|
double const erg=*stkptr;
|
|
|
delete [] stack;
|
|
|
if(err==0)
|
|
|
{
|
|
|
errpos=0;
|
|
|
return erg;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
errpos=lptr-(str.latin1())+1;
|
|
|
return 0.;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
int Parser::idValue(int const ix)
|
|
|
{
|
|
|
if ( ix >=0 && ix<(int)ufkt.count() ) // range check
|
|
|
{
|
|
|
if ( !( ufkt.count()==1 && ufkt[0].fname.isEmpty() ) )
|
|
|
return ufkt[ix].id;
|
|
|
}
|
|
|
return -1;
|
|
|
|
|
|
}
|
|
|
|
|
|
int Parser::ixValue(uint const id)
|
|
|
{
|
|
|
int ix=0;
|
|
|
for( TQValueVector<Ufkt>::iterator it = ufkt.begin(); it != ufkt.end(); ++it)
|
|
|
{
|
|
|
if ( it->id ==id)
|
|
|
return ix;
|
|
|
ix++;
|
|
|
}
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
double Parser::fkt(uint const id, double const x)
|
|
|
{
|
|
|
for( TQValueVector<Ufkt>::iterator it = ufkt.begin(); it != ufkt.end(); ++it)
|
|
|
{
|
|
|
if ( it->id == id)
|
|
|
return fkt(it,x);
|
|
|
}
|
|
|
err=13;
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
double Parser::fkt(Ufkt *it, double const x)
|
|
|
{
|
|
|
double *pd, (**pf)(double);
|
|
|
double *stack, *stkptr;
|
|
|
uint *puf;
|
|
|
it->mptr=it->mem;
|
|
|
stack=stkptr= new double [STACKSIZE];
|
|
|
|
|
|
while(1)
|
|
|
{
|
|
|
switch(*it->mptr++)
|
|
|
{
|
|
|
case KONST:
|
|
|
pd=(double*)it->mptr;
|
|
|
*stkptr=*pd++;
|
|
|
it->mptr=(unsigned char*)pd;
|
|
|
break;
|
|
|
case XWERT:
|
|
|
*stkptr=x;
|
|
|
break;
|
|
|
case YWERT:
|
|
|
*stkptr=it->oldy;
|
|
|
break;
|
|
|
case KWERT:
|
|
|
*stkptr=it->k;
|
|
|
break;
|
|
|
case PUSH:
|
|
|
++stkptr;
|
|
|
break;
|
|
|
case PLUS:
|
|
|
stkptr[-1]+=*stkptr;
|
|
|
--stkptr;
|
|
|
break;
|
|
|
case MINUS:
|
|
|
stkptr[-1]-=*stkptr;
|
|
|
--stkptr;
|
|
|
break;
|
|
|
case MULT:
|
|
|
stkptr[-1]*=*stkptr;
|
|
|
--stkptr;
|
|
|
break;
|
|
|
case DIV:
|
|
|
if(*stkptr==0.)*(--stkptr)=HUGE_VAL;
|
|
|
else
|
|
|
{
|
|
|
stkptr[-1]/=*stkptr;
|
|
|
--stkptr;
|
|
|
}
|
|
|
break;
|
|
|
case POW:
|
|
|
stkptr[-1]=pow(*(stkptr-1), *stkptr);
|
|
|
--stkptr;
|
|
|
break;
|
|
|
case NEG:
|
|
|
*stkptr=-*stkptr;
|
|
|
break;
|
|
|
case FKT:
|
|
|
pf=(double(**)(double))it->mptr;
|
|
|
*stkptr=(*pf++)(*stkptr);
|
|
|
it->mptr=(unsigned char*)pf;
|
|
|
break;
|
|
|
case UFKT:
|
|
|
{
|
|
|
puf=(uint*)it->mptr;
|
|
|
uint id = *puf++;
|
|
|
for( TQValueVector<Ufkt>::iterator ite = ufkt.begin(); ite != ufkt.end(); ++ite)
|
|
|
{
|
|
|
if ( ite->id == id)
|
|
|
{
|
|
|
*stkptr=fkt(ite, *stkptr);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
it->mptr=(unsigned char*)puf;
|
|
|
break;
|
|
|
}
|
|
|
case ENDE:
|
|
|
double const erg=*stkptr;
|
|
|
delete [] stack;
|
|
|
return erg;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
int Parser::addfkt(TQString str)
|
|
|
{
|
|
|
TQString const extstr = str;
|
|
|
stkptr=stack=0;
|
|
|
err=0;
|
|
|
errpos=1;
|
|
|
const int p1=str.find('(');
|
|
|
int p2=str.find(',');
|
|
|
const int p3=str.find(")=");
|
|
|
fix_expression(str,p1+4);
|
|
|
|
|
|
if(p1==-1 || p3==-1 || p1>p3)
|
|
|
{ err=4;
|
|
|
return -1;
|
|
|
}
|
|
|
if ( p3+2 == (int) str.length()) //empty function
|
|
|
{ err=11;
|
|
|
return -1;
|
|
|
}
|
|
|
if(p2==-1 || p2>p3) p2=p3;
|
|
|
|
|
|
if( fnameToId(str.left(p1))!=-1 )
|
|
|
{
|
|
|
err=8;
|
|
|
return -1;
|
|
|
}
|
|
|
else
|
|
|
err=0;
|
|
|
|
|
|
if (str.mid(p1+1, p2-p1-1) == "e")
|
|
|
{ err=4;
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
if ( ufkt.begin()->fname.isEmpty() )
|
|
|
{
|
|
|
ufkt.begin()->id = 0;
|
|
|
//kdDebug() << "ufkt.begin()->id:" << ufkt.begin()->id << endl;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
Ufkt temp;
|
|
|
if ( !temp.fstr.isEmpty() && temp.fstr.at(0) == 'y')
|
|
|
temp.id = ufkt.last().id; //the function belongs to the last inserted function
|
|
|
else
|
|
|
temp.id = getNewId();
|
|
|
temp.mem=new unsigned char [MEMSIZE];
|
|
|
ufkt.append(temp );
|
|
|
}
|
|
|
TQString const fname = str.left(p1);
|
|
|
Ufkt *temp = &ufkt.last();
|
|
|
temp->fstr=extstr;
|
|
|
temp->mptr = 0;
|
|
|
temp->fname=fname;
|
|
|
temp->fvar=str.mid(p1+1, p2-p1-1);
|
|
|
if(p2<p3) temp->fpar=str.mid(p2+1, p3-p2-1);
|
|
|
else temp->fpar=""; //.resize(1);
|
|
|
|
|
|
kdDebug() << "temp.id:" << temp->id << endl;
|
|
|
|
|
|
if ( temp->fname != temp->fname.lower() ) //isn't allowed to contain capital letters
|
|
|
{
|
|
|
delfkt(temp);
|
|
|
err=12;
|
|
|
return -1;
|
|
|
}
|
|
|
current_item = temp;
|
|
|
mem=mptr=temp->mem;
|
|
|
lptr=(str.latin1())+p3+2;
|
|
|
heir1();
|
|
|
if(*lptr!=0 && err==0) err=1; // Syntaxfehler
|
|
|
addtoken(ENDE);
|
|
|
if(err!=0)
|
|
|
{
|
|
|
errpos=lptr-(str.latin1())+1;
|
|
|
delfkt(temp);
|
|
|
return -1;
|
|
|
}
|
|
|
errpos=0;
|
|
|
return temp->id; //return the unique ID-number for the function
|
|
|
}
|
|
|
|
|
|
void Parser::reparse(int ix)
|
|
|
{
|
|
|
reparse( &ufkt[ix] );
|
|
|
}
|
|
|
|
|
|
void Parser::reparse(Ufkt *item)
|
|
|
{
|
|
|
kdDebug() << "Reparsing: " << item->fstr << endl;
|
|
|
TQString str = item->fstr.latin1();
|
|
|
err=0;
|
|
|
errpos=1;
|
|
|
|
|
|
const int p1=str.find('(');
|
|
|
int p2=str.find(',');
|
|
|
const int p3=str.find(")=");
|
|
|
|
|
|
fix_expression(str,p1+4);
|
|
|
|
|
|
if(p1==-1 || p3==-1 || p1>p3)
|
|
|
{ err=4;
|
|
|
return;
|
|
|
}
|
|
|
if ( p3+2 == (int) str.length()) //empty function
|
|
|
{ err=11;
|
|
|
return;
|
|
|
}
|
|
|
if(p2==-1 || p2>p3) p2=p3;
|
|
|
|
|
|
if (str.mid(p1+1, p2-p1-1) == "e")
|
|
|
{ err=4;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
item->fname=str.left(p1);
|
|
|
item->fvar=str.mid(p1+1, p2-p1-1);
|
|
|
if(p2<p3) item->fpar=str.mid(p2+1, p3-p2-1);
|
|
|
else item->fpar="";
|
|
|
|
|
|
if ( item->fname != item->fname.lower() ) //isn't allowed to contain capital letters
|
|
|
{
|
|
|
err=12;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
//ixa=ix;
|
|
|
current_item = item;
|
|
|
mem=mptr=item->mem;
|
|
|
lptr=(str.latin1())+p3+2;
|
|
|
heir1();
|
|
|
if(*lptr!=0 && err==0) err=1; // Syntaxfehler
|
|
|
addtoken(ENDE);
|
|
|
errpos=0;
|
|
|
}
|
|
|
|
|
|
void Parser::fix_expression(TQString &str, int const pos)
|
|
|
{
|
|
|
str.remove(" " );
|
|
|
|
|
|
//insert '*' when it is needed
|
|
|
TQChar ch;
|
|
|
bool function = false;
|
|
|
for(uint i=pos; i < str.length();i++)
|
|
|
{
|
|
|
ch = str.at(i);
|
|
|
if ( str.at(i+1)=='(' && ch.category()==TQChar::Letter_Lowercase )
|
|
|
{
|
|
|
TQString str_function(ch);
|
|
|
int n=i-1;
|
|
|
while (n>0 && str.at(n).category() == TQChar::Letter_Lowercase )
|
|
|
{
|
|
|
str_function.prepend(str.at(n));
|
|
|
--n;
|
|
|
}
|
|
|
if (str_function == "tanh" || str_function == "tan" || str_function =="sqrt" || str_function =="sqr" || str_function =="sin" || str_function =="sinh" || str_function =="sign" || str_function =="sech" || str_function =="sec" || str_function =="log" || str_function =="ln" || str_function =="exp" || str_function =="coth" || str_function =="cot" || str_function =="cosh" || str_function =="cosech" || str_function =="cosec" || str_function =="cos" || str_function =="artanh" || str_function =="arsinh" || str_function =="arsech" || str_function =="arctan" || str_function =="arcsin" || str_function =="arcsec" || str_function =="arcoth" || str_function =="arcosh" || str_function =="arcosech" || str_function =="arccot" || str_function =="arccosec" || str_function =="arccos" || str_function =="abs" || str_function=="arctanh" || str_function=="arcsinh" || str_function=="arccosh")
|
|
|
function = true;
|
|
|
else
|
|
|
for( TQValueVector<Ufkt>::iterator it = ufkt.begin(); it != ufkt.end(); ++it)
|
|
|
{
|
|
|
for ( int j=i; j>0 && (str.at(j).isLetter() || str.at(j).isNumber() ) ; --j)
|
|
|
{
|
|
|
if ( it->fname == str.mid(j,i-j+1) )
|
|
|
function = true;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
else if (function)
|
|
|
function = false;
|
|
|
|
|
|
if( (ch.isNumber() || ch.category()==TQChar::Letter_Uppercase )&& ( str.at(i-1).isLetter() || str.at(i-1) == ')' ) || (ch.isLetter() && str.at(i-1)==')') )
|
|
|
str.insert(i,'*');
|
|
|
else if( (ch.isNumber() || ch == ')' || ch.category()==TQChar::Letter_Uppercase) && ( str.at(i+1).isLetter() || str.at(i+1) == '(' ) || (ch.isLetter() && str.at(i+1)=='(' && !function ) )
|
|
|
{
|
|
|
str.insert(i+1,'*');
|
|
|
i++;
|
|
|
}
|
|
|
}
|
|
|
TQString str_end = str.mid(pos);
|
|
|
str_end = str_end.replace(m_decimalsymbol, "."); //replace the locale decimal symbol with a '.'
|
|
|
str.truncate(pos);
|
|
|
str.append(str_end);
|
|
|
//kdDebug() << "str:" << str << endl;
|
|
|
}
|
|
|
|
|
|
bool Parser::delfkt( Ufkt *item)
|
|
|
{
|
|
|
kdDebug() << "Deleting id:" << item->id << endl;
|
|
|
if (!item->dep.isEmpty())
|
|
|
{
|
|
|
KMessageBox::error(0,i18n("This function is depending on an other function"));
|
|
|
return false;
|
|
|
}
|
|
|
for(TQValueVector<Ufkt>::iterator it1=ufkt.begin(); it1!=ufkt.end(); ++it1)
|
|
|
{
|
|
|
if (it1==item)
|
|
|
continue;
|
|
|
for(TQValueList<int>::iterator it2=it1->dep.begin(); it2!=it1->dep.end(); ++it2)
|
|
|
if ( (uint)*it2 == item->id )
|
|
|
it2 = it1->dep.erase(it2);
|
|
|
}
|
|
|
|
|
|
if ( ufkt.count()==1 )
|
|
|
{
|
|
|
//kdDebug() << "first item, don't delete" << endl;
|
|
|
item->fname="";
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
//kdDebug() << "Deleting something" << endl;
|
|
|
TQChar const extstr_c = item->fstr.at(0);
|
|
|
uint const id = item->id;
|
|
|
delete []item->mem;
|
|
|
ufkt.erase(item);
|
|
|
if ( extstr_c == 'x')
|
|
|
{
|
|
|
int const ix = ixValue(id+1);
|
|
|
if (ix!= -1 && ufkt[ix].fstr.at(0) == 'y')
|
|
|
delfkt( &ufkt[ix]);
|
|
|
}
|
|
|
else if ( extstr_c == 'y')
|
|
|
{
|
|
|
int const ix = ixValue(id-1);
|
|
|
if (ix!= -1 && ufkt[ix].fstr.at(0) == 'x')
|
|
|
delfkt( &ufkt[ix]);
|
|
|
}
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
bool Parser::delfkt(uint id)
|
|
|
{
|
|
|
int ix = ixValue(id);
|
|
|
if ( ix!=-1 && delfkt(&ufkt[ix]))
|
|
|
return true;
|
|
|
else
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
uint Parser::countFunctions()
|
|
|
{
|
|
|
uint const count = ufkt.count();
|
|
|
if (count == 1 && ufkt.begin()->fname.isEmpty())
|
|
|
return 0;
|
|
|
else
|
|
|
return count;
|
|
|
}
|
|
|
|
|
|
void Parser::heir1()
|
|
|
{
|
|
|
char c;
|
|
|
heir2();
|
|
|
if(err!=0) return ;
|
|
|
|
|
|
while(1)
|
|
|
{
|
|
|
switch(c=*lptr)
|
|
|
{
|
|
|
default:
|
|
|
return ;
|
|
|
|
|
|
case ' ':
|
|
|
++lptr;
|
|
|
continue;
|
|
|
case '+':
|
|
|
case '-':
|
|
|
++lptr;
|
|
|
addtoken(PUSH);
|
|
|
heir2();
|
|
|
if(err!=0)
|
|
|
return;
|
|
|
}
|
|
|
switch(c)
|
|
|
{
|
|
|
case '+':
|
|
|
addtoken(PLUS);
|
|
|
break;
|
|
|
case '-':
|
|
|
addtoken(MINUS);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
void Parser::heir2()
|
|
|
{
|
|
|
if(match("-"))
|
|
|
{
|
|
|
heir2();
|
|
|
if(err!=0)
|
|
|
return;
|
|
|
addtoken(NEG);
|
|
|
}
|
|
|
else
|
|
|
heir3();
|
|
|
}
|
|
|
|
|
|
|
|
|
void Parser::heir3()
|
|
|
{
|
|
|
char c;
|
|
|
heir4();
|
|
|
if(err!=0)
|
|
|
return;
|
|
|
while(1)
|
|
|
{
|
|
|
switch(c=*lptr)
|
|
|
{
|
|
|
default:
|
|
|
return;
|
|
|
case ' ':
|
|
|
++lptr;
|
|
|
continue;
|
|
|
case '*':
|
|
|
case '/':
|
|
|
++lptr;
|
|
|
addtoken(PUSH);
|
|
|
heir4();
|
|
|
if(err!=0)
|
|
|
return ;
|
|
|
}
|
|
|
switch(c)
|
|
|
{
|
|
|
case '*':
|
|
|
addtoken(MULT);
|
|
|
break;
|
|
|
case '/':
|
|
|
addtoken(DIV);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
void Parser::heir4()
|
|
|
{
|
|
|
primary();
|
|
|
if(err!=0)
|
|
|
return;
|
|
|
while(match("^"))
|
|
|
{
|
|
|
addtoken(PUSH);
|
|
|
primary();
|
|
|
if(err!=0)
|
|
|
return;
|
|
|
addtoken(POW);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
void Parser::primary()
|
|
|
{
|
|
|
if(match("("))
|
|
|
{
|
|
|
heir1();
|
|
|
if(match(")")==0)
|
|
|
err=2; // fehlende Klammer
|
|
|
return;
|
|
|
}
|
|
|
int i;
|
|
|
for(i=0; i<FANZ; ++i)
|
|
|
{
|
|
|
if(match(mfkttab[i].mfstr))
|
|
|
{
|
|
|
primary();
|
|
|
addtoken(FKT);
|
|
|
addfptr(mfkttab[i].mfadr);
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
for( TQValueVector<Ufkt>::iterator it = ufkt.begin(); it != ufkt.end(); ++it)
|
|
|
{
|
|
|
if(TQString(lptr)=="pi" || TQString(lptr)=="e") continue;
|
|
|
|
|
|
if( match(it->fname.latin1()) )
|
|
|
{
|
|
|
if (it == current_item)
|
|
|
{
|
|
|
err=9;
|
|
|
return;
|
|
|
}
|
|
|
primary();
|
|
|
addtoken(UFKT);
|
|
|
addfptr( it->id );
|
|
|
it->dep.append(current_item->id);
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// A constant
|
|
|
if(lptr[0] >='A' && lptr[0]<='Z' )
|
|
|
{
|
|
|
char tmp[2];
|
|
|
tmp[1] = '\0';
|
|
|
for( i = 0; i< (int)constant.size();i++)
|
|
|
{
|
|
|
tmp[0] = constant[i].constant;
|
|
|
if ( match( tmp) )
|
|
|
{
|
|
|
addtoken(KONST);
|
|
|
addwert(constant[i].value);
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
err = 10;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if(match("pi"))
|
|
|
{
|
|
|
addtoken(KONST);
|
|
|
addwert(M_PI);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if(match("e"))
|
|
|
{
|
|
|
addtoken(KONST);
|
|
|
addwert(M_E);
|
|
|
return;
|
|
|
}
|
|
|
//if(match(ufkt[ixa].fvar.latin1()))
|
|
|
if(match(current_item->fvar.latin1()))
|
|
|
{
|
|
|
addtoken(XWERT);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if(match("y"))
|
|
|
{
|
|
|
addtoken(YWERT);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
//if(match(ufkt[ixa].fpar.latin1()))
|
|
|
if(match(current_item->fpar.latin1()))
|
|
|
{
|
|
|
addtoken(KWERT);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
char *p;
|
|
|
double const w=strtod(lptr, &p);
|
|
|
if(lptr!=p)
|
|
|
{
|
|
|
lptr=p;
|
|
|
addtoken(KONST);
|
|
|
addwert(w);
|
|
|
}
|
|
|
else
|
|
|
err=1; // Syntax-Fehler
|
|
|
}
|
|
|
|
|
|
|
|
|
int Parser::match(const char *lit)
|
|
|
{
|
|
|
|
|
|
const char *p;
|
|
|
if(*lit==0)
|
|
|
return 0;
|
|
|
while(*lptr==' ')
|
|
|
++lptr;
|
|
|
p=lptr;
|
|
|
|
|
|
while(*lit)
|
|
|
{
|
|
|
if(*lit++!=*p++)
|
|
|
return 0;
|
|
|
}
|
|
|
lptr=p;
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
|
|
|
void Parser::addtoken(unsigned char token)
|
|
|
{
|
|
|
if(stkptr>=stack+STACKSIZE-1)
|
|
|
{
|
|
|
err=7;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if(evalflg==0)
|
|
|
{
|
|
|
if(mptr>=&mem[MEMSIZE-10])
|
|
|
err=6;
|
|
|
else
|
|
|
*mptr++=token;
|
|
|
|
|
|
switch(token)
|
|
|
{
|
|
|
case PUSH:
|
|
|
++stkptr;
|
|
|
break;
|
|
|
case PLUS:
|
|
|
case MINUS:
|
|
|
case MULT:
|
|
|
case DIV:
|
|
|
case POW:
|
|
|
--stkptr;
|
|
|
}
|
|
|
}
|
|
|
else switch(token)
|
|
|
{
|
|
|
case PUSH:
|
|
|
++stkptr;
|
|
|
break;
|
|
|
case PLUS:
|
|
|
stkptr[-1]+=*stkptr;
|
|
|
--stkptr;
|
|
|
break;
|
|
|
|
|
|
case MINUS:
|
|
|
stkptr[-1]-=*stkptr;
|
|
|
--stkptr;
|
|
|
break;
|
|
|
case MULT:
|
|
|
stkptr[-1]*=*stkptr;
|
|
|
--stkptr;
|
|
|
break;
|
|
|
case DIV:
|
|
|
if(*stkptr==0.)
|
|
|
*(--stkptr)=HUGE_VAL;
|
|
|
else
|
|
|
{
|
|
|
stkptr[-1]/=*stkptr;
|
|
|
--stkptr;
|
|
|
}
|
|
|
break;
|
|
|
|
|
|
case POW:
|
|
|
stkptr[-1]=pow(*(stkptr-1), *stkptr);
|
|
|
--stkptr;
|
|
|
break;
|
|
|
case NEG:
|
|
|
*stkptr=-*stkptr;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
void Parser::addwert(double x)
|
|
|
{
|
|
|
double *pd=(double*)mptr;
|
|
|
|
|
|
if(evalflg==0)
|
|
|
{
|
|
|
if(mptr>=&mem[MEMSIZE-10])
|
|
|
err=6;
|
|
|
else
|
|
|
{
|
|
|
*pd++=x;
|
|
|
mptr=(unsigned char*)pd;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
*stkptr=x;
|
|
|
}
|
|
|
|
|
|
|
|
|
void Parser::addfptr(double(*fadr)(double))
|
|
|
{
|
|
|
double (**pf)(double)=(double(**)(double))mptr;
|
|
|
if( evalflg==0 )
|
|
|
{
|
|
|
if( mptr>=&mem[MEMSIZE-10] )
|
|
|
err=6;
|
|
|
else
|
|
|
{
|
|
|
*pf++=fadr;
|
|
|
mptr=(unsigned char*)pf;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
*stkptr=(*fadr)(*stkptr);
|
|
|
}
|
|
|
|
|
|
|
|
|
void Parser::addfptr(uint id)
|
|
|
{
|
|
|
uint *p=(uint*)mptr;
|
|
|
if(evalflg==0)
|
|
|
{
|
|
|
if(mptr>=&mem[MEMSIZE-10]) err=6;
|
|
|
else
|
|
|
{
|
|
|
*p++=id;
|
|
|
mptr=(unsigned char*)p;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
for( TQValueVector<Ufkt>::iterator it = ufkt.begin(); it != ufkt.end(); ++it)
|
|
|
if ( it->id == id)
|
|
|
{
|
|
|
*stkptr=fkt(it, *stkptr);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
int Parser::fnameToId(const TQString &name)
|
|
|
{
|
|
|
for( TQValueVector<Ufkt>::iterator it = ufkt.begin(); it != ufkt.end(); ++it)
|
|
|
{
|
|
|
if(name==it->fname)
|
|
|
return it->id;
|
|
|
}
|
|
|
return -1; // Name nicht bekannt
|
|
|
}
|
|
|
|
|
|
|
|
|
int Parser::parserError(bool showMessageBox)
|
|
|
{
|
|
|
if (!showMessageBox)
|
|
|
return err;
|
|
|
switch(err)
|
|
|
{
|
|
|
case 1: KMessageBox::error(0, i18n("Parser error at position %1:\n"
|
|
|
"Syntax error").arg(TQString::number(errpos)), "KmPlot");
|
|
|
break;
|
|
|
case 2: KMessageBox::error(0, i18n("Parser error at position %1:\n"
|
|
|
"Missing parenthesis").arg(TQString::number(errpos)), "KmPlot");
|
|
|
break;
|
|
|
case 3: KMessageBox::error(0, i18n("Parser error at position %1:\n"
|
|
|
"Function name unknown").arg(TQString::number(errpos)), "KmPlot");
|
|
|
break;
|
|
|
case 4: KMessageBox::error(0, i18n("Parser error at position %1:\n"
|
|
|
"Void function variable").arg(TQString::number(errpos)), "KmPlot");
|
|
|
break;
|
|
|
case 5: KMessageBox::error(0, i18n("Parser error at position %1:\n"
|
|
|
"Too many functions").arg(TQString::number(errpos)), "KmPlot");
|
|
|
break;
|
|
|
case 6: KMessageBox::error(0, i18n("Parser error at position %1:\n"
|
|
|
"Token-memory overflow").arg(TQString::number(errpos)), "KmPlot");
|
|
|
break;
|
|
|
case 7: KMessageBox::error(0, i18n("Parser error at position %1:\n"
|
|
|
"Stack overflow").arg(TQString::number(errpos)), "KmPlot");
|
|
|
break;
|
|
|
case 8: KMessageBox::error(0, i18n("Parser error at position %1:\n"
|
|
|
"Name of function not free.").arg(TQString::number(errpos)), "KmPlot");
|
|
|
break;
|
|
|
case 9: KMessageBox::error(0, i18n("Parser error at position %1:\n"
|
|
|
"recursive function not allowed.").arg(TQString::number(errpos)), "KmPlot");
|
|
|
break;
|
|
|
case 10: KMessageBox::error(0, i18n("Could not find a defined constant at position %1." ).arg(TQString::number(errpos)),
|
|
|
"KmPlot");
|
|
|
break;
|
|
|
case 11: KMessageBox::error(0, i18n("Empty function"), "KmPlot");
|
|
|
break;
|
|
|
case 12: KMessageBox::error(0, i18n("The function name is not allowed to contain capital letters."), "KmPlot");
|
|
|
break;
|
|
|
case 13: KMessageBox::error(0, i18n("Function could not be found."), "KmPlot");
|
|
|
break;
|
|
|
case 14: KMessageBox::error(0, i18n("The expression must not contain user-defined constants."), "KmPlot");
|
|
|
break;
|
|
|
}
|
|
|
return err;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// static
|
|
|
TQString Parser::number( double value )
|
|
|
{
|
|
|
TQString str = TQString::number( value, 'g', 6 );
|
|
|
str.replace( 'e', "*10^" );
|
|
|
// kDebug() << "returning str="<<str<<endl;
|
|
|
return str;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
double ln(double x)
|
|
|
{
|
|
|
return log(x);
|
|
|
}
|
|
|
|
|
|
double llog(double x)
|
|
|
{
|
|
|
return log10(x);
|
|
|
}
|
|
|
|
|
|
double sign(double x)
|
|
|
{
|
|
|
if(x<0.)
|
|
|
return -1.;
|
|
|
else
|
|
|
if(x>0.)
|
|
|
return 1.;
|
|
|
return 0.;
|
|
|
}
|
|
|
|
|
|
double sqr(double x)
|
|
|
{
|
|
|
return x*x;
|
|
|
}
|
|
|
|
|
|
double arsinh(double x)
|
|
|
{
|
|
|
return log(x+sqrt(x*x+1));
|
|
|
}
|
|
|
|
|
|
|
|
|
double arcosh(double x)
|
|
|
{
|
|
|
return log(x+sqrt(x*x-1));
|
|
|
}
|
|
|
|
|
|
|
|
|
double artanh(double x)
|
|
|
{
|
|
|
return log((1+x)/(1-x))/2;
|
|
|
}
|
|
|
|
|
|
// sec, cosec, cot and their inverses
|
|
|
|
|
|
double sec(double x)
|
|
|
{
|
|
|
return (1 / cos(x*Parser::anglemode()));
|
|
|
}
|
|
|
|
|
|
double cosec(double x)
|
|
|
{
|
|
|
return (1 / sin(x*Parser::anglemode()));
|
|
|
}
|
|
|
|
|
|
double cot(double x)
|
|
|
{
|
|
|
return (1 / tan(x*Parser::anglemode()));
|
|
|
}
|
|
|
|
|
|
double arcsec(double x)
|
|
|
{
|
|
|
if ( !Parser::anglemode() )
|
|
|
return ( 1/acos(x)* 180/M_PI );
|
|
|
else
|
|
|
return acos(1/x);
|
|
|
}
|
|
|
|
|
|
double arccosec(double x)
|
|
|
{
|
|
|
return asin(1/x)* 1/Parser::anglemode();
|
|
|
}
|
|
|
|
|
|
double arccot(double x)
|
|
|
{
|
|
|
return atan(1/x)* 1/Parser::anglemode();
|
|
|
}
|
|
|
|
|
|
// sech, cosech, coth and their inverses
|
|
|
|
|
|
|
|
|
double sech(double x)
|
|
|
{
|
|
|
return (1 / cosh(x*Parser::anglemode()));
|
|
|
}
|
|
|
|
|
|
double cosech(double x)
|
|
|
{
|
|
|
return (1 / sinh(x*Parser::anglemode()));
|
|
|
}
|
|
|
|
|
|
double coth(double x)
|
|
|
{
|
|
|
return (1 / tanh(x*Parser::anglemode()));
|
|
|
}
|
|
|
|
|
|
double arsech(double x)
|
|
|
{
|
|
|
return arcosh(1/x)* 1/Parser::anglemode();
|
|
|
}
|
|
|
|
|
|
double arcosech(double x)
|
|
|
{
|
|
|
return arsinh(1/x)* 1/Parser::anglemode();
|
|
|
}
|
|
|
|
|
|
double arcoth(double x)
|
|
|
{ return artanh(1/x)* 1/Parser::anglemode();
|
|
|
}
|
|
|
|
|
|
//basic trigonometry functions
|
|
|
|
|
|
double lcos(double x)
|
|
|
{
|
|
|
return cos(x*Parser::anglemode());
|
|
|
}
|
|
|
double lsin(double x)
|
|
|
{
|
|
|
return sin(x*Parser::anglemode());
|
|
|
}
|
|
|
double ltan(double x)
|
|
|
{
|
|
|
return tan(x*Parser::anglemode());
|
|
|
}
|
|
|
|
|
|
double lcosh(double x)
|
|
|
{
|
|
|
return cosh(x*Parser::anglemode());
|
|
|
}
|
|
|
double lsinh(double x)
|
|
|
{
|
|
|
return sinh(x*Parser::anglemode());
|
|
|
}
|
|
|
double ltanh(double x)
|
|
|
{
|
|
|
return tanh(x*Parser::anglemode());
|
|
|
}
|
|
|
|
|
|
double arccos(double x)
|
|
|
{
|
|
|
return acos(x) * 1/Parser::anglemode();
|
|
|
}
|
|
|
double arcsin(double x)
|
|
|
{
|
|
|
return asin(x)* 1/Parser::anglemode();
|
|
|
}
|
|
|
|
|
|
double arctan(double x)
|
|
|
{
|
|
|
return atan(x)* 1/Parser::anglemode();
|
|
|
}
|