Simpler C Funktionsparser

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.
Antworten
anogayales
User
Beiträge: 456
Registriert: Mittwoch 15. April 2009, 14:11

Hallo zusammen!

Ich schreib gerade einen kleinen Funktionsparser, der top level Funktionsnamen auflisten soll.

Hier ist der zu parsende Code:

Code: Alles auswählen

void functionname1(float a, float r) {
	return min(a,r);
}

float nonesense(int b) {
    function body;
}


float abs(vec3 pos) {
    function body;
} 
Der reguläre Ausdruck auf den ich gekommen bin lautet:

Code: Alles auswählen

[\w]+[\s]+([\w]+)\(
Das Ergebnis:

Code: Alles auswählen

['functionname1', 'min', 'nonesense', 'abs']
Leider nimmt er dabei auch das min auf. Wie kann ich sagen, dass er nur top level funtionen aufnehmen soll? Geht das mit Regulären Ausdrücken?

Es wäre nett, wenn mir jemand helfen könnte.

Grüße,
anogayales
BlackJack

@anogayales: Ich würde sagen das geht nicht zuverlässig mit einem regulären Ausdruck.
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

anogayales hat geschrieben:Leider nimmt er dabei auch das min auf. Wie kann ich sagen, dass er nur top level funtionen aufnehmen soll? Geht das mit Regulären Ausdrücken?
Vergiss es. Spätestens wenn du auf Strings mit passenden Inhalten stößt ist Schluss mit lustig.
BlackJack

Ergänzend zu /me: Passende Treffer in Kommentaren, zum Beispiel auskommentierter Quelltext. Ausserdem kann vor dem Funktionsnamen mehr als ein ”Wort” stehen, zum Beispiel bei ``unsigned int``. Nicht zu vergessen Schlüsselwörter wie ``static`` oder ``const``. Und der ``*``. Nach dem Funktionsnamen kann unter Umständen auch noch etwas stehen.
anogayales
User
Beiträge: 456
Registriert: Mittwoch 15. April 2009, 14:11

Danke für euren Input. Um genau zu sein parse ich GLSL Code. Dort sollten keine Konstrukte der form "unsigned integer" auftauchen. Im Grunde genommen ist es eine sehr abgespeckte form vom C-Standard. Es können wahrscheinlich weitere Probleme auftreten, aber damit kann ich leben.

Module wie pycparser finde ich dann doch eine bisschen schwergewichtig. Gibt es keinen RE, der für mein oben genanntes Beispiel und "ähnliche" das passende liefert?

Grüße,
anogayales
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Da es beliebig tiefe Verschachtelungen geben kann ist ein RE nicht möglich. Mit einem Parser wirst du auf jeden Fall schneller ans Ziel kommen.
Das Leben ist wie ein Tennisball.
lunar

@anogayales: Einen regulären Ausdruck, der Funktionssignaturen zuverlässig erkennt, gibt es erwiesenermaßen nicht. GLSL ist zwar in mancher Hinsicht einfacher, aber noch immer eine kontextfreie Sprache, welche sich mit regulären Ausdrücke nicht parsen lässt. Man kann zwar einen regulären Ausdruck für eine Funktionsdeklaration aufstellen, doch es ist unmöglich, mit einem regulären Ausdruck allein zu erkennen, ob diese Deklaration in einem Kommentar steht.

Ich bezweifele allerdings, dass pycparser GLSL parsen kann. GLSL unterscheidet sich an manchen Punkten signifikant von C. Manche GLSL-Konstrukte gibt die C-Grammatik nicht her, und so wird ein C-Parser wahrscheinlich auch an solchen Konstrukten scheitern (zumindest wenn er sich an den Standard hält).
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

lunar hat geschrieben:Einen regulären Ausdruck, der Funktionssignaturen zuverlässig erkennt, gibt es erwiesenermaßen nicht.
Aber *muss* es den nicht geben? Der Compiler erkennt die Signatur ja schließlich auch, sonst könnte er die Übersetzung nicht leisten.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

snafu hat geschrieben:
lunar hat geschrieben:Einen regulären Ausdruck, der Funktionssignaturen zuverlässig erkennt, gibt es erwiesenermaßen nicht.
Aber *muss* es den nicht geben? Der Compiler erkennt die Signatur ja schließlich auch, sonst könnte er die Übersetzung nicht leisten.
Der Compiler benutzt aber tot sicher nicht nur einen Lexer - und genau für diese Funktionalität benutzt man ja RegExps.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Die Definition müsste doch IMHO wie folgt sein: Ein Wort, welches kein Schlüsselwort ist mit optionalem Whitespace gefolg von einem Klammer-Auf-Zeichen. Vor diesem Wort muss etwas stehen, das ein Schlüsselwort ist. Naja, gut. Das scheitert spätestens an eigenen Typbezeichnungen. Bietet der GCC einem da keine Schnittstelle, oder so?
BlackJack

@snafu: Wenn es sich denn um C handeln würde, aber wir haben ja mittlerweile GLSL als Sprache.
lunar

@BlackJack: Trifft diese Definition bei GLSL nicht noch eher zu als bei C? Immerhin hat GLSL keine Zeiger und mithin auch keine Signaturen ala:

Code: Alles auswählen

void (*signal(int sig, void (*func)(int)))(int);
BlackJack

@lunar: Dazu kenne ich GLSL zu wenig. Es bleibt aber auf jeden Fall das Problem mit Zeichenketten und Kommentaren.
lunar

@BlackJack: Ich kenne GLSL gar nicht, sondern hab lediglich einen kurzen Blick in die Spezifikation geworfen. Da stand irgendwo "no pointers", und zu Zeichenketten habe ich dort auch nichts gefunden. Und in den Beispielen waren auch eine Ausdrücke zu sehen, die kein gültiges C mehr sind.

Mit regulären Ausdrücken kann man GLSL natürlich trotzdem nicht parsen.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Wenn "toplevel" heißt, der Ausdruck beginnt immer ganz links, und wenn kein anderer Ausdruck ganz links beginnt, einfach ein "^" in den RE einfügen und das Multiline-Flag setzen, wenn man einen RE für das gesamte Programm benutzt.

Code: Alles auswählen

import re

s = """
void functionname1(float a, float r) {
   return min(a,r);
}
...
"""
print re.findall(r'^[\w]+[\s]+([\w]+)\(', s, re.M)
Auch nur ein Hack, aber ein besserer :)

Stefan
Antworten