User soll ausführbaren Code zur laufzeit eingeben

Interstate76

Grünschnabel
Hi an alle,

bin relativ neu im Forum und in Java, hab aber schon eine gute Grundlage in Java-Programmierung, brauch jetzt aber doch den ein oder anderen Trick.

Ich weiß bei meinem Programm leider nicht mehr weiter:
Ich möchte gern vom User über eine Eingabemaske eine Funktion eingeben lassen. Diese Funktion soll dann in einem X-Y Koordinatensystem angezeigt werden (ich benutze JMathPlot). Und dieses JMathPlot arbeitet mit üblichen f(x) Funktionen (Bsp.: Math.sin(3*x+3)*1/3 )

Nur weiß ich leider nicht wie ich den "f(x) - String" in ausführbaren Code umwandeln kann. Ich hab von nem Freund nen Tipp bekommen ich müsse Parser benutzen. Parser kenn ich eigenltich nur wenn ich von einem String z.B.: in Integer konvertieren will, aber ich meine das ist was anderes als eine ganze Zeile Code zu "übersetzen". Hab unter Parser leider nichts hilfreiches im Netz gefunden. Aber vllt fehlen mir auch nur die Vokabeln um den passenden Thread zu finden, oder es ist überhaupt die völlig falsche Baustelle :rolleyes:.


kann mir da jemand helfen? mit nem link zu nem codebeispiel oder so?

herzlichen Dank schon mal und
Viele Grüße!
 

Interstate76

Grünschnabel
Danke Klaus. Na wie gesagt hab ich ja bereits gekannt.
Aber ich war der meinung es gäbe da ne möglichkeit einen langen String auf einmal in ausführbaren Code zu wandeln.
Das was auf Wikipedia steht ist ja ein rumdrehn der Zeichen für Zeichen.

gibts denn sowas komfortables denn nicht?
 

vfl_freak

Premium-User
Moin,

eine hinter dem Parser liegende Grammatik muss ja Deinen Ausdruck zeichenweise auswerten !
Wie soll es denn sonst noch einfacher gehen ?

Du willst doch wohl keine Grammtik definieren, die jeden theorisch möglichen, kompletten Ausdruck kennt, also :
Java:
// ...
Math.sin(1*x+1)*1/2
Math.sin(2*x+1)*1/2
// ...
Math.sin(1*x+1)*1/2
Math.sin(1*x+2)*1/2
// ...
Math.sin(1*x+1)*1/3
Math.sin(1*x+1)*1/4
// ...
// usw. usw.
Gerade das zeichenweise auswerten ermöglich Dir ja mit (relativ) kurzem Code größt-mögliche Flexibilität!

Gruß
Klaus
 

ikosaeder

Teekannen-Agnostiker
Das Problem hatte andere ja auch schon, schau mal hier, das scheint eine recht gut durch dachte Lösung zu sein.
http://rsudhakar.wordpress.com/2010/11/03/eval-in-java/
Alternativ wird hier vorgeschlagen, das ganze mit Javascript zu lösen:
http://www.beyondlinux.com/2011/08/07/3-method-to-evaluate-expressions/
Und hier nochmal ähnlich wie die Erste:
http://introcs.cs.princeton.edu/java/43stack/Evaluate.java.html

Achja, wenn du den String selbst parst, muss der User Sachen wie Math.sin nicht eingeben. Für den User würde es reichen sin einzugeben und dein Parser ersetzt das dann du den korrekten Funktionsaufruf. Dadurch könntest du sogar komplexe Sachen wie eine Ableitung behandeln. Der User schreibt dxdt und dein Parser erzeugt daraus einen Differenzenquotienten (x2-x1)/(t2-t1). Als Beispiel ist in der 3. Lösung die Wurzelfunktion zu finden.

Eine weitere Alternative wäre noch die Einbindung von Matlab in dein Javaprogramm. Scheint etwas tricky zu sein, aber auch dafür gibt es hier
http://www.cs.virginia.edu/~whitehouse/matlab/JavaMatlab.html
eine Anleitung.

Nachtrag: Noch eine Alternative:
http://gnujavaplot.sourceforge.net/JavaPlot/About.html
Viel Spaß damit!
 
Zuletzt bearbeitet:

Interstate76

Grünschnabel
mit JavaScript kenn ich mich leider gar nicht aus.
Ich hab mir aber mal die Beispiele angeschaut.

Ich nehme mal das Beispiel Evaluate.java ( http://introcs.cs.princeton.edu/java/43stack/Evaluate.java.html ) :
Wenn mich nicht alles täuscht tut er den String zwar Parsen aber er gibt ihn einfach nur berechnet wieder aus (oder?). Hab jetzt gesehen dass es günstiger ist mich um das Parsen selber zu kümmern.
Aber eigentlich möcht ich ja die Funktion die eingegeben wurde in JMathPlot ausführen lassen, also wie der titel schon sagt, zur laufzeit ausführbaren code eingeben. Das ist noch der Hacken bei dems noch hängt. Danke an euch beide erst mal! Ich glaub wir habens gleich :)
 

ikosaeder

Teekannen-Agnostiker
Vielleicht habe ich dich ja falsch verstanden.
So wie ich das sehe benötigst du für deinen Plot zwei Arrays mit Werten für x und y
Das heißt dein User gibt eine Funktion an, f(x)=sin(x*2)+5 und einen Wertebereich [-2,8]
Dann soll dein Programm für jedes X in dem Intervall das f(x) bzw. y ausrechnen
also f(-2)=sin(-2*2)+5, f(-1)=sin(-1 *2) +5, ... , f(8)=sin(8*2)+5
Das gibt dann die Arrays X[-2,-1,...,8] und y[f(-2),f(-1),...,f(8)] die Jmathplot dann benutzt um den Graphen zu zeichnen.
Wenn also dein String geparst wird und ausgerechnet, musst du dich ja nur noch um die Übergabe der Wertepaare an Jmathplot kümmern.
Aber natürlich solltest du den Parser selbst schreiben, die Beispiele decken ja nur einen kleinen Teil der möglichen Eingaben dar.
Das letzte Beispiel funktioniert anders, da übergibst du deinen ungeparsten String (in Gnuplot Syntax) an die JGnuplotfunktion, die dann direkt den Plot zeichnet, als alternative zu JMathplot. Da musst du dich halt um gar nichts kümmern. Interessant dürfte sein, das dies OpenSource ist, du also im Code nachschauen kannst, wie die den String parsen.
 

Interstate76

Grünschnabel
du hast recht ich hab das völlig aus den Augen verloren, ich brauche eigentlich nur eine Wertemenge abhänig von der schrittweite. Damit wäre das Problem eigentlich gelöst

Aber gäbe is frei von dieser Aufgabe die möglichkeit einzelne (unbekannte/unerwartbare) Codezeilen vom Nutzer eingeben zu lassen? Ich mein ist das nicht irgendwie nicht auch der Sinn eines Interpreters?
 

ikosaeder

Teekannen-Agnostiker
Klar kannst du beliebigen Code eingeben lassen. Aber egal wie du es machst, du musst den String, den der User eingibt zerlegen und stückweise auswerten (parsen)
Das ist allerdings immer ein Sicherheitsrisiko und eine erhebliche Fehlerquelle.
Der User kann schließlich beliebige Strings eingeben, die im günstigsten Fall nichts bewirken. Im schlechtesten Fall kann es zu Abstürzen, Sicherheitslücken und unerwartetem Verhalten des Codes kommen.
Also musst du die User Eingaben immer noch mal checken, ob sie den erlaubten Vorgaben entsprechen und das ganze in try catch Anweisungen packen um ungültige Eingaben abzufangen.
Und je mehr Möglichkeiten du einbauen willst, desto umfangreicher und komplexer wird dein Parser. Wenn du das weit genug treibst, hast du am Ende einen eigenen Interpreter erstellt.

Merke: Eval is Evil
 

Interstate76

Grünschnabel
okay ich verstehe. Wobei ich mal gehört habe dass Java anscheinend keinen zugriff auf fieße Systeminterrupts gewährt? also können doch so horrorszenarien wie format c: oder ähnliches gar nicht passieren? Naja aber so genau wollt ichs dann doch nicht wissen.

Ich weiß jetzt einiges mehr, herzlichsten Dank ikosaeder und vfl_freak für die Unterstützung !!

Viele Grüße