Forum: PC-Programmierung Verwendung von Lex/Yacc


von Tobias P. (hubertus)


Lesenswert?

Hallo zusammen

ich möchte mich mal mit dem Thema Lex/Yacc befassen.
Gestern habe ich mir mal Lex ein wenig angeschaut. Eigentlich keine 
riesen Hexerei. Aber Lex allein taugt im Prinzip nicht viel, oder?

Jetzt habe ich mir mal für den Text, den ich parsen möchte, eine Datei 
mit dieser Backus Naur Form angelegt. Wikipedia hilft, es ist relativ 
einfach, wenn man mal ein paar Beispiele durchgelesen hat.
Allerdings frage ich mich jetzt ein paar Sachen.

a) wie komme ich jetzt mit Hilfe dieser Backus Naur Form auf ein 
C-Programm?
eigentlich brauche ich hierzu Lex doch gar nicht, oder? Ich meine, man 
müsste eine Zerlegung in Tokens schon anhand der Backus-Datei vornehmen 
können, wozu braucht man dann Lex?

b) jetzt noch fast die wichtigere Frage:
Zwar erhalte ich beispielsweise mit Lex ein lauffähiges Programm, 
welches verschiedene Tokens unterscheiden kann. Dann kann man 
beispielsweise in der Konsole einen Text eingeben, und das Programm 
zerlegt den dan. Ansich eine ganz nette Spielerei, aber wenn ich z.B. 
eine INI-Datei parsen möchte (als triviales Beispiel) dann nützt mir das 
von Lex generierte Programm wenig. Wie baue ich also etwas, was ich mit 
Lex generiert habe, in mein bestehendes C-Programm ein? und noch 
wichtiger: Der generierte Quelltext ist total aufgeblasen und nahezu 
unlesbar, ist das wirklich dafür gedacht, 1:1 so verwendet zu werden?

von Schantall (Gast)


Lesenswert?

lex:  Scanner-Generator: Erkennt die "Wörter" (== Token) einer Sprache
yacc: Parser-Generator:  Erkennt, ob ein Eingabetext einer definierten
Grammatik entspricht. Üblicherweise ruft der Parser den Scanner auf, 
wenn er ein neues Token aus dem Eingabetext braucht.
Konkret: Der aus der in Backus-Naur geschriebenen Grammatik vom yacc
erzeugte Parser ruft den lex-generierten Scanner auf.

>Der generierte Quelltext ist total aufgeblasen und nahezu
>unlesbar, ist das wirklich dafür gedacht, 1:1 so verwendet zu werden?

Wieso willst Du den überhaupt lesen? Völlig unötig.
Und: Wie willst Du beurteilen können, ob "aufgeblasen" oder nicht, ohne 
die Grundlagen zu kennen? Ansonsten: Scanner kann man auch "von Hand" 
schreiben.

Empfehlung: Hole Dir die Bison (GNU Version von Yacc) und
Flex (GNU Version von lex) Manuals und lese die durch.

Oder besser noch: Befasse Dich mit den Grundlagen des Compilerbaus. Da 
gibt es sicher genug Material in den Weiten des Internets.
Ansonsten: Wirth: Compilerbau oder Aho, Sethi, Ullman: Principles of 
Compiler Design (Drachenbuch)

von Schantall (Gast)


Lesenswert?

>Aho, Sethi, Ullman: Principles of Compiler Design (Drachenbuch)

Bzw: Compilers: Principles, Techniques, and Tools

von Jonas K. (jonas_k)


Lesenswert?

Tobias Plüss schrieb:
> a) wie komme ich jetzt mit Hilfe dieser Backus Naur Form auf ein
> C-Programm?
> eigentlich brauche ich hierzu Lex doch gar nicht, oder? Ich meine, man
> müsste eine Zerlegung in Tokens schon anhand der Backus-Datei vornehmen
> können, wozu braucht man dann Lex?
Der Scanner geht die Eingabedatei halt Wort für Wort (Token für Token) 
durch und gibt die gefundenen Token an den Parser. Ist eigtl nicht 
besonders aufwendig und kann man natürlich auch leicht selbst machen, 
wie oben schon gesagt.

> b) jetzt noch fast die wichtigere Frage:
> Zwar erhalte ich beispielsweise mit Lex ein lauffähiges Programm,
> welches verschiedene Tokens unterscheiden kann. Dann kann man
> beispielsweise in der Konsole einen Text eingeben, und das Programm
> zerlegt den dan. Ansich eine ganz nette Spielerei, aber wenn ich z.B.
> eine INI-Datei parsen möchte (als triviales Beispiel) dann nützt mir das
> von Lex generierte Programm wenig. Wie baue ich also etwas, was ich mit
> Lex generiert habe, in mein bestehendes C-Programm ein? und noch
> wichtiger: Der generierte Quelltext ist total aufgeblasen und nahezu
> unlesbar, ist das wirklich dafür gedacht, 1:1 so verwendet zu werden?
Du brauchst natürlich die zweite Komponente - z. B. yacc - auch noch. 
Erst dann werden die Token in einen wie auch immer gearteten 
Zusammenhang gesetzt und interpretiert, indem z.B. eine einstprechende 
Baumstruktur erstellt wird.

Am besten du postet mal konkreten Code, sonst ist das alles sehr 
schwammig. Von Punkt b) her zu urteilen, vermute ich, dass du irgendwas 
falsch machst ;)

von Fred (Gast)


Lesenswert?

Tobias Plüss schrieb:
> eigentlich brauche ich hierzu Lex doch gar nicht, oder? Ich meine, man
> müsste eine Zerlegung in Tokens schon anhand der Backus-Datei vornehmen
> können, wozu braucht man dann Lex?

Ja, kann man. Dann wird die Grammatik aber relativ groß und 
undurchsichtig.

Das ist der weniger wichtige Grund, warum man lex getrennt verwendet.

Der wichtigere ist, daß die Grammatik, die yacc erkennt, kontextfrei 
ist.

Das ist viel zu mächtig für die reine Tokenerkennung, da kann lex 
deutlich effizienter zu Werke gehen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Tobias Plüss schrieb:
> wie komme ich jetzt mit Hilfe dieser Backus Naur Form auf ein
> C-Programm?

Eigentlich ist der Yacc-Quellcode erstmal (auf der linken Seite) eine
recht reine BNF.

Diese allein kann man natürlich vom Yacc parsen lassen, aber dann
bekommst du (als Rückgabewert von yyparse()) letztlich nur heraus,
ob das Dokument auf deine Grammatik gepasst hat oder nicht.

Daher willst du normalerweise anschließend beim Erkennen der einzelnen
syntaktischen Konstrukte auch irgendwas ausführen lassen.  Das ist das,
was rechts neben der BNF in geschweiften Klammern steht.  Compiler
bauen sich dann einen Syntaxbaum auf, für den Anfang kann man auch
einfach erstmal ein paar printf()s da hinsetzen.

Und nein, den generierten Code muss man nicht mehr lesen können.  Das
ist ein Compiler Compiler (naja, daher kommt zumindest der Name :),
und auch den (Assembler-)Code, den dein C-Compiler so generiert, musst
du nicht unbedingt lesen können.

Die Quelldatei ist die .y-Datei, nur an dieser wird herum geändert.

von Jonas K. (jonas_k)


Lesenswert?

Ich glaub, ihr habt seinen Post nicht genau gelesen. Ihr redet alle von 
yacc, der TO nimmt aber (bisher) nur lex her, hat er zumindest 
geschrieben.

> Zwar erhalte ich beispielsweise mit Lex ein lauffähiges Programm,
Er meint auch, dass er mit lex ein fertiges Programm erhält. Entweder er 
hat das Zusammenspiel Scanner/Parser nicht verstanden und nimmt nur 
einen Scanner her, oder er hat sich nur falsch ausgedrückt....

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Jonas K. schrieb:
> der TO nimmt aber (bisher) nur lex her, hat er zumindest geschrieben.

Hat aber in der Überschrift auch den Yacc drin.

Erst damit setzt man dann die BNF um.

Über Sinn und Unsinn der Trennung von Scanner und Parser hatten ja 
andere
bereits philosophiert.

von (prx) A. K. (prx)


Lesenswert?

Tobias Plüss schrieb:
> ich möchte mich mal mit dem Thema Lex/Yacc befassen.

Wie wärs mit flex/bison?

> Gestern habe ich mir mal Lex ein wenig angeschaut. Eigentlich keine
> riesen Hexerei. Aber Lex allein taugt im Prinzip nicht viel, oder?

Kommt drauf an wofür. Als Tokenizer taugt er. Der ist aber meist nur ein 
Teil einer Lösung.

> Der generierte Quelltext ist total aufgeblasen und nahezu
> unlesbar,

Das ist bei automatisch generiertem Quellcode normal. Erst recht bei 
tabellenbasiertem Code.

>  ist das wirklich dafür gedacht, 1:1 so verwendet zu werden?

Ja. Der ist definitiv nicht dafür gedacht, ihn zu verstehen oder gar 
drin rumzuschreiben.

von Sven (Gast)


Lesenswert?

Wenn dich ein ähnlicher Parser für C++ aber ohne Zwischencode 
interessiert, kannst du einen Blick auf http://boost-spirit.com werfen.

von Tobias P. (hubertus)


Lesenswert?

Hallo allerseits!

danke schon mal für die vielen Infos :-)

Zum generierten Code kann ich nur folgendes sagen. Irgendwie muss ich 
den ja in ein bestehendes Programm integrieren können. Also wie gehe ich 
dann da vor? wenn mir Lex (oder meinetwegen auch Yacc) da schon eine 
main()-Funktion rein baut, dann kann ich das so ja nicht verwenden. Also 
muss ich dann ja noch dauernd an dem generierten Code rum ändern .... 
:-/

Den "Workflow" stelle ich mir so vor:
entweder man benutzt Lex und bekommt dann die Tokens. Was meines 
Erachtens nicht extrem nützlich ist.
Oder aber man benutzt Yacc. Dann muss man sich eine BNF Datei 
erstellen und hat dann einen Parser für dieses Format.
Jedenfalls wenn ich Lex auf meinen Rechner laufen lasse, bekomme ich da 
nichts raus, was ich an Yacc weiter verfüttern könnte, sondern es kommt 
C-Code raus.

Ein Beispiels suche ich heute Abend hervor, habe jetzt grade hier keines 
zur Hand.

Gruss!

von Innensechskant (Gast)


Lesenswert?

>Irgendwie muss ich
>den ja in ein bestehendes Programm integrieren können. Also wie gehe ich
>dann da vor? wenn mir Lex (oder meinetwegen auch Yacc) da schon eine
>main()-Funktion rein baut, dann kann ich das so ja nicht verwenden. Also
>muss ich dann ja noch dauernd an dem generierten Code rum ändern ....

Nun lies Dir doch ersteinmal die Dokumentation dazu in Ruhe durch und 
erzeuge mal lexer und yacc für eine kleine Beispielgrammatik.
Das macht doch keinen Sinn, Dir hier das zu erklären, was ohnehin in der 
Dokumentation steht.

von Karl H. (kbuchegg)


Lesenswert?

Tobias Plüss schrieb:
> Hallo allerseits!
>
> danke schon mal für die vielen Infos :-)
>
> Zum generierten Code kann ich nur folgendes sagen. Irgendwie muss ich
> den ja in ein bestehendes Programm integrieren können.

Ja.
Da gibt es eine Funktion und die rufst du auf.
In einem Beispielcode wirst du sicherlich fündig.


> dann da vor? wenn mir Lex (oder meinetwegen auch Yacc) da schon eine
> main()-Funktion rein baut, dann kann ich das so ja nicht verwenden.


Schau die mal die Yacc Doku an.
http://pubs.opengroup.org/onlinepubs/7908799/xcu/yacc.html

Such nach main() in der Doku. Die erklärt dir, wie sich die Sache 
wirklich verhält.

von Karl H. (kbuchegg)


Lesenswert?

> entweder man benutzt Lex und bekommt dann die Tokens. Was
> meines Erachtens nicht extrem nützlich ist.
> Oder aber man benutzt Yacc.

Nicht 'entweder oder'.
Sondern 'und'.

Lex und Yacc arbeiten als Duo zusammen. Man kann sie einzeln benutzen. 
Muss aber nicht. Das volle Potential kann man mit beiden zusammen 
ausschöpfen.

Studier bitte die Doku und ein paar Beispiele dazu. Auf den ersten Blick 
sieht das alles etwas verwirrend aus. Es ist aber einfacher, als es 
zunächst aussieht.

von Karl H. (kbuchegg)


Lesenswert?


von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

A. K. schrieb:
>> ich möchte mich mal mit dem Thema Lex/Yacc befassen.
>
> Wie wärs mit flex/bison?

Lex taucht doch (wenn man nicht gerade ein Solaris benutzt) praktisch
immer in seiner Inkarnation als Flex auf.  (Mir ist zumindest kein
weiteres plug-kompatibles Opensource-Pendant bekannt.)

Bison ist wie viele GNU-Dinge, creeping featurism. ;-)  Letztlich aber
auch so einigermaßen eine Obermenge von Yacc.  Im Gegensatz zu lex gibt
es aber mit dem byacc noch eine einigermaßen schlanke
Opensource-Alternative.  flex und byacc habe ich sogar schon mal auf
den AVR portiert ;-) (wobei die wesentliche Änderung darin bestand, die
Tabellen im Flash aufzubauen und dort abzurufen).  So ab einem ATmega128
aufwärts ist das durchaus sogar benutzbar.  Das "Grundrauschen" ist
halt schon recht voluminös, aber ob wenn man Scanner und Parser dann
erweitert, bleiben sie trotzdem recht effektiv.

von Tobias P. (hubertus)


Lesenswert?

Hallo,

also ich habe mir mal noch das Video hier angeschaut:
http://www.youtube.com/watch?v=__-wUHG2rfM
es ist einigermassen aufschlussreich und das aller erste mal, wo ich 
sehe, dass Lex und Yacc tatsächlich zusammen benutzt werden.

Im Prinzip könnte man aber auch (wenn man wollte) Lex alleine benutzen 
und dann mittels einer FSM die erkannten Tokens durchgehen und mit 
yytext den Text jedes Tokens ermitteln, oder?


@Jörg
Also du hast einen mit flex und byacc generierten Parser auf dem AVR 
laufen? Hast du denn malloc() umgehen können? sind ein paar Aufrufe dazu 
drin. Leider.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Tobias Plüss schrieb:

> es ist einigermassen aufschlussreich und das aller erste mal, wo ich
> sehe, dass Lex und Yacc tatsächlich zusammen benutzt werden.

Ach nö, so ungewöhnlich ist diese Kombination nun nicht.  AVRDUDE
beispielsweise parst seine Konfigurationsdateien damit.

> Im Prinzip könnte man aber auch (wenn man wollte) Lex alleine benutzen
> und dann mittels einer FSM die erkannten Tokens durchgehen und mit
> yytext den Text jedes Tokens ermitteln, oder?

Eher geht man den umgekehrten Weg, einen Yacc- oder Bison-Parser,
aber einen handgefeilten Scanner.  Sowas macht beispielsweise der GCC.

> @Jörg
> Also du hast einen mit flex und byacc generierten Parser auf dem AVR
> laufen?

Ja.

> Hast du denn malloc() umgehen können? sind ein paar Aufrufe dazu
> drin. Leider.

"Ein Gespenst geht um in Micocontroller-Land, das Gespenst des
malloc()." :-)

Weißt du, das Ding hat so viel Grundrauschen, ich glaube so um die
10 oder 12 KiB an Code, warum soll man sich da um malloc() eine Rübe
machen?  Ich versteh' die Philosophie nicht, warum sich jeder lieber
einen riesigen statischen Speicherklotz ans Bein binden würde, um
dynamische Probleme damit zu lösen.  Hauptsache, kein malloc() …

Nein, da war natürlich ein malloc() drin.  Beispielanwendung war ein
(mehr oder minder gelungener) BASIC-Interpreter, der für seine
Programmzeilen sowieso dynamischen Speicher brauchte.  Das habe ich
aber alles auf einem ATmega128 mit externem SRAM damals probiert.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Jörg Wunsch schrieb:
> Eher geht man den umgekehrten Weg, einen Yacc- oder Bison-Parser,
> aber einen handgefeilten Scanner.  Sowas macht beispielsweise der GCC.

Beim GCC ist schon seit längerem auch der Parser handgefeilt.

von Innensechskant (Gast)


Lesenswert?

>Beim GCC ist schon seit längerem auch der Parser handgefeilt.

Warum hat man das eigentlich gemacht? Weiss das jemand? Warum ist ein 
yacc/bison parser nicht ausreichend resp. passend gewesen?

von Tobias P. (hubertus)


Lesenswert?

Hallo nochmals,

noch eine kurze Frage.
Ich habe jetzt genauso wie in dem Video mal einen Parser gemacht um eine 
INI Datei zu lesen. Der hat funktioniert. Jetzt versuche ich etwas 
komplizierteres:

mein zu parsender String enthält sowas:

filename=/home/tobias/test.txt;address=0xafff4b8c

wie zerlege ich das gescheit in Token? Ich dachte mir folgendes.

1. Token: filename (TOK_FILENAME)
2. Token: Gleich = (TOK_EQ)
3. Token: ?        (TOK_FULLPATH)
4. Token: Strichpunkt ; (TOK_SEMICOLON)
5. Token: wieder =
6. Token: 0x[0-9a-fA-F]{8} (TOK_HEX)

Für das Token Nr. 3 müsste ich ja dann einen Regex String finden, der 
auf einen Pfad passt, oder?

Und meine BNF für YACC lautet dann:

entry: TOK_FILENAME TOK_EQ TOK_FULLPATH TOK_SEMICOLON TOK_ADDR TOK_EQ 
TOK_HEX

ein mögliches Problem wäre dann allerdings, wenn der Pfad eine Hexzahl 
enthalten würde, also z.B. /home/tobias/ordner0x12345678/test.txt (ok, 
niemand benennt seine Ordner hexadezimal, aber könnte ja trotzdem 
vorkommen...)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Tobias Plüss schrieb:

> 1. Token: filename (TOK_FILENAME)
> 2. Token: Gleich = (TOK_EQ)
> 3. Token: ?        (TOK_FULLPATH)
> 4. Token: Strichpunkt ; (TOK_SEMICOLON)
> 5. Token: wieder =
> 6. Token: 0x[0-9a-fA-F]{8} (TOK_HEX)

Gleichheitszeichen und Semikolon würde ich nicht als separate Tokens
vereinbaren; vom lex nicht erkannte Dinge werden ohnehin zum Yacc
durchgereicht.
1
assign_stmt:
2
        LET VAR_INT '=' expr_int        { if (interprete) setivar($2, $4); }
3
        | VAR_INT '=' expr_int          { if (interprete) setivar($1, $3); }
4
        | LET VAR_REAL '=' expr_real    { if (interprete) setrvar($2, $4); }
5
        | VAR_REAL '=' expr_real        { if (interprete) setrvar($1, $3); }
6
        | LET VAR_STR '=' expr_str      { if (interprete) setstrvar($2, $4); }
7
        | VAR_STR '=' expr_str          { if (interprete) setstrvar($1, $3); }
8
        ;

> Für das Token Nr. 3 müsste ich ja dann einen Regex String finden, der
> auf einen Pfad passt, oder?

Ja, z. B.
1
[-/a-zA-Z0-9_.]+

Mal in der Annahme, dass du deine Dateinamen auf diese Zeichenmenge
begrenzen willst, damit die Grammatik auch eindeutig bleibt.

Ansonsten kannst du natürlich immer noch vorschreiben, dass ein
Dateiname in Anführungszeichen stehen muss.

> ein mögliches Problem wäre dann allerdings, wenn der Pfad eine Hexzahl
> enthalten würde, also z.B. /home/tobias/ordner0x12345678/test.txt

An sich nicht, weil ja nach dem Dateinamen grundsätzlich erstmal ein
Semikolon stehen muss.  Ein Dateiname, der mit 0x beginnt, würde
allerdings nicht passen, denn der würde als Hexzahl fehlinterpretiert
und damit an der Stelle eines Dateinamens nicht zulässig sein.  Ausweg:
Anführungszeichen um Dateinamen vorschreiben.  Außerdem geht natürlich
folgender schräger Hack:
1
 entry: TOK_FILENAME TOK_EQ TOK_FULLPATH TOK_SEMICOLON TOK_ADDR TOK_EQ TOK_HEX |
2
        TOK_FILENAME TOK_EQ TOK_HEX TOK_SEMICOLON TOK_ADDR TOK_EQ TOK_HEX
3
        ;

;-)

Wenn die zweite Alternative vorliegt, ist ja klar, dass der Dateiname
mit 0x beginnt. :)

: Bearbeitet durch Moderator
von Jonas K. (jonas_k)


Lesenswert?

Tobias Plüss schrieb:
> filename=/home/tobias/test.txt;address=0xafff4b8c
>
> 3. Token: ?        (TOK_FULLPATH)

Das ist doch kein Problem, wenn das erste Zeichen ein / sein muss und 
das Ende immer ein Semikolon ist. (lookahead)

Man könnte auch, um Problemen vorzubeugen, den Pfad in 
Anführungszeichen"" oder '' packen...

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Jörg Wunsch schrieb:

> und damit an der Stelle eines Dateinamens nicht zulässig sein.  Ausweg:
> Anführungszeichen um Dateinamen vorschreiben.

Oder zumindest eine 2.te Form eines Dateinamens ermöglichen, in der der 
Name in Anführungszeichen eingeschlossen werden kann (womit automatisch 
klar ist, dass ein " in einem Dateinamen nicht mehr zulässig ist). Das 
löst dann auch das leidige Problem mit einem Dateinamen
1
C:\Benutzer\Alle\Doumente und sonstiger Schwachsinn\Joke.txt
in dem die Leerzeichen zu allerhand Parse-Problemen führen.
Ein Dateinamen ist dann einfach eine Abfolge von Zeichen, die mit einem 
" beginnt und mit einem " endet (und sinnvollerweise wird man ein paar 
andere Sonder-Zeichen auch noch ausschliessen, so dass man weitgehend 
mit der Nicht-Anführungszeichen Version kompatibel ist). Wobei die " 
natürlich nicht zum eigentlichen Namen gehören.

: Bearbeitet durch User
von Tobias P. (hubertus)


Lesenswert?

Hallo zusammen,

so ich habe jetzt meine Dateinamen mit Anführungszeichen versehen. Und 
nun funktioniert mein Parser zuverlässig!
zunächst habe ich die Yaccdatei erstellt. Und meine Grammatik mit BNF 
definiert. Dabei habe ich herausgefunden, welche Zeichen ich als Token 
verwenden muss.

@Jörg Wunsch:
Was macht es für einen Unterschied, ob ich das Komma als Token nehme 
oder nicht?



Nach dem erstellen der Yaccdatei kannte ich meine zu verwendenden Token 
und habe diese in einer Lexdatei eingetragen.

Es scheint nun also, als würde mein Parser das gewünschte tun.

Allerdings möchte ich den jetzt in ein C++ Programm einbinden und anhand 
der gelesenen Daten jeweils eine Instanz einer Klasse erzeugen und in 
eine Liste eintragen. Kann ich denn das Yacc/Lex-Programm so einfach in 
ein anderes Projekt einbinden? Mit extern "C" wird es ja dann schwierig, 
eine Klasse zu erstellen... :-)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Tobias Plüss schrieb:

> Was macht es für einen Unterschied, ob ich das Komma als Token nehme
> oder nicht?

Mehr Schreibarbeit: du musst bereits im Scanner für jedes Zeichen ein
Token anlegen.  Ansonsten kannst du den Rest "durchfallen" lassen:
1
...
2
3
[ \t]           { /* ignore */ }
4
5
[\n]            { return '\n'; }
6
.               { return yytext[0]; }

Ich finde auch, dass sich
1
entry TOK_FILENAME '=' TOK_STRING ';' TOK_ADDR '=' TOK_HEX

etwas schneller lesen lässt als:
1
entry: TOK_FILENAME TOK_EQ TOK_FULLPATH TOK_SEMICOLON TOK_ADDR TOK_EQ TOK_HEX

> Kann ich denn das Yacc/Lex-Programm so einfach in
> ein anderes Projekt einbinden? Mit extern "C" wird es ja dann schwierig,
> eine Klasse zu erstellen... :-)

Meines Wissens haben Flex und Bison auch C++-Support.  Aber da musst
du mal Doku wälzen.

von Karl H. (kbuchegg)


Lesenswert?

Tobias Plüss schrieb:

> eine Liste eintragen. Kann ich denn das Yacc/Lex-Programm so einfach in
> ein anderes Projekt einbinden? Mit extern "C" wird es ja dann schwierig,
> eine Klasse zu erstellen... :-)

Ich habs selber noch nie gemacht.
Aber hier hab ich ein Beispielprojekt gefunden, der scheinbar den 
Lex/Yacc benutzt und die Brücke zurück zu C++ schafft.

http://www.telos.de/de/compiler/lex-yacc-und-c/

Würde ich mal studieren (makefile nicht vergessen), wie er das gemacht 
hat.

Auch die Anmerkungen hier
http://tldp.org/HOWTO/Lex-YACC-HOWTO-5.html
dürften nicht uninteressant sein.


Generell: Bei Fragen dieser Art kannst du davon ausgehen, dass du nicht 
der erste bist, der sowas probiert. Da gibt es also mit Sicherheit da 
draussen im Web jemanden, der schon lange vor dir diese Problemstellung 
hatte, sie gelöst hat und auch Willens war, den Lösungsweg in Form einer 
Web Seite bereit zu stellen.

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:

> Würde ich mal studieren (makefile nicht vergessen), wie er das gemacht
> hat.


Ah!
1
CFLAGS = -Wall
2
OBJFILES = easypars.o easyscan.o main.o global.o ast.o interpret.o
3
4
easy : $(OBJFILES)
5
  g++ -o easy $(OBJFILES)
6
easypars.cpp : easypars.yy global.h
7
  bison -t -d -o easypars.cpp easypars.yy
8
easyscan.cpp : easyscan.l
9
  flex -i easyscan.l
10
  mv lex.yy.c easyscan.cpp
11
12
global.o: global.cpp global.h
13
  g++ -c $(CFLAGS) -c  global.cpp
14
main.o: main.cpp global.h
15
  g++ -c $(CFLAGS) main.cpp
16
ast.o: ast.cpp ast.h
17
  g++ -c $(CFLAGS) ast.cpp
18
easyscan.o : easyscan.cpp global.h easypars.hpp 
19
  g++ -c $(CFLAGS) easyscan.cpp
20
easypars.o: easypars.cpp global.h
21
  g++ -c $(CFLAGS) easypars.cpp
22
clean:
23
  rm $(OBJFILES)
24
  rm easy.exe
25
  rm easypars.cpp easypars.hpp easyscan.cpp

Er behandelt einfach die Ergebnisse von bison und flex (yacc und lex) 
als wären sie cpp Files und jagt sie durch den C++ Compiler.

Ja, wenn das geht und der erzeugte Code soweit durch den C++ Compiler 
geht, dann kann man das natürlich machen und somit löst sich das Problem 
in Luft auf.

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.