Datentypen Reader/InputStream wiederverwenden?

diggaa1984

Top Contributor
Hiho,

ich habe gerade den Fall, dass ich vor meinen Lexer (Analyse von Strings für Grammatik-Parser) einen Stream schalten muss (CharacterStream aus ANTLR-api). Dieser Stream soll als Input einen String erhalten. Nach einem erfolgreichen Durchgang, sprich ich habe den Input komplett gelext, hätte ich nun gern, dass ich nich jedesmal ein neues Stream-Objekt erstelle und an den Lexer hänge, sondern stattdessen neue Daten in den Stream schreibe.

Ich habe nun die Wahl zwischen Reader und InputStream-Interfaces um mein Vorhaben zu realisieren.
Gibt es da eine Möglichkeit zur Laufzeit die Streams neu zu befüllen?! Ich habe bisher echt nix gefunden

Folgender Ablauf sollte möglich sein:

Stream füllen -> lexen (Stream kann gelernt werden, muss nich sein, kann man auch manuell machen)
Stream notfalls leeren + Lexer resetten + Stream neu befüllen -> lexen
 
Zuletzt bearbeitet:
Hm... so ganz klar ist es (mir) nicht... Das kann eine eigene Klasse sein? Dann könnte man ja einen eigenen InputStream schreiben ("RefillableInputStream" oder so 😀 ) - welche Rolle spielt da genau der "CharacterStream"? (Und was spricht dagegen, einen neuen Stream zu erstellen, wenn das vielleicht ohne irgendwelche Krämpfe und/oder eigene Spezialklassen möglich ist (die die Flexibilität der API einschrängen können, weil sie ja dann im schlimmsten Fall immer einen RefillableInputStream erwartet (und keinen allgemeinen InputStream))?)
 
also ich müsste jedesmal wenn ich etwas lexen möchte sagen:
Java:
lexer.setCharacterStream(new ...(stringToParse))

das find ich irgendwie komisch und beim Syntaxhighlighting muss ich sowas ja regelmäßig aufrufen.
Ich hatte schon die Idee ne Klasse wie du sie vorschlägst zu schreiben und mich dabei an den Initialisierungs-prozeduren der Superklasse (zb: ANTLRStringStream) zu orientieren, bzw die protected-Felder zu bearbeiten, aber da bin ich zum bsp. nicht sicher ob das Beerben der Klasse lizenztechnisch andere Umstände darstellt als das bloße Verwenden der API aus der jar-Datei. Ich wäre aber der Meinung, dass das nichts ausmacht und ich meine Software nicht zwangsweise frei verfügbar machen muss, was ich nämlich nicht entscheiden kann (Diplomarbeit).

ANTLR 3 License

[The BSD License]
Copyright (c) 2010 Terence Parr
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

vermutlich sollte ich einfach die set-Methode beibehalten ^^
Deiner Antwort entnehme ich aber, dass du auch nichts kennst, was so wie es ist, meinen Anforderungen entspricht, sondern ich mir nen Wrapper schreiben müsste, der die Funktion bereitstellt.
 
Pipe heisst das Zauberwort denk' ich. Da gibt es einen PipedReader und einen PipedWriter bzw. auch Input- und OutputStreams. Benötigt werden 2 Threads, einer für Ein- der andere für Ausgabe. Das ist nötig, da der OutputStream im Leerlauf stets auf neue Eingaben und der InputStream bei befülltem Puffer auf Entnahme der Daten wartet.
Am Ende würde dann also ein [c]lexer.write((CharSequence) sequenceToParse);[/c] genügen.
 
bezüglich der threads, fehlt wohl noch eine info 🙂

es gibt folgende Struktur (bedingt durch ANTLR-API):

Code:
CharacterStream -> Lexer -> TokenStream -> Parser (oder zB. Syntaxhighlighting-Klasse)


Der Lexer bekommt als Input ein CharacterStream (das kann StringStream sein, FileStream, InputStream etc.) .. wesentlich ist, dass der CharacterStream die Daten sofort intern ablegt und aus den internen Daten bei Bedarf die Infos rausgibt.
Der Parser pollt quasi aus dem TokenStream die Infos, welche meiner Meinung nach auch on Demand aus'm Lexer gelesen werden. Der Lexer holt die sich wiederum on Demand aus dem CharacterStream.

Daher wäre durch das manuelle Pollen erstma kein Threadhandling notwendig. ICh bräuchte auch gar nicht direkt den Lexer ansprechen sondern würde sagen
Code:
TokenStream.<machWas>
und der liefert mir das Token oder was auch immer. So der Plan.
 
Zuletzt bearbeitet:
Ok... was es damit auf sich hat, entzieht sich meiner Kenntnis. Aber du hast doch nach einem wiederbefüllbaren Stream (RandomAccessStream) gesucht. Die Pipe bietet diese Möglichkeit, erfordert aber halt 2 unabhängige Threads. Möglicherweise ist der Lexer ja bereits ein solcher Thread oder man kann ihn zu einem machen.
Eine andere Möglichkeit wäre, sich diese Pipe-Klassen mal anzusehen, zu schauen, warum 2 Threads nötig sind um sich anschliessend mit den gewonnenen Erkenntnissen selbst einen solchen RAStream zu coden, der mit nur einem Thread auskommt.
 
Lexer und Parser bei ANTLR laufen ohne Threads, d.h. für den PipedStream muss man sich selbst um die Threads kümmern.
 
Ich glaube das wäre mit Kanonen auf Spatzen schiessen, ich belass es erstmal beim Erzeugen neuer Instanzen, gibt ja noch genug andere Baustellen im Projekt 🙂

Trotzdem danke für den Ansatz mit den Pipes, werds mir mal anschauen, vielleicht kann ich das ja woanders noch gebrauchen.
 
Wenn ich so recht überlege wird das auch nicht funktionieren mit wiederverwenden. Denn der Lexer und Parser kann das Ende der Eingabe nicht zuverlässig erkennen solange der Stream nicht geschlossen wird. Dadurch würde der Syntaxcheck dann hängen bleiben wenn z.B. die abschließende Klammer in deinem Text fehlt. Denn die könnte ja noch kommen, der Stream ist ja noch nicht am Ende.
 
Interessante Überlegung, müsste man mal testen 🙂
Dann wäre die Krücke zu sagen, wenn nix im Stream soll er null liefern, mal spontan gedacht.
 
Nicht null, sondern -1 muss dein Stream liefern von dem du deinen Code liest. Und darauf musst du deinen AntlrCharacterStream los lassen. Das sollte funktionieren. Wobei ich nicht weiß wie der Lexer reagiert wenn ein Stream der zu Ende ist plötzlich wieder Daten liefert.
 
den lexer kann man resetten und der pollt vom stream, da dürfte es keine probleme geben ich kann auch bisher folgendes machen:

CharacterStream-Subklasse liefert eine Funktionalität von Files einzulesen (ANTLRFileStream). Diese Klasse besitzt eine Methode
Code:
load(...)
. Damit kann ich zur Laufzeit neue Daten in die interne Struktur des Streams laden. Der lexer wird resetted und alles klappt.
Damit habe ich mal eine Reihe von Testdateien auf meinen Lexer losgelassen. Intern hat der Stream dann seine Datenfelder angepasst bzw überschrieben mit den neuen Werten.
 

Zurück
Oben