/* * Code based on parser from KmPlot - a math. function plotter for the KDE-Desktop * * Original code * Copyright (C) 1998, 1999 Klaus-Dieter Möller * 2000, 2002 kd.moeller@t-online.de * * Modifications: 2004 Andrew Coles (andrew_coles@yahoo.co.uk) * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * */ // standard c(++) includes #include #include #include //KDE includes #include #include #include // 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", log10}, // Logarithm base 10 {"ln", log}, // 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 {"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 }; Parser::Parser() { ps_init( UFANZ, MEMSIZE, STACKSIZE ); } Parser::Parser( int anz, int m_size, int s_size ) { ps_init( anz, m_size, s_size ); } void Parser::ps_init(int anz, int m_size, int s_size) { int ix; ufanz=anz; memsize=m_size; stacksize=s_size; ufkt=new Ufkt[ufanz]; evalflg=ixa=0; for(ix=0; ixfkt(*stkptr); mptr=(unsigned char*)puf; break; case ENDE: erg=*stkptr; delete [] stack; return erg; } } } int Parser::getNextIndex() { int ix = 0; while( ( ix < ufanz ) && !ufkt[ ix ].fname.isEmpty() ) ix++; if( ix == ufanz ) ix = -1; return ix; } int Parser::addfkt(TQString str) { int ix; stkptr=stack=0; err=0; errpos=1; str.remove(" " ); const int p1=str.find('('); int p2=str.find(','); const int p3=str.find(")="); //insert '*' when it is needed for(int i=p1+3; i < (int) str.length();i++) { if( (str.at(i).isNumber() || str.at(i).category()==TQChar::Letter_Uppercase )&& ( str.at(i-1).isLetter() || str.at(i-1) == ')' ) ) { str.insert(i,'*'); } else if( (str.at(i).isNumber() || str.at(i) == ')' || str.at(i).category()==TQChar::Letter_Uppercase) && ( str.at(i+1).isLetter() || str.at(i+1) == '(' ) ) { str.insert(i+1,'*'); i++; } } 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(getfix(str.left(p1))!=-1) { err=8; return -1; } else err=0; if (str.mid(p1+1, p2-p1-1) == "e") { err=4; return -1; } for(ix=0; ix=ufanz) return -1; // ungltiger Index ufkt[ix].fname=""; //.resize(1); // Name l�chen return ix; } double Parser::fkt(TQString name, double x) { int ix; ix=getfix(name); if(ix==-1) return 0.; return ufkt[ix].fkt(x); } 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() { char *p; int i; double w; if(match("(")) { heir1(); if(match(")")==0) err=2; // fehlende Klammer return; } for(i=0; i='A' && lptr[0]<='Z' ) { char tmp[2]; tmp[1] = '\0'; for( int 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())) { addtoken(XWERT); return; } if(match("y")) { addtoken(YWERT); return; } if(match(ufkt[ixa].fpar.latin1())) { addtoken(KWERT); return; } 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(Ufkt *adr) { Ufkt **p=(Ufkt**)mptr; if(evalflg==0) { if(mptr>=&mem[memsize-10]) err=6; else { *p++=adr; mptr=(unsigned char*)p; } } else *stkptr=adr->fkt(*stkptr); } int Parser::chkfix(int ix) { if(ix<0 || ix>=ufanz) return -1; // ungltiger Index if(ufkt[ix].fname.isEmpty()) return -1; // keine Funktion return ix; } int Parser::getfkt(int ix, TQString& name, TQString& str) { if(ix<0 || ix>=ufanz) return -1; // ungltiger Index if(ufkt[ix].fname.isEmpty()) return -1; // keine Funktion name=ufkt[ix].fname.copy(); str=ufkt[ix].fstr.copy(); return ix; } int Parser::getfix(TQString name) { int ix; err=0; for(ix=0; ix0.) 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(); }