Verfasst: Freitag 2. Februar 2007, 14:09
implementier nen richtigen parser, samt statemachine und allem
Seit 2002 Diskussionen rund um die Programmiersprache Python
https://www.python-forum.de/
XML ja, BBCode nein. Für BBCode parsen habe ich für pocoo doch einen relativ komplexen Lexer/Parser Verschnitt schreiben müssen. Probleme sind verschachtelte Quote/Code Blöcke, da geht mit Regex nichts mehr und code/list blöcke ansich, die kein BBCode in sich erlauben etc.BlackJack hat geschrieben:So etwas wie BBCode oder XML/HTML ist recht einfach, weil man bei einem Start-Tag rekursiv absteigen kann und bei einem Ende-Tag wieder eine Ebene höher gehen kann.
Das "Nein" verstehe ich jetzt nicht? Wo widersprichst Du mir denn? Oder wo gibt's Probleme mit einem rekursiv absteigenden Parser?blackbird hat geschrieben:XML ja, BBCode nein. Für BBCode parsen habe ich für pocoo doch einen relativ komplexen Lexer/Parser Verschnitt schreiben müssen. Probleme sind verschachtelte Quote/Code Blöcke, da geht mit Regex nichts mehr und code/list blöcke ansich, die kein BBCode in sich erlauben etc.BlackJack hat geschrieben:So etwas wie BBCode oder XML/HTML ist recht einfach, weil man bei einem Start-Tag rekursiv absteigen kann und bei einem Ende-Tag wieder eine Ebene höher gehen kann.
Dieser Aufbau wird doch immer wieder gemacht. Könnte man nicht eine Variante bauen, die allgemein Gültig ist?cracki hat geschrieben:tokenisieren, parsen, ausgeben...
Klar, PyParsing und ZestyParser lassen grüßen.jens hat geschrieben:Dieser Aufbau wird doch immer wieder gemacht. Könnte man nicht eine Variante bauen, die allgemein Gültig ist?cracki hat geschrieben:tokenisieren, parsen, ausgeben...
Ja kann man. Daran versuche ich mich ja gerade.jens hat geschrieben: Also das man einen Parser hat, bei den man die Syntax quasi per config definiert. So könnte man den Parser für verschiedene Markups gleichzeitig nutzten.
Es gibt ja auch welche die EBNF als Config akzeptieren. Sieh dir mal als Beispiel dan guten alten yacc an, der versteht BNF.jens hat geschrieben:Also das man einen Parser hat, bei den man die Syntax quasi per config definiert.
Einfach im Lexer den Text spliten:EnTeQuAk hat geschrieben: So... so soll das aber nicht erkannt werden... *grml* -- wie kann ich da besser vorgehen -- wie müsste ich über den Text iterieren, um Tokens anzufertigen, um solche Sachen auch "zuferlässig" zu treffen?
Code: Alles auswählen
src = """{{{LITERAL_ALL_CHARS
}}}
**//test//**
"""
regexp = re.compile(r'({{{|}}}|\*\*|//|__|)')
output = [x for x in regexp.split(src) if x != '']
print output
Code: Alles auswählen
['{{{', 'LITERAL_ALL_CHARS\n', '}}}', '\n', '**', '//', 'test', '//', '**', '\n']
Code: Alles auswählen
['LITERAL_ALL_CHARS\n', '\n', 'test', '\n']
genau sowas habe ich ja auch gemacht. der parser ist ein modul mit funktionen und klassen. das grammar ist ein grosses dict mit nonterminal -> grammar zuordnungen und alles ist mit funktionen modelliert. man muss das grammar selbst also nicht nochmal parsen, weils schon code ist.jens hat geschrieben:Könnte man nicht eine Variante bauen, die allgemein Gültig ist?
Ich meine, das man nicht direkt die Regeln "wenn input = xy dann output =xy" festlegt, sondern das nochmals in einer weiteren Ebene.
Also das man einen Parser hat, bei den man die Syntax quasi per config definiert. So könnte man den Parser für verschiedene Markups gleichzeitig nutzten.
Wie man generell einen AST verarbeitet oder modellieren sollte um leichten Zugriff zu haben oder speziell von dem PEG?cracki hat geschrieben:und wie man den baum gescheit weiterverarbeitet (oder beim parsen gleich verarbeitet), das wissen fehlt mir noch.
Hey... das mit der Klammer wars Das werde ich gleich mal ausprobieren.sape hat geschrieben:Einfach im Lexer den Text spliten:EnTeQuAk hat geschrieben: So... so soll das aber nicht erkannt werden... *grml* -- wie kann ich da besser vorgehen -- wie müsste ich über den Text iterieren, um Tokens anzufertigen, um solche Sachen auch "zuferlässig" zu treffen?
Code: Alles auswählen
src = """{{{LITERAL_ALL_CHARS }}} **//test//** """ regexp = re.compile(r'({{{|}}}|\*\*|//|__|)') output = [x for x in regexp.split(src) if x != ''] print output
Die einzelnen Tokens muss dann der Lexer mit den richtigen Typ versehen.Code: Alles auswählen
['{{{', 'LITERAL_ALL_CHARS\n', '}}}', '\n', '**', '//', 'test', '//', '**', '\n']
BTW: Wichtig ist das der ausdruck im re-teil in runden klammern eingeschlossen ist!!
r'({{{|}}}|\*\*|//|__|)' = OK
r'{{{|}}}|\*\*|//|__|' = Nicht OK weil dann sowas bei rauskommt:lgCode: Alles auswählen
['LITERAL_ALL_CHARS\n', '\n', 'test', '\n']
wie ich einen AST so bequem wie moeglich weiterverarbeite. dazu zaehlt z.b. baum stutzen, transformationen, solche geschichten. braucht dich aber nicht kuemmern, weil es geht ja, nur ists mir zu umstaendlich. hab auch das drachenbuch noch nicht gelesen, also...sape hat geschrieben:Wie man generell einen AST verarbeitet oder modellieren sollte um leichten Zugriff zu haben oder speziell von dem PEG?
Das kann mein Lexer auch nicht, das wird im HTML-Writer mit dem Stack gemacht.sape hat geschrieben:Hmm, irgendwie verstehe ich nicht so ganz wie dein Lexer den Beginn- und End-Tag von Markups mit gleichen Token unterscheiden kann Bei mir musste ich dafür ein par Zeilen schreiben.
Code: Alles auswählen
[...]
from ast.ast import MarkupClassNames as MCN
_NAME_OF_THIS_MODULE = os.path.basename(__file__).split('.')[0]
class BasisLexer(object):[...]
def __init__(self, source):
self.markup_identifier = (
# Markups die den gleichen Bezeichner für Begin und Ende verwenden.
{MCN.MARKUP_BOLD: (r'\*\*', None)}, # <- **
{MCN.MARKUP_ITALIC: (r'//', None)},
{MCN.MARKUP_UNDERLINE: (r'__', None)},
# Markups die unterschiedliche Bezeichner für Begin und Ende verwenden.
{MCN.MARKUP_CODE: (r'{{{', r'}}}')}
)
self.init(source)
def init(self, source):
mre = re.compile(self._merge_markups_to_restr())
self.source = [x for x in mre.split(source) if x != '']
self._lexer_stream = None
[...]
def _merge_markups_to_restr(self):
li = list()
for elem in self.markup_identifier:
identifier = elem.values()[0]
if identifier[1] is not None:
li.append("%s|%s|" % (identifier[0], identifier[1]))
else:
li.append("%s|" % identifier[0])
return r"(%s)" % "".join(li)[0:-1]
[...]
Das ist schon okay, erkennt aber weder Überschriften noch "Befehle mit Argumenten" wie ``#image[spam/eggs.png]``. Den ersten Teil habe ich genauso wie Du.sape hat geschrieben:BTW: Die regexp von dir verstehe ich noch nicht. Müssen die so Kompliziert sein?
Ich hab das so gelöst mit de regexp (Kleiner Ausschnitt):
[…]
Das ergibt (\*\*|//|__|{{{|}}}). Damit splite ich den text. Ist das eventuell nicht ok? Welchen vorteil habe ich mit deinen regexp code? -- Bisher habe ich damit alles richtig gesplitet gekriegt ohne Fehler.