Zerlegen in Token, RegEx Ausdruck für Pascal

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Angeregt durch das Video von sma wollte ich einen Converter basteln der mir das Portieren von Pascal Code erleichert.
Mein Problem ist gleich am Anfang beim zerlegen in die Token.
Dafür wird ein reg. Ausdruck verwendet.
Nun steh ich vor den Problem wie ich Kommentare und Strings handle als ganzes.
Als Beispiel, Pascal kennt (* *) und { } als Kommentar, FreePascal/Delphi erlaubt noch //.
Nun sollen darin keine weiteren Token erkannt werden, was bei mir natürlich kollidiert mit den anderen Regeln wie für Zahlen etc.
Wie stelle ich nun das am besten an? Mein Ansatz[1] funktioniert so nat. nicht, bin auch nicht sonderlich geübt in RegEx.

[1]

Code: Alles auswählen

TOKENS = re.compile(r"\(\*.*?\*\)|\d+")
Zuletzt geändert von darktrym am Dienstag 11. März 2014, 21:46, insgesamt 1-mal geändert.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
BlackJack

@darktrym: *Das* Video vom sma? Ein Link wäre vielleicht nicht schlecht. ;-)

Denn so ohne Kontext sehe ich nicht warum das „natürlich” nicht funktioniert. Der Text '42 (* foo 23 *) 4711' hätte zumindest drei Matches mit dem Ausdruck wobei die 23 in dem Kommentar nicht von dem \d+ erfasst wird.
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Habs ergänzt, nun sollte klar sein wovon ich sprach.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
BlackJack

@darktrym: Nicht wirklich. Was ist denn das konkrete Problem? Zeig doch mal eine Eingabe und die dazugehörige Ausgabe oder Fehlermeldung und beschreibe was nicht wie gewünscht funktioniert. Wie schon gesagt, den ”Ausdruck” '42 (* foo 23 *) 4711' kann man damit wunderbar aufteilen.

Da Pascal nicht zeilenorientiert ist wie der BASIC-Dialekt in sma's Interpreter, kann man den Quelltext natürlich nicht zeilenweise verarbeiten wenn man Kommentare über mehrere Zeilen erkennen will und man muss auch das Flag mitgeben, dass der '.' auch auf '\n' zutreffen kann. Und das MULTILINE-Flag für '//'-Kommentare um das Zeilenende mit '$' erkennen zu können. Ist das das Problem?
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Ich glaub, das hilft weiter. Danke.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
Benutzeravatar
diesch
User
Beiträge: 80
Registriert: Dienstag 14. April 2009, 13:36
Wohnort: Brandenburg a.d. Havel
Kontaktdaten:

Reguläre Ausdrücke sind für so was genauso wenig geeignet wie für das Parsen von HTML oder XML.

Nimm dir eine richtige Parser-Bibliothek, wie z.B. PyParsing, oder eine Tokenizer/Parsergenerator-Kombination (lex/yacc), wie z.B. PLY
http://www.florian-diesch.de
BlackJack

Zumindest für den Lexer verwendet man üblicherweise schon reguläre Ausdrücke. Ob man mehr braucht, hängt davon ab ob man wirklich die Programmstruktur für die Weiterverarbeitung benötigt, oder ob eine Strom von Tokens ausreicht.
Benutzeravatar
diesch
User
Beiträge: 80
Registriert: Dienstag 14. April 2009, 13:36
Wohnort: Brandenburg a.d. Havel
Kontaktdaten:

Verschachtelte Kommentare oder Kommentare, die String-Literale mit Kommentar-Ende-Zeichen enthalten, sind mit echten regulären Ausdrücken nicht zu parsen, mit den perl-artigen Erweiterungen in Python müsste das gehen, aber schön oder einfach ist das eher nicht.

Kommentare zu erkennen ist daher Sache des Parsers, nicht des Lexers.

Man kann sich natürlich auch selbst einen Kellerautomat bauen, mit dem man die Tokens verarbeitet. Aber mit den richtigen Werkzeugen kommt man schneller zu übersichtlichem, robustem Code.
http://www.florian-diesch.de
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Die Zerlegung der Token funktioniert erstmal muss aber trotzdem sukzessiv erweitert werden. Die Grammatik ist ein wenig komplexer als Basic.
Vielleicht kennt jemand eine gute Seite zur Übersicht.

Eine Frage zum Abschluss, zur Überprüfung ob alles wichtige in Token aufgeteilt wurde, hätte ich gern eine Möglichkeit der Überprüfung. Praktischerweise verliert man ja alle Formatierungszeichen und Whitespaces. Für die Verarbeitung toll, zur Kontrolle bescheiden.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
BlackJack

@darktrym: Schau Dir FreePascal an, notfalls die Quellen für deren Parser. Und verwende wie diesch schon sagte eine Parserbibliothek.
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

@diesch: Kannst mal ein Beispiel nennen, das ich testen kann. Kann mir so recht schwer vorstellen, warum das schief gehen sollte.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
BlackJack

@darktrym: '(* (* test *) *)'. Das ist aber kein Standardpascal und weder TurboPascal noch Delphi verarbeiten das. FreePascal erlaubt das, wenn man nicht im TP- oder Delphi-Modus übersetzt, gibt aber eine Warnung aus.
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Rein aus Interesse(nicht auf Pascal bezogen) wenn sowas wie "\"" in C hätte, das begreift doch kein reg. Ausdruck.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@diesch: ich hoffe mal, dass es keine Sprache gibt, in denen Stringliterale eine besondere Rolle innerhalb von Kommentaren spielen, weil das auch jeden Parser vor unlösbare Probleme stellt.
BlackJack

@darktrym: Natürlich kann man da einen regulären Ausdruck für schreiben. Da muss man noch nicht einmal \" besonders berücksichtigen, sondern kann ganz allgemein Escape-Sequenzen berücksichtigen: r'"(\\.|[^"])*"'. Hier jetzt mal nur für Sequenzen die nur aus einem Zeichen bestehen.
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Sirius3 hat geschrieben:@diesch: ich hoffe mal, dass es keine Sprache gibt, in denen Stringliterale eine besondere Rolle innerhalb von Kommentaren spielen, weil das auch jeden Parser vor unlösbare Probleme stellt.
Pascal verfolgt zum. so ein Konzept namens Compilerdirektiven, dass sein Kommentarblock evtl. umfunktioniert wenn ein Dollarzeichen am Anfang gefunden wurde. Was noch erwähnenswert ist, irgendjemand dachte es ist cool sowas zu erlauben {Kommentar*).
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Wie formuliere ich denn richtig den Kommentar als Regel, mein Ansatz scheint jedenfalls nicht ganz richtig zu sein.
r"[\{|(\(\*)].*?[\}|(\*\))]
Testdaten:

Code: Alles auswählen

(* 2047 jjkhAS asd
 * +asasdasda
 *)
var s:string;
{QUARK}
(*Test}
begin 
    writeln('HALLO');
    var a: int;
    a:=234;
    a := 1+2*3+(3*3);
    ^a := 2;
    if a=3 then begin end;
end.
Ergebnis, erwischt nich nur Kommentare:

Code: Alles auswählen

['(*', '* +asasdasda\n *', ')\nvar s:string;\n{QUARK}', '(*', "('HALLO')", '*3+(', '*3)']
PS: Das hiesige Formatierungsskript machts übrigens auch falsch.
PPS: Ich weiß das oben ist nicht pascal-konform.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@darktrym: Eckige Klammern definieren in regulären Ausdrücken Mengen.
Was Du willst, ist "(?:{|\(\*).*?(?:}|\*\))".
BlackJack

@darktrym: Innerhalb von eckigen Klammern gelten andere Regeln. Die meisten Sonderzeichen verlieren ihre besondere Bedeutung, dafür gibt es dort Zeichen mit besonderer oder anderer Bedeutung als ausserhalb. ^ ist zum Beispiel Negation statt Anfang der Zeichenkette, - hat die Bedeutung „bis” wenn es zwischen zwei Zeichen steht, | und die runden Klammern sind einfach nur | und runde Klammern und keine Alternative oder Gruppe.

Edit: Zu *dem* richtigen Ausdruck für Kommentare muss man wohl auch immer dazu angeben wie Kommentare eigentlich definiert sind, denn das scheint sich ja von Compiler zu Compiler zu unterscheiden, beziehungsweise von Optionen/Direktiven abhängig zu sein.
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Es gibt für Pascal eine ISO-Norm.

Da steht drin:
Where a commentary shall be any sequence of characters and separations of lines, containing neither } nor *), the construct

( '{' | '(*' ) commentary ( '*)' | '}' )

shall be a comment if neither the { nor the (* occurs within a character-string or within a commentary.

NOTES

A comment may thus commence with { and end with *), or commence with (* and end with }.
The sequence (*) cannot occur in a commentary even though the sequence {) can.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
Antworten