diff options
Diffstat (limited to 'kicker-applets/math')
-rw-r--r-- | kicker-applets/math/Makefile.am | 19 | ||||
-rw-r--r-- | kicker-applets/math/mathapplet.cpp | 285 | ||||
-rw-r--r-- | kicker-applets/math/mathapplet.desktop | 114 | ||||
-rw-r--r-- | kicker-applets/math/mathapplet.h | 74 | ||||
-rw-r--r-- | kicker-applets/math/parser.cpp | 813 | ||||
-rw-r--r-- | kicker-applets/math/parser.h | 241 |
6 files changed, 1546 insertions, 0 deletions
diff --git a/kicker-applets/math/Makefile.am b/kicker-applets/math/Makefile.am new file mode 100644 index 0000000..da94ffb --- /dev/null +++ b/kicker-applets/math/Makefile.am @@ -0,0 +1,19 @@ +INCLUDES = $(all_includes) + +kde_module_LTLIBRARIES = math_panelapplet.la + +math_panelapplet_la_SOURCES = mathapplet.cpp parser.cpp + +METASOURCES = mathapplet.moc +noinst_HEADERS = mathapplet.h parser.h + +lnkdir = $(kde_datadir)/kicker/applets +lnk_DATA = mathapplet.desktop + +EXTRA_DIST = $(lnk_DATA) + +math_panelapplet_la_LDFLAGS = -module $(KDE_PLUGIN) $(all_libraries) +math_panelapplet_la_LIBADD = $(LIB_KSYCOCA) $(LIB_KDEUI) + +messages: + $(XGETTEXT) *.cpp *.h -o $(podir)/kmathapplet.pot diff --git a/kicker-applets/math/mathapplet.cpp b/kicker-applets/math/mathapplet.cpp new file mode 100644 index 0000000..b4966b2 --- /dev/null +++ b/kicker-applets/math/mathapplet.cpp @@ -0,0 +1,285 @@ +/***************************************************************** + +Based on code 'Run' applet code, copyright (c) 2000 Matthias Elter <elter@kde.org> + +Modifications made by Andrew Coles, 2004 <andrew_coles@yahoo.co.uk> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#include <qlabel.h> +#include <qfont.h> +#include <qstringlist.h> +#include <qpushbutton.h> +#include <qhbox.h> + +#include <kapplication.h> +#include <kglobal.h> +#include <klocale.h> +#include <kconfig.h> +#include <kcombobox.h> +#include <kurifilter.h> +#include <kdialog.h> +#include <krun.h> +#include <kmessagebox.h> +#include <kpopupmenu.h> + +#include "parser.h" + + + +#include "mathapplet.h" +#include "mathapplet.moc" + +extern "C" +{ + KDE_EXPORT KPanelApplet* init(QWidget *parent, const QString& configFile) + { + KGlobal::locale()->insertCatalogue("kmathapplet"); + return new MathApplet(configFile, KPanelApplet::Stretch, 0, parent, "kmathapplet"); + } +} + +MathApplet::MathApplet(const QString& configFile, Type type, int actions, + QWidget *parent, const char *name) + : KPanelApplet(configFile, type, actions, parent, name), + m_hasFocus(false) +{ + // setBackgroundMode(X11ParentRelative); + setBackgroundOrigin( AncestorOrigin ); + // setup label + _label = new QLabel(i18n("Evaluate:"), this); + QFont f(_label->font()); + f.setPixelSize(12); +// _label->setBackgroundMode(X11ParentRelative); + _label->setBackgroundOrigin( AncestorOrigin ); + _label->setFixedHeight(14); + _label->setFont(f); + + // setup popup button + _btn = new QPushButton(this); + f = _btn->font(); + f.setPixelSize(12); + _btn->setFont(f); + connect(_btn, SIGNAL(clicked()), SLOT(popup_combo())); + + // setup history combo + _input = new KHistoryCombo(this); + _input->setFocus(); + _input->clearEdit(); + watchForFocus(_input->lineEdit()); + connect(_input, SIGNAL(activated(const QString&)), + SLOT(evaluate(const QString&))); + + initContextMenu(); + useDegrees(); + + KConfig *c = config(); + c->setGroup("General"); + + + // restore history and completion list + QStringList list = c->readListEntry("Completion list"); + _input->completionObject()->setItems(list); + list = c->readListEntry("History list"); + _input->setHistoryItems(list); + int mode = c->readNumEntry( "CompletionMode", KGlobalSettings::completionMode() ); + _input->setCompletionMode( (KGlobalSettings::Completion) mode ); + + _hbox = new QHBox( 0, 0, WStyle_Customize | WType_Popup ); + _hbox->setFixedSize(120, 22); + + +} + +void MathApplet::initContextMenu() +{ + mContextMenu = new KPopupMenu(this); + mContextMenu->setCheckable(true); + mContextMenu->insertItem(i18n("Use &Degrees"), this, SLOT(useDegrees()), 0, 0, 0); + mContextMenu->insertItem(i18n("Use &Radians"), this, SLOT(useRadians()), 0, 1, 1); + setCustomMenu(mContextMenu); +} + + +MathApplet::~MathApplet() +{ + KConfig *c = config(); + c->setGroup("General"); + + // save history and completion list + QStringList list = _input->completionObject()->items(); + c->writeEntry("Completion list", list); + list = _input->historyItems(); + c->writeEntry("History list", list); + c->writeEntry( "CompletionMode", (int) _input->completionMode() ); + c->sync(); + + KGlobal::locale()->removeCatalogue("kmathapplet"); +} + +void MathApplet::useDegrees() { + + mContextMenu->setItemChecked(0, true); + mContextMenu->setItemChecked(1, false); + Parser dummy; + dummy.setAngleMode(1); +} + +void MathApplet::useRadians() { + mContextMenu->setItemChecked(0, false); + mContextMenu->setItemChecked(1, true); + Parser dummy; + dummy.setAngleMode(0); +} + +void MathApplet::resizeEvent(QResizeEvent*) +{ + if(orientation() == Horizontal) + { + _btn->hide(); + _input->reparent(this, QPoint(0,0), true); + _label->setGeometry(0,0, width(), _label->height()); + + if(height() >= _input->sizeHint().height() + _label->height()) + { + int inputVOffset = height() - _input->sizeHint().height() - 2; + int labelHeight = _label->sizeHint().height(); + _label->setGeometry(0, inputVOffset - labelHeight, + width(), labelHeight); + _input->setGeometry(0, inputVOffset, + width(), _input->sizeHint().height()); + _label->show(); + } + else + { + _label->hide(); + + // make it as high as the combobox naturally wants to be + // but no taller than the panel is! + // don't forget to center it vertically either. + int newHeight = _input->sizeHint().height(); + if (newHeight > height()) + newHeight = height(); + _input->setGeometry(0, (height() - newHeight) / 2, + width(), newHeight); + } + } + else + { + _btn->show(); + _btn->setFixedSize(width(), 22); + _input->reparent( _hbox, QPoint(0, 0), false); + _label->hide(); + } + setButtonText(); +} + +void MathApplet::positionChange(KPanelApplet::Position) +{ + setButtonText(); +} + +void MathApplet::setButtonText() +{ + QString t; + + if (position() == pLeft) + { + if (width() >= 42) + t = i18n("< Eval"); + else + t = "<"; + } + else + { + if(width() >= 42) + t = i18n("Eval >"); + else + t = ">"; + } + + _btn->setText(t); +} + +int MathApplet::widthForHeight(int ) const +{ + return 110; +} + +int MathApplet::heightForWidth(int ) const +{ + return 22; +} + +void MathApplet::popup_combo() +{ + QPoint p; + if (position() == pLeft) + p = mapToGlobal(QPoint(-_input->width()-1, 0)); + else + p = mapToGlobal(QPoint(width()+1, 0)); + _hbox->move(p); + _hbox->show(); + _input->setFocus(); +} + +void MathApplet::evaluate(const QString& command) +{ + QString exec; + + Parser evaluator; + + kapp->propagateSessionManager(); + + _input->addToHistory(command); + + + QString cmd = command; + + // Nothing interesting. Quit! + if ( cmd.isEmpty() ){ + KMessageBox::sorry(0L, i18n("You have to enter an expression to be evaluated first.")); + needsFocus(true); + } else { + double answer = evaluator.eval(command); + if (evaluator.errmsg() == 0) { + QString ansAsString = QString::number(answer); + _input->clearEdit(); + _input->setEditText(ansAsString); + } else { + _input->removeFromHistory(_input->currentText()); + needsFocus(true); + } + } + + if (orientation() == Vertical) + _hbox->hide(); +} + +void MathApplet::mousePressEvent(QMouseEvent *e) +{ + if ( e->button() != RightButton ) + { + KPanelApplet::mousePressEvent( e ); + return; + } + + mContextMenu->exec(e->globalPos()); +} diff --git a/kicker-applets/math/mathapplet.desktop b/kicker-applets/math/mathapplet.desktop new file mode 100644 index 0000000..9aba622 --- /dev/null +++ b/kicker-applets/math/mathapplet.desktop @@ -0,0 +1,114 @@ +[Desktop Entry] +Type=Plugin +Name=Math Expression Evaluator +Name[bg]=Математически изрази +Name[bs]=Procjena matematičkih izraza +Name[ca]=Avaluador d'expressions matemàtiques +Name[cs]=Vyhodnocení matematického výrazu +Name[da]=Evaluering af matematiske udtryk +Name[de]=Auswertung mathematischer Ausdrücke +Name[el]=Ελεγκτής εγκυρότητας μαθηματικής έκφρασης +Name[en_GB]=Maths Expression Evaluator +Name[eo]=Matematikesprima interpretilo +Name[es]=Evaluador de expresiones matemáticas +Name[et]=Matemaatikaavaldiste kontrollija +Name[eu]=Espresio matematikoen balidatzailea +Name[fa]=ارزیاب عبارت ریاضی +Name[fi]=Matemaattisen lausekkeen laskija +Name[fr]=Interpréteur d'expressions mathématique +Name[fy]=Lytse rekkenmachine +Name[ga]=Luachálaí Slonn Matamaiticiúil +Name[gl]=Avaliación de Expresións Matemáticas +Name[he]=מפענח נוסחאות מתמטיות +Name[hi]=मैथ एक्सप्रेशन इवेल्यूएटर्स +Name[hr]=Ocjena matematičkih izraza +Name[hu]=Kifejezéskiértékelő +Name[is]=Algebrureiknivél +Name[it]=Disegnatore di funzioni matematiche +Name[ja]=数学的表現の評価者 +Name[ka]=მათემატიკური გამოსახულებების გამომთვლელი +Name[kk]=Математикалық өрнегін есептеу +Name[km]=កម្មវិធីវាយតម្លៃកន្សោមពិជគណិត +Name[lt]=Matematinių išraiškų vertinimo priemonė +Name[mk]=Пресметувач на математички изрази +Name[ms]=Penilaian Ungkapan Matematik +Name[nb]=Matematikkberegner +Name[nds]=Mathemaatsche Utdrück utreken +Name[ne]=गणित अभिव्यक्ति मुल्याङ्कनकर्ता +Name[nl]=Kleine rekenmachine +Name[nn]=Matteuttrykkevaluerar +Name[pl]=Program wyliczający wyrażenia matematyczne +Name[pt]=Avaliação de Expressões Matemáticas +Name[pt_BR]=Validador de Expressões Matemáticas +Name[ru]=Вычисление математических выражений +Name[sk]=Vyhodnotenie matematického výrazu +Name[sl]=Vrednotenje matematičnih izrazov +Name[sr]=Рачунар математичких израза +Name[sr@Latn]=Računar matematičkih izraza +Name[sv]=Utvärdering av matematiska uttryck +Name[ta]=கணிதத் தொடர் மதிப்பிடு +Name[tg]=Тафтиши ифодаҳои математикӣ +Name[tr]=Matematiksel İşlem Değerlendiricisi +Name[uk]=Перевірка математичних виразів +Name[uz]=Matematik ifodalarni hisoblagich +Name[uz@cyrillic]=Математик ифодаларни ҳисоблагич +Name[vi]=Bộ định giá biểu thức toán học +Name[zh_CN]=数学表达式计算器 +Name[zh_TW]=數學運算模擬器 +Comment=A mathematical expression evaluator +Comment[bg]=Изчисление на математически изрази +Comment[bs]=Procjena matematičkih izraza +Comment[ca]=Un avaluador d'expressions matemàtiques +Comment[cs]=Program pro vyhodnocování matematických výrazů +Comment[da]=Til evaluering af matematiske udtryk +Comment[de]=Auswerten von mathematischen Ausdrücken +Comment[el]=Ένας ελεγκτής εγκυρότητας μαθηματικών εκφράσεων +Comment[eo]=Matematikesprima interpretilo +Comment[es]=Un evaluador de expresiones matemáticas +Comment[et]=Matemaatikaavaldiste kontrollija +Comment[eu]=Espresio matematikoen ebaluatzailea +Comment[fa]=ارزیاب عبارتهای ریاضی +Comment[fi]=Matemaattisen lausekkeen laskija +Comment[fr]=Un interpréteur d'expressions mathématiques +Comment[fy]=In applet om wiskundige útdrukkingen te evaluearjen +Comment[ga]=Luachálaí slonn matamaiticiúil +Comment[gl]=Un avaliador de expresións matemáticas +Comment[he]=מפענח נוסחאות מתמטיות +Comment[hi]=एक मैथमेटिकल एक्सप्रेशन इवेल्यूएटर +Comment[hr]=Ocjenjivanje matematičkih izraza +Comment[hu]=Matematikai kifejezések kiszámítására alkalmas program +Comment[is]=Algebrureiknivél +Comment[it]=Uno strumento per disegnare funzioni matematiche +Comment[ja]=数学的表現の評価者 +Comment[ka]=მათემატიკური გამოსახულებების გამომთვლელი +Comment[kk]=Математикалық өрнекті есептеп шығару +Comment[km]=កម្មវិធីវាយតម្លៃកន្សោមពិជគណិត +Comment[lt]=Matematinių išraiškų vertinimo priemonė +Comment[mk]=Пресметување математички изрази +Comment[ms]=Penilai ungkapan matematik +Comment[nb]=En beregner for matematiske uttrykk +Comment[nds]=Utreken vun mathemaatsche Utdrück +Comment[ne]=एउटा गणितिय अभिव्यक्ति मुल्याङ्कनकर्ता +Comment[nl]=Een applet waarmee u wiskundige uitdrukkingen kunt evalueren +Comment[nn]=Ein utreknar for matematiske uttrykk +Comment[pl]=Program wyliczający wyrażenia matematyczne +Comment[pt]=Um avaliador de expressões matemáticas +Comment[pt_BR]=Um validador de expressões +Comment[ru]=Вычисление математических выражений +Comment[sk]=Program pre vyhodnotenie matematických výrazov +Comment[sl]=Vrednotenje matematičnih izrazov +Comment[sr]=Израчунава задате математичке изразе +Comment[sr@Latn]=Izračunava zadate matematičke izraze +Comment[sv]=Ett verktyg för utvärdering av matematiska uttryck +Comment[ta]=கணிதத் தொடர் மதிப்பிடு +Comment[tg]=Тафтиши ифодаҳои математикӣ +Comment[tr]=Matematiksel işlem değerlendirici +Comment[uk]=Перевірка математичних виразів +Comment[uz]=Matematik ifodalarni hisoblagich +Comment[uz@cyrillic]=Математик ифодаларни ҳисоблагич +Comment[vi]=Bộ định giá biểu thức toán học +Comment[zh_CN]=数学表达式计算器 +Comment[zh_TW]=數學運算模擬器 +Icon=math_int +X-KDE-Library=math_panelapplet +X-KDE-UniqueApplet=true diff --git a/kicker-applets/math/mathapplet.h b/kicker-applets/math/mathapplet.h new file mode 100644 index 0000000..1a918c3 --- /dev/null +++ b/kicker-applets/math/mathapplet.h @@ -0,0 +1,74 @@ +/***************************************************************** + +Based on code 'Run' applet code, copyright (c) 2000 Matthias Elter <elter@kde.org> + +Modifications made by Andrew Coles, 2004 <andrew_coles@yahoo.co.uk> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************/ + +#ifndef __mathapplet_h__ +#define __mathapplet_h__ + +#include <qstring.h> +#include <kpanelapplet.h> + +class QLabel; +class QHBox; +class QPushButton; +class KHistoryCombo; +class KPopupMenu; + +class MathApplet : public KPanelApplet +{ + Q_OBJECT + +public: + MathApplet(const QString& configFile, Type t = Stretch, int actions = 0, + QWidget *parent = 0, const char *name = 0); + virtual ~MathApplet(); + + int widthForHeight(int height) const; + int heightForWidth(int width) const; + +protected: + void resizeEvent(QResizeEvent*); + void positionChange(KPanelApplet::Position); + +protected slots: + void evaluate(const QString&); + void popup_combo(); + void setButtonText(); + void useDegrees(); + void useRadians(); + +private: + + void initContextMenu(); + void mousePressEvent(QMouseEvent *e); + + KHistoryCombo *_input; + QLabel *_label; + QPushButton *_btn; + QHBox *_hbox; + KPopupMenu *mContextMenu; + bool m_hasFocus; +}; + +#endif diff --git a/kicker-applets/math/parser.cpp b/kicker-applets/math/parser.cpp new file mode 100644 index 0000000..7d99c87 --- /dev/null +++ b/kicker-applets/math/parser.cpp @@ -0,0 +1,813 @@ +/* +* Code based on parser from KmPlot - a math. function plotter for the KDE-Desktop +* +* Original code +* Copyright (C) 1998, 1999 Klaus-Dieter Mller +* 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 <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", 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; ix<ufanz; ++ix) + { ufkt[ix].memsize=memsize; + ufkt[ix].stacksize=stacksize; + ufkt[ix].fname=""; //.resize(1); + ufkt[ix].fvar=""; //.resize(1); + ufkt[ix].fpar=""; //.resize(1); + ufkt[ix].fstr=""; //.resize(1); + ufkt[ix].mem=new unsigned char [memsize]; + } +} + + +Parser::~Parser() +{ delete [] ufkt; +} + + +Parser::Ufkt::Ufkt() +{ +} + + +Parser::Ufkt::~Ufkt() +{ delete [] mem; +} + + +void Parser::setAngleMode(int angle) +{ if(angle==0) + m_anglemode = 1; + else + m_anglemode = M_PI/180; +} + +double Parser::anglemode() +{ return m_anglemode; +} + +double Parser::eval(QString str) +{ double erg; + + stack=new double [stacksize]; + stkptr=stack; + evalflg=1; + lptr=str.latin1(); + err=0; + heir1(); + if(*lptr!=0 && err==0) err=1; + evalflg=0; + erg=*stkptr; + delete [] stack; + if(err==0) + { errpos=0; + return erg; + } + else + { errpos=lptr-(str.latin1())+1; + return 0.; + } +} + + +double Parser::Ufkt::fkt(double x) +{ unsigned char token; + double *pd, (**pf)(double); + double erg, *stack, *stkptr; + Ufkt **puf; + + mptr=mem; + stack=stkptr= new double [stacksize]; + while(1) + { switch(token=*mptr++) + { case KONST: pd=(double*)mptr; + *stkptr=*pd++; + mptr=(unsigned char*)pd; + break; + case XWERT: *stkptr=x; + break; + case YWERT: *stkptr=oldy; + break; + case KWERT: *stkptr=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))mptr; + *stkptr=(*pf++)(*stkptr); + mptr=(unsigned char*)pf; + break; + + case UFKT: puf=(Ufkt**)mptr; + *stkptr=(*puf++)->fkt(*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(QString 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()==QChar::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()==QChar::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; ++ix) + { if(ufkt[ix].fname.isEmpty()) + { ufkt[ix].fname=str.left(p1); + ufkt[ix].fvar=str.mid(p1+1, p2-p1-1); + ufkt[ix].fstr=str; + if(p2<p3) ufkt[ix].fpar=str.mid(p2+1, p3-p2-1); + else ufkt[ix].fpar=""; //.resize(1); + break; + } + } + + if(ix==ufanz) + { err=5; + return -1; + } // zu viele Funktionen + + ixa=ix; + mem=mptr=ufkt[ix].mem; + lptr=(str.latin1())+p3+2; + heir1(); + if(*lptr!=0 && err==0) err=1; // Syntaxfehler + addtoken(ENDE); + + if(err!=0) + { ufkt[ix].fname=""; //.resize(1); + errpos=lptr-(str.latin1())+1; + return -1; + } + + + errpos=0; + return ix; +} + + +int Parser::delfkt(QString name) +{ int ix; + + ix=getfix(name); + if(ix!=-1) ufkt[ix].fname=""; //.resize(1); // Name l�chen + return ix; +} + + +int Parser::delfkt(int ix) +{ if(ix<0 || ix>=ufanz) return -1; // ungltiger Index + + ufkt[ix].fname=""; //.resize(1); // Name l�chen + return ix; +} + + +double Parser::fkt(QString 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<FANZ; ++i) + { if(match(mfkttab[i].mfstr)) + { primary(); + addtoken(FKT); + addfptr(mfkttab[i].mfadr); + return; + } + } + + for(i=0; i<ufanz; ++i) + { if(ufkt[i].fname[0]==0) continue; + if(match(ufkt[i].fname.latin1())) + { if(i==ixa) {err=9; return;} + + primary(); + addtoken(UFKT); + addfptr(&ufkt[i]); + return; + } + } + // A constant + if(lptr[0] >='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, QString& name, QString& 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(QString name) +{ int ix; + + err=0; + for(ix=0; ix<ufanz; ++ix) + { if(name==ufkt[ix].fname) return ix; + } + err=3; // Name nicht bekannt + return -1; +} + + +int Parser::errmsg() +{ switch(err) + { case 1: KMessageBox::error(0, i18n("Parser error at position %1:\n" + "Syntax error").arg(QString::number(errpos)), i18n("Math Expression Evaluator")); + break; + + case 2: KMessageBox::error(0, i18n("Parser error at position %1:\n" + "Missing parenthesis").arg(QString::number(errpos)), i18n("Math Expression Evaluator")); + break; + + case 3: KMessageBox::error(0, i18n("Parser error at position %1:\n" + "Function name unknown").arg(QString::number(errpos)), i18n("Math Expression Evaluator")); + break; + + case 4: KMessageBox::error(0, i18n("Parser error at position %1:\n" + "Void function variable").arg(QString::number(errpos)), i18n("Math Expression Evaluator")); + break; + + case 5: KMessageBox::error(0, i18n("Parser error at position %1:\n" + "Too many functions").arg(QString::number(errpos)), i18n("Math Expression Evaluator")); + break; + + case 6: KMessageBox::error(0, i18n("Parser error at position %1:\n" + "Token-memory overflow").arg(QString::number(errpos)), i18n("Math Expression Evaluator")); + break; + + case 7: KMessageBox::error(0, i18n("Parser error at position %1:\n" + "Stack overflow").arg(QString::number(errpos)), i18n("Math Expression Evaluator")); + break; + + case 8: KMessageBox::error(0, i18n("Parser error at position %1:\n" + "Name of function not free").arg(QString::number(errpos)), i18n("Math Expression Evaluator")); + break; + + case 9: KMessageBox::error(0, i18n("Parser error at position %1:\n" + "recursive function not allowed").arg(QString::number(errpos)), i18n("Math Expression Evaluator")); + break; + case 10: KMessageBox::error(0, i18n("Could not find a defined constant at position %1" ).arg(QString::number(errpos)), + i18n("Math Expression Evaluator")); + break; + case 11: KMessageBox::error(0, i18n("Empty function"), i18n("Math Expression Evaluator")); + break; + } + + return err; +} + + +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(); +} diff --git a/kicker-applets/math/parser.h b/kicker-applets/math/parser.h new file mode 100644 index 0000000..44e82ba --- /dev/null +++ b/kicker-applets/math/parser.h @@ -0,0 +1,241 @@ +/* +* Code based on parser from KmPlot - a math. function plotter for the KDE-Desktop +* +* Original code +* Copyright (C) 1998, 1999 Klaus-Dieter Mller +* 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. +* +*/ + +/** @file parser.h + * \brief Contains the parser core class Parser. */ + +// Qt includes +#include <qstring.h> +#include <qvaluevector.h> + +#ifndef parser_included +#define parser_included + +// Voreinstellungen bei Verwendung des Standardkonstruktors : + + +#define UFANZ 10 ///< max. count of user defined functions +#define MEMSIZE 200 ///< memory size for tokens +#define STACKSIZE 50 ///< stack depth + +//@{ +/** Token type. */ +#define KONST 0 // double value follows +#define XWERT 1 // get x value +#define KWERT 2 // get function parameter +#define PUSH 3 // push value to stack +#define PLUS 4 // add +#define MINUS 5 // subtract +#define MULT 6 // multiply +#define DIV 7 // divide +#define POW 8 // exponentiate +#define NEG 9 // negate +#define FKT 10 // address to function followes +#define UFKT 11 // address to user defined function follows +#define ENDE 12 // end of function +#define YWERT 13 // get y value +#define FANZ 31 // number of mathematical functions in mfkttab[] +//@} + +//@{ +/** Predefined mathematical function. */ +double sign(double x); +double sqr(double x); +double arsinh(double x); +double arcosh(double x); +double artanh(double x); + +double sec(double x); +double cosec(double x); +double cot(double x); +double arcsec(double x); +double arccosec(double x); +double arccot(double x); + +double sech(double x); +double cosech(double x); +double coth(double x); +double arsech(double x); +double arcosech(double x); +double arcoth(double x); + +double lcos(double x); +double lsin(double x); +double ltan(double x); + +double lcosh(double x); +double lsinh(double x); +double ltanh(double x); + +double arccos(double x); +double arcsin(double x); +double arctan(double x); + +//@} + +class Constant +{ +public: + Constant( char c='A', double v=0) + { + constant = c; + value = v; + } + + char constant; + double value; +}; + +/** @short Parser. + * + * Tokenizes a function equation to be evaluated. + */ +class Parser +{ +public: + + Parser(); + Parser(int, int, int); + + ~Parser(); + + /// Evaluates the given expression. + double eval(QString); + /// Evaluates the function with the given name at the position. + double fkt(QString, double); + /// Evaluates the function with the given index at the position. + double fkt(int ix, double x) {return ufkt[ix].fkt(x);} + /// Adds a user defined function with the given equation. + int addfkt(QString); + /// Removes the function with the given name. + int delfkt(QString); + /// Removes the function with the given index. + int delfkt(int); + /// Returns name and expression of the function with the given index. + int getfkt(int, QString&, QString&); + /// Checks, if at the given index a function is stored. + int chkfix(int); + /// Returns the index of the function with the given name. + int getfix(QString); + /// Returns the lowest index in the array of user defined functions which is empty, + /// or -1, if the array is full. + int getNextIndex(); + /// Shows an error message box. + int errmsg(); + /// ? + void setparameter(int ix, double k) {ufkt[ix].k=k;} + /// return the angletype + static double anglemode(); + /// sets the angletype. TRUE is radians and FALSE degrees + void setAngleMode(int); + + QValueVector<Constant> constant; + + /// Error codes. + /** + * The values have following meanings: + * \li 0 => parse success + * \li 1 => syntax error + * \li 2 => missing bracket + * \li 3 => function unknown + * \li 4 => function variable not valid + * \li 5 => too much functions + * \li 6 => memory overflow + * \li 7 => stack overflow + * \li 8 => function name allready used + * \li 9 => recursive function call + * \li 10 => didn't found the wanted constant + * \li 11 => emtpy function + */ + int err, + errpos, ///< Position where the error occured. + ufanz; ///< Max. count of user defined functions. + + + /** User function. */ + class Ufkt + { + public: + Ufkt(); + ~Ufkt(); + double fkt(double); ///< User defined function. + + unsigned char *mem; ///< Pointer to the allocated memory for the tokens. + unsigned char *mptr; ///< Pointer to the token. + QString fname; ///< Name of the function. + QString fvar; ///< Dummy variable. + QString fpar; ///< Parameter. + QString fstr; ///< Function expression. + int memsize; ///< Size of token memory + int stacksize; ///< Size of the stack. + double k, ///< Function parameter. + oldy; ///< The last y-value needed for Euler's method + } + *ufkt; ///< Points to the array of user defined functions. + +protected: + /** Mathematical function. */ + struct Mfkt + { + const char *mfstr; + double (*mfadr)(double); + }; + static Mfkt mfkttab[FANZ]; + +//private: +public: + + void ps_init(int, int, int), + heir1(), + heir2(), + heir3(), + heir4(), + primary(), + addtoken(unsigned char), + addwert(double), + addfptr(double(*)(double)), + addfptr(Ufkt*); + int match(const char*); + + unsigned + char evalflg, // 0 => String wird tokenisiert + // 1 => String wird direkt ausgewertet + *mem, // Zeiger auf Speicher fr Token + *mptr; // Zeiger fr Token + const + char *lptr; // Zeiger fr Funktions-String + int memsize, // Gr�e des Tokenspeichers + stacksize, // Gr�e des Stack + ixa; // Index der aktuellen Funktion + double *stack, // Zeiger auf Stackanfang + *stkptr; // Stackpointer + static double m_anglemode; + +}; + +#endif // parser_included |