EnglischFranzösischSpanisch

OnWorks-Favicon

freebsd-lex - Online in der Cloud

Führen Sie freebsd-lex im kostenlosen OnWorks-Hosting-Provider über Ubuntu Online, Fedora Online, Windows-Online-Emulator oder MAC OS-Online-Emulator aus

Dies ist der Befehl freebsd-lex, der im kostenlosen OnWorks-Hosting-Provider mit einer unserer zahlreichen kostenlosen Online-Workstations wie Ubuntu Online, Fedora Online, Windows-Online-Emulator oder MAC OS-Online-Emulator ausgeführt werden kann

PROGRAMM:

NAME/FUNKTION


flex, lex - schneller lexikalischer Analysegenerator

ZUSAMMENFASSUNG


biegen [-bcdfhilnpstvwBFILTV78+? -C[aefFmr] -Ausgabe -Ppräfix -Skelett] [--Hilfe --Ausführung]
[Dateiname ...]

Überblick


Dieses Handbuch beschreibt biegen, ein Werkzeug zum Generieren von Programmen, die Pattern-Matching durchführen
auf Text. Das Handbuch enthält sowohl Tutorial- als auch Referenzabschnitte:

Beschreibung
ein kurzer Überblick über das Tool

Einige einfache Beispiele

Format der Eingabedatei

Patterns
die von flex verwendeten erweiterten regulären Ausdrücke

Wie die Eingabe abgeglichen wird
die Regeln für die Bestimmung, was abgeglichen wurde

Aktionen
So legen Sie fest, was zu tun ist, wenn ein Muster übereinstimmt

Der generierte Scanner
Details zum Scanner, den Flex produziert;
So steuern Sie die Eingangsquelle

Startbedingungen
Einfügen von Kontext in Ihre Scanner und
Verwaltung von "Mini-Scannern"

Mehrere Eingabepuffer
wie man mehrere Eingangsquellen manipuliert; wie man
Scannen von Zeichenfolgen statt von Dateien

Ende-der-Datei-Regeln
spezielle Regeln für das Abgleichen des Endes der Eingabe

Verschiedene Makros
eine Zusammenfassung der Makros, die für die Aktionen verfügbar sind

Für den Benutzer verfügbare Werte
eine Zusammenfassung der für die Aktionen verfügbaren Werte

Schnittstelle zu Yacc
Verbinden von Flex-Scannern mit Yacc-Parsern

Optionen
flex-Befehlszeilenoptionen und die "%option"
Richtlinien

Leistungsüberlegungen
wie Sie Ihren Scanner so schnell wie möglich machen

Generieren von C++-Scannern
die (experimentelle) Möglichkeit zur Generierung von C++
Scannerklassen

Inkompatibilitäten mit Lex und POSIX
wie sich flex von AT&T lex und dem POSIX lex unterscheidet
Standard

Diagnose
Diese Fehlermeldungen, die von Flex (oder Scannern
es erzeugt), deren Bedeutungen möglicherweise nicht offensichtlich sind

Mappen
von flex verwendete Dateien

Mängel / Bugs
bekannte Probleme mit Flex

Siehe auch
andere Dokumentation, zugehörige Tools

Autor
enthält Kontaktinformationen

BESCHREIBUNG


biegen ist ein Werkzeug zum Generieren Scanner: Programme, die lexikalische Muster in Texten erkennen.
biegen liest die angegebenen Eingabedateien oder ihre Standardeingabe, wenn keine Dateinamen angegeben sind, für a
Beschreibung eines zu generierenden Scanners. Die Beschreibung erfolgt in Form von Paaren von regulären
Ausdrücke und C-Code, genannt Regeln. biegen erzeugt als Ausgabe eine C-Quelldatei, lex.yy.c,
was eine Routine definiert yylex(). Diese Datei wird kompiliert und mit dem -NS Bibliothek zu
eine ausführbare Datei erstellen. Wenn die ausführbare Datei ausgeführt wird, analysiert sie ihre Eingabe auf Vorkommen
der regulären Ausdrücke. Immer wenn es einen findet, führt es den entsprechenden C-Code aus.

ETWAS Schlicht Beispiele:


Zuerst einige einfache Beispiele, um einen Eindruck davon zu bekommen, wie man verwendet biegen. Folgende biegen
input gibt einen Scanner an, der jedes Mal, wenn er auf die Zeichenfolge "Benutzername" trifft, ersetzt wird
es mit dem Login-Namen des Benutzers:

%%
Benutzername printf( "%s", getlogin() );

Standardmäßig ist jeder Text, der nicht mit a übereinstimmt biegen Scanner wird auf die Ausgabe kopiert, also das Netz
Der Effekt dieses Scanners besteht darin, seine Eingabedatei bei jedem Auftreten von in seine Ausgabe zu kopieren
"Benutzername" erweitert. In dieser Eingabe gibt es nur eine Regel. "Benutzername" ist der Anleitungen
und das "printf" ist das Maßnahmen. Das "%%" markiert den Anfang der Regeln.

Hier ist ein weiteres einfaches Beispiel:

%{
int Anzahl_Zeilen = 0, Anzahl_Zeichen = 0;
%}

%%
\n ++Anzahl_Zeilen; ++num_chars;
. ++Anzahl_Zeichen;

%%
Main()
{
ylex();
printf( "Anzahl Zeilen = %d, Anzahl Zeichen = %d\n",
Anzahl_Zeilen, Anzahl_Zeichen );
}

Dieser Scanner zählt die Anzahl der Zeichen und die Anzahl der Zeilen in seiner Eingabe (es
produziert keine andere Ausgabe als den Abschlussbericht über die Zählungen). Die erste Zeile erklärt
zwei Globals, "num_lines" und "num_chars", die beide von innen zugänglich sind yylex() und im
Main() nach dem zweiten "%%" deklarierte Routine. Es gibt zwei Regeln, eine, die übereinstimmt
ein Zeilenumbruch ("\n") und erhöht sowohl die Zeilenzahl als auch die Zeichenzahl, und eine, die
stimmt mit jedem anderen Zeichen als einem Zeilenumbruch überein (angezeigt durch den regulären Ausdruck ".").

Ein etwas komplizierteres Beispiel:

/* Scanner für eine Spielzeug-Pascal-ähnliche Sprache */

%{
/* brauche dies für den Aufruf von atof() unten */
#einschließen
%}

ZIFFER [0-9]
ID [az][a-z0-9]*

%%

{Ziffer}+ {
printf( "Eine ganze Zahl: %s (%d)\n", yytext,
atoi(yytext));
}

{DIGIT}+"."{DIGIT}* {
printf( "Ein Gleitkomma: %s (%g)\n", yytext,
atof(yytext));
}

wenn|dann|beginnen|ende|prozedur|funktion {
printf( "Ein Schlüsselwort: %s\n", yytext );
}

{ID} printf( "Ein Bezeichner: %s\n", yytext );

"+"|"-"|"*"|"/" printf( "Ein Operator: %s\n", yytext );

"{"[^}\n]*"}" /* fressen einzeilige Kommentare */

[ \t\n]+ /* Leerzeichen auffressen */

. printf( "Unerkanntes Zeichen: %s\n", yytext );

%%

main( argc, argv )
int argc;
Zeichen **argv;
{
++argv, --argc; /* Programmnamen überspringen */
if ( argc > 0 )
yyin = fopen( argv[0], "r" );
sonst
yyin = stdin;

ylex();
}

Dies ist der Anfang eines einfachen Scanners für eine Sprache wie Pascal. Es identifiziert
verschiedene Arten von Token und berichtet über das Gesehene.

Die Details dieses Beispiels werden in den folgenden Abschnitten erläutert.

FORMAT OF SPEISUNG FILE


Die biegen Die Eingabedatei besteht aus drei Abschnitten, die durch eine Zeile mit nur getrennt sind %% drin:

Definitionen
%%
Ohne eine erfahrene Medienplanung zur Festlegung von Regeln und Strategien beschleunigt der programmatische Medieneinkauf einfach die Rate der verschwenderischen Ausgaben.
%%
Benutzercode

Die Definitionen Abschnitt enthält Deklarationen von simple Name Definitionen zur Vereinfachung
Scannerspezifikation und Erklärungen von Anfang Bedingungen, die in a . erklärt werden
späterer Abschnitt.

Namensdefinitionen haben die Form:

Namensdefinition

Der "Name" ist ein Wort, das mit einem Buchstaben oder einem Unterstrich ('_') beginnt, gefolgt von einer Null oder
mehr Buchstaben, Ziffern, '_' oder '-' (Bindestrich). Die Definition beginnt am ersten
Zeichen ohne Leerzeichen, das dem Namen folgt und bis zum Ende der Zeile fortgesetzt wird. Die
Auf die Definition kann anschließend mit "{name}" verwiesen werden, das zu erweitert wird
"(Definition)". Zum Beispiel,

ZIFFER [0-9]
ID [az][a-z0-9]*

definiert "DIGIT" als regulären Ausdruck, der einer einzelnen Ziffer entspricht, und "ID" als a
regulärer Ausdruck, der einem Buchstaben gefolgt von null oder mehr Buchstaben oder Ziffern entspricht. EIN
nachträglicher Verweis auf

{DIGIT}+"."{DIGIT}*

ist identisch mit

([0-9])+"."([0-9])*

und stimmt mit einer oder mehreren Ziffern, gefolgt von einem '.' überein. gefolgt von null oder mehr Ziffern.

Die Ohne eine erfahrene Medienplanung zur Festlegung von Regeln und Strategien beschleunigt der programmatische Medieneinkauf einfach die Rate der verschwenderischen Ausgaben. Abschnitt der biegen input enthält eine Reihe von Regeln der Form:

Musteraktion

Dabei muss das Muster nicht eingerückt sein und die Aktion muss in derselben Zeile beginnen.

Siehe unten für eine weitere Beschreibung von Mustern und Aktionen.

Zum Schluss wird der Benutzercode-Abschnitt einfach kopiert nach lex.yy.c wörtlich. Es wird genutzt für
Begleitroutinen, die den Scanner aufrufen oder von ihm aufgerufen werden. Das Vorhandensein dieses Abschnitts
es ist optional; wenn es fehlt, das zweite %% in der Eingabedatei kann auch übersprungen werden.

In den Abschnitten Definitionen und Regeln können alle eingerückt Text oder Text eingeschlossen in %{ und %} is
wörtlich in die Ausgabe kopiert (wobei die %{} entfernt wurden). Die %{}s müssen nicht eingerückt erscheinen
auf Linien von selbst.

Im Regelabschnitt kann jeder eingerückte oder %{}-Text verwendet werden, der vor der ersten Regel erscheint
Variablen zu deklarieren, die lokal für die Scan-Routine sind und (nach den Deklarationen)
Code, der bei jedem Einstieg in die Scan-Routine ausgeführt werden soll. Andere eingerückt oder
%{} Text im Regelabschnitt wird immer noch in die Ausgabe kopiert, aber seine Bedeutung ist nicht richtig.
definiert und es kann durchaus zu Fehlern bei der Kompilierung kommen (diese Funktion ist vorhanden für POSIX
Einhaltung; siehe unten für andere solche Funktionen).

Im Abschnitt "Definitionen" (aber nicht im Abschnitt "Regeln") wird ein nicht eingerückter Kommentar (dh a
Zeile beginnend mit "/*") wird ebenfalls wörtlich bis zum nächsten "*/" in die Ausgabe kopiert.

PATTERNS


Die Muster in der Eingabe werden mit einem erweiterten Satz regulärer Ausdrücke geschrieben. Diese
sind:

x entspricht dem Zeichen 'x'
. ein beliebiges Zeichen (Byte) außer Newline
[xyz] eine "Zeichenklasse"; in diesem Fall das Muster
entspricht entweder einem 'x', einem 'y' oder einem 'z'
[abj-oZ] eine "Zeichenklasse" mit einem Bereich darin; Streichhölzer
ein 'a', ein 'b', jeder Buchstabe von 'j' bis 'o',
oder ein 'Z'
[^AZ] eine "negierte Zeichenklasse", dh ein beliebiges Zeichen
aber die in der klasse. In diesem Fall alle
Zeichen AUSSER ein Großbuchstabe.
[^AZ\n] ein beliebiges Zeichen AUSSER ein Großbuchstabe oder
ein Zeilenumbruch
r* null oder mehr r's, wobei r ein beliebiger regulärer Ausdruck ist
r+ ein oder mehrere r's
R? null oder eins r (d. h. "ein optionales r")
r{2,5} irgendwo von zwei bis fünf r's
r{2,} zwei oder mehr r's
r{4} genau 4 r's
{name} die Erweiterung der "Name"-Definition
(siehe oben)
"[xyz]\"foo"
die wörtliche Zeichenfolge: [xyz]"foo
\X wenn X ein 'a', 'b', 'f', 'n', 'r', 't' oder 'v' ist,
dann die ANSI-C-Interpretation von \x.
Andernfalls wird ein wörtliches 'X' (verwendet, um zu entkommen
Operatoren wie '*')
\0 ein NUL-Zeichen (ASCII-Code 0)
\123 das Zeichen mit dem Oktalwert 123
\x2a das Zeichen mit dem Hexadezimalwert 2a
(r) mit einem r übereinstimmen; Klammern werden zum Überschreiben verwendet
Vorrang (siehe unten)

rs der reguläre Ausdruck r gefolgt von dem
Reguläre Ausdrücke; genannt "Verkettung"

r|s entweder ein r oder ein s

r/s an r, aber nur, wenn darauf ein s folgt. Die
Text, der mit s übereinstimmt, wird bei der Bestimmung berücksichtigt
ob diese Regel die "längste Übereinstimmung" ist,
wird dann aber zum Eingang zurückgekehrt, bevor
die Aktion wird ausgeführt. Also nur die Aktion
sieht den von r passenden Text. Dieser Typ
des Musters wird als Trailing Context" bezeichnet.
(Es gibt einige Kombinationen von r/s, die sich biegen
kann nicht richtig übereinstimmen; siehe Hinweise im
Mängel / Bugs Abschnitt unten in Bezug auf
"gefährlicher Trailing-Kontext".)
^r an r, aber nur am Anfang einer Zeile (dh
wenn Sie gerade anfangen zu scannen, oder gleich nach a
Zeilenumbruch wurde gescannt).
r$ an r, aber nur am Ende einer Zeile (dh nur
vor einem Zeilenumbruch). Entspricht "r/\n".

Beachten Sie, dass der Begriff "Neuzeile" von flex genau ist
was auch immer der C-Compiler verwendet hat, um flex zu kompilieren
interpretiert '\n' als; insbesondere auf einigen DOS
Systeme müssen Sie entweder \r's im herausfiltern
Geben Sie selbst ein oder verwenden Sie explizit r/\r\n für "r$".

r an r, aber nur in Startbedingung s (siehe
unten zur Diskussion der Startbedingungen)
R
gleich, aber in jeder der Startbedingungen s1,
s2 oder s3
<*>r an r in jeder Startbedingung, sogar einer exklusiven.

< > ein Dateiende
< >
ein Dateiende bei Startbedingung s1 oder s2

Beachten Sie, dass innerhalb einer Zeichenklasse alle regulären Ausdrucksoperatoren ihre Sonderzeichen verlieren
Bedeutung außer Escape ('\') und den Zeichenklassenoperatoren '-', ']' und bei der
Anfang der Klasse, '^'.

Die oben aufgeführten regulären Ausdrücke sind nach Rangfolge gruppiert, von höchster
Vorrang oben zum niedrigsten unten. Diejenigen, die zusammen gruppiert sind, sind gleich
Vorrang. Zum Beispiel,

foo|bar*

ist die gleiche wie

(foo)|(ba(r*))

da der '*'-Operator eine höhere Priorität hat als die Verkettung und die Verkettung höher
als Wechsel ('|'). Dieses Muster passt daher entweder die Zeichenfolge "foo" or
String "ba", gefolgt von null oder mehr r's. Um "foo" oder null oder mehr "bar" abzugleichen, verwenden Sie:

foo|(Balken)*

und um null oder mehr "foo"'s-oder-"bar"'s abzugleichen:

(foo|bar)*

Neben Zeichen und Zeichenbereichen können Zeichenklassen auch
Zeichenklasse Ausdrücke. Dies sind Ausdrücke, die darin eingeschlossen sind [: und :] Trennzeichen
(die selbst zwischen den '[' und ']' der Zeichenklasse stehen müssen; andere
Elemente können auch innerhalb der Zeichenklasse vorkommen). Die gültigen Ausdrücke sind:

[:alnum:] [:alpha:] [:leer:]
[:Strg:] [:Ziffer:] [:Grafik:]
[:unten:] [:Druck:] [:Punkt:]
[:Leerzeichen:] [:obere:] [:xStelle:]

Diese Ausdrücke bezeichnen alle einen Satz von Zeichen, der dem entsprechenden . entspricht
Standard-C istXXX Funktion. Beispielsweise, [:alnum:] bezeichnet die Zeichen, für die
isalnum() gibt true zurück, dh alle alphabetischen oder numerischen Werte. Einige Systeme bieten kein
ist leer(), also flex definiert [:leer:] als Leerzeichen oder als Tab.

Die folgenden Zeichenklassen sind beispielsweise alle gleichwertig:

[[:alnum:]]
[[:alpha:][:ziffer:]]
[[:alpha:]0-9]
[a-zA-Z0-9]

Wenn bei Ihrem Scanner die Groß-/Kleinschreibung nicht beachtet wird (die -i Flagge), dann [:Oberer, höher:] und [:untere:] sind
entspricht [:Alpha:].

Einige Hinweise zu Mustern:

- Eine negierte Zeichenklasse wie das obige Beispiel "[^AZ]" werden wir Spiel a Neue Zeile
es sei denn, "\n" (oder eine äquivalente Escape-Sequenz) ist explizit eines der Zeichen
in der negierten Zeichenklasse vorhanden (zB "[^AZ\n]"). Das ist anders als wie viele
andere Tools für reguläre Ausdrücke behandeln negierte Zeichenklassen, aber leider
die Inkonsistenz ist historisch verwurzelt. Übereinstimmende Zeilenumbrüche bedeuten, dass a
Muster wie [^"]* können mit der gesamten Eingabe übereinstimmen, es sei denn, es gibt ein weiteres Anführungszeichen im
Eingang.

- Eine Regel kann höchstens eine Instanz eines abschließenden Kontexts haben (der '/'-Operator oder der
'$'-Operator). Die Startbedingung '^' und "< >" Muster können nur bei . auftreten
am Anfang eines Musters, und, sowie mit '/' und '$', nicht gruppierbar
in Klammern. Ein '^' das nicht am Anfang einer Regel steht oder ein '$'
was nicht am Ende einer Regel auftritt, verliert seine besonderen Eigenschaften und ist
wie ein normaler Charakter behandelt.

Folgendes ist illegal:

foo/bar$
foo Bar

Beachten Sie, dass der erste von diesen "foo/bar\n" geschrieben werden kann.

Folgendes führt dazu, dass '$' oder '^' als normales Zeichen behandelt werden:

foo|(bar$)
foo|^bar

Wenn ein "foo" oder ein Balken gefolgt von einem Zeilenumbruch gewünscht wird, könnte Folgendes sein:
verwendet (die spezielle Aktion '|' wird unten erklärt):

foo |
bar$ /* Aktion geht hier */

Ein ähnlicher Trick funktioniert, um ein Foo oder einen Balken am Anfang einer Zeile zu finden.

WIE SPEISUNG IS PASSEND


Wenn der generierte Scanner ausgeführt wird, analysiert er seine Eingabe und sucht nach Zeichenfolgen, die übereinstimmen
eines seiner Muster. Wenn mehr als eine Übereinstimmung gefunden wird, wird diejenige verwendet, die am meisten zutrifft
text (bei nachgestellten Kontextregeln umfasst dies die Länge des nachgestellten Teils, sogar
obwohl es dann an den Eingang zurückgegeben wird). Wenn es zwei oder mehr Übereinstimmungen der findet
gleiche Länge, die zuerst aufgeführte Regel in der biegen Eingabedatei gewählt.

Sobald die Übereinstimmung festgestellt wurde, wird der Text, der der Übereinstimmung entspricht (genannt die Zeichen) is
im globalen Zeichenzeiger verfügbar gemacht jaytext, und seine Länge im globalen
ganze Zahl Yyleng. Die Aktion entsprechend dem übereinstimmenden Muster wird dann ausgeführt (ein more
detaillierte Beschreibung der Aktionen folgt), und dann wird nach den restlichen Eingaben gesucht
ein anderes Spiel.

Wenn keine Übereinstimmung gefunden wird, wird die Standard regieren wird ausgeführt: das nächste Zeichen in der Eingabe
gilt als abgeglichen und in die Standardausgabe kopiert. Also die einfachste legale biegen
Eingabe ist:

%%

was einen Scanner generiert, der einfach seine Eingabe (ein Zeichen nach dem anderen) in seine . kopiert
Ausgabe.

Beachten Sie, dass jjtext kann auf zwei verschiedene Arten definiert werden: entweder als Zeichen Zeiger oder als
ein Zeichen Array. Sie können steuern, welche Definition biegen verwendet, indem Sie eines der
besondere Richtlinien %Zeiger or %Array im ersten Abschnitt (Definitionen) Ihres Flex
Eingang. Die Standardeinstellung ist %Zeiger, es sei denn, Sie verwenden die -l lex-Kompatibilitätsoption, in der
Häuser jjtext wird ein Array sein. Der Vorteil der Verwendung %Zeiger ist wesentlich schneller
Scannen und kein Pufferüberlauf beim Abgleichen sehr großer Token (es sei denn, Sie haben keine
dynamisches Gedächtnis). Der Nachteil ist, dass Sie in Ihren Handlungen eingeschränkt sind
ändern jjtext (siehe nächster Abschnitt) und Anrufe an die unput() Funktion zerstört die
aktuelle Inhalte von jaytext, was beim Umzug zu erheblichen Portierungs-Kopfschmerzen führen kann
zwischen verschiedenen lex Versionen.

Der Vorteil der %Array ist, dass Sie dann ändern können jjtext nach Herzenslust und
ruft an unput() nicht zerstören jjtext (siehe unten). Darüber hinaus vorhandene lex Programme
manchmal zugreifen jjtext extern mit Deklarationen der Form:
externes Zeichen yytext[];
Diese Definition ist falsch, wenn sie mit verwendet wird %Zeiger, aber richtig für %Array.

%Array definiert jjtext eine Reihe von sein YYLMAX Zeichen, die standardmäßig auf ein ziemlich
großer Wert. Sie können die Größe ändern, indem Sie einfach #define'ing YYLMAX auf einen anderen Wert in
der erste Abschnitt deines biegen Eingang. Wie oben erwähnt, mit %Zeiger yytext wächst
dynamisch, um große Token aufzunehmen. Während dies bedeutet, dass Ihr %Zeiger Scanner kann
Platz für sehr große Token (z. B. das Abgleichen ganzer Kommentarblöcke), bedenken Sie
dass der Scanner jedes Mal die Größe ändern muss jjtext Es muss auch das gesamte Token von erneut scannen
der Anfang, daher kann sich das Abgleichen solcher Token als langsam erweisen. jjtext tut es derzeit nicht
dynamisch wachsen, wenn ein Aufruf an unput() führt dazu, dass zu viel Text zurückgeschoben wird; stattdessen,
ein Laufzeitfehler resultiert.

Beachten Sie auch, dass Sie nicht verwenden können %Array mit C++-Scannerklassen (die c ++ Möglichkeit; siehe unten).

MASSNAHMEN


Jedes Muster in einer Regel hat eine entsprechende Aktion, die eine beliebige C-Anweisung sein kann.
Das Muster endet beim ersten Leerzeichen ohne Escapezeichen; der Rest der Zeile
ist seine Aktion. Wenn die Aktion leer ist, wird bei Übereinstimmung mit dem Muster das Eingabetoken
wird einfach verworfen. Hier zum Beispiel die Spezifikation für ein Programm, das löscht
alle Vorkommen von "zap me" aus seiner Eingabe:

%%
"Zapp mich"

(Es werden alle anderen Zeichen in der Eingabe in die Ausgabe kopiert, da sie abgeglichen werden
nach der Standardregel.)

Hier ist ein Programm, das mehrere Leerzeichen und Tabulatoren zu einem einzigen Leerzeichen komprimiert, und
wirft Leerzeichen am Ende einer Zeile weg:

%%
[ \t]+ putchar( ' ' );
[ \t]+$ /* dieses Token ignorieren */

Wenn die Aktion ein '{' enthält, erstreckt sich die Aktion, bis der Ausgleich '}' gefunden wird, und
die Aktion kann mehrere Zeilen überschreiten. biegen kennt C-Strings und Kommentare und wird es nicht sein
von darin enthaltenen geschweiften Klammern getäuscht, ermöglicht aber auch den Beginn von Aktionen %{ und wird
betrachte die Aktion als den gesamten Text bis zum nächsten %} (unabhängig von gewöhnlichen Zahnspangen
innerhalb der Aktion).

Eine Aktion, die nur aus einem vertikalen Strich ('|') besteht, bedeutet "wie die Aktion für die nächste"
Regel." Siehe unten für eine Illustration.

Aktionen können beliebigen C-Code enthalten, einschließlich Rückkehr Anweisungen, um einen Wert zurückzugeben an
wie auch immer die Routine heißt yylex(). Jedes Mal yylex() heißt es wird weiter verarbeitet
Token von dort, wo es zuletzt aufgehört hat, bis es entweder das Ende der Datei erreicht oder ausgeführt wird
eine Rückgabe.

Aktionen können frei geändert werden jjtext außer zum Verlängern (Hinzufügen von Zeichen zu seinem
end - diese überschreiben spätere Zeichen im Eingabestrom). Dies ist jedoch nicht
bei Verwendung anwenden %Array (siehe oben); In diesem Fall, jjtext kann in jeder frei geändert werden
Weise.

Aktionen können frei geändert werden Yyleng es sei denn, sie sollten dies nicht tun, wenn die Aktion auch umfasst
Verwendung von jjmehr() (siehe unten).

Es gibt eine Reihe von Sonderanweisungen, die in eine Aktion aufgenommen werden können:

- ECHO kopiert yytext in die Ausgabe des Scanners.

- START gefolgt vom Namen einer Startbedingung versetzt den Scanner in den
entsprechende Startbedingung (siehe unten).

- ABLEHNEN weist den Scanner an, mit der "zweitbesten" Regel fortzufahren, die zutrifft
die Eingabe (oder ein Präfix der Eingabe). Die Regel wird wie oben in beschrieben gewählt
"Wie die Eingabe abgeglichen wird", und jjtext und Yyleng passend einrichten. Es kann
entweder eine sein, die genauso viel Text wie die ursprünglich gewählte Regel hat, aber kam
später im biegen Eingabedatei oder eine, die weniger Text entsprach. Zum Beispiel die
Im Folgenden werden sowohl die Wörter in der Eingabe gezählt als auch die Routine special() aufgerufen.
immer wenn "frob" gesehen wird:

int Wortzahl = 0;
%%

frob spezial(); ABLEHNEN;
[^ \t\n]+ ++word_count;

Ohne das ABLEHNEN, alle "frob"'s in der Eingabe würden nicht als Wörter gezählt, da
der Scanner führt normalerweise nur eine Aktion pro Token aus. Mehrere Lehnt ab sind
erlaubt, wobei jeder die nächstbeste Wahl zur aktuell aktiven Regel findet. Zum
Wenn der folgende Scanner beispielsweise das Token "abcd" scannt, wird es schreiben
"abcdabcaba" zur Ausgabe:

%%
ein |
ab |
abc |
abcd ECHO; ABLEHNEN;
.|\n /* alle nicht übereinstimmenden Zeichen auffressen */

(Die ersten drei Regeln teilen sich die Aktion der vierten, da sie das spezielle '|'
Aktion.) ABLEHNEN ist ein besonders teures Feature in Bezug auf den Scanner
Leistung; wenn es verwendet wird in für der Aktionen des Scanners wird er verlangsamt alle of
die Übereinstimmung des Scanners. Außerdem, ABLEHNEN kann nicht mit verwendet werden -Vgl or -CF
Optionen (siehe unten).

Beachten Sie auch, dass im Gegensatz zu den anderen Sonderaktionen ABLEHNEN ist eine Ast; Code
unmittelbar danach in der Aktion wird nicht ausgeführt werden.

- jjmehr() teilt dem Scanner mit, dass bei der nächsten Übereinstimmung mit einer Regel der entsprechende
Token sollte sein angehängt auf den aktuellen Wert von jjtext anstatt es zu ersetzen.
Wenn beispielsweise die Eingabe "mega-kludge" gegeben ist, wird Folgendes geschrieben: "mega-mega-
kludge" zur Ausgabe:

%%
Mega-ECHO; yymore();
Flickschust ECHO;

Zuerst wird "mega-" abgeglichen und an die Ausgabe ausgegeben. Dann wird "kludge" gematcht, aber
das vorherige "Mega-" hängt noch anfangs rum jjtext so das ECHO
denn die "kludge"-Regel schreibt eigentlich "mega-kludge".

Zwei Hinweise zur Verwendung von yymore(). Erstens jjmehr() hängt vom Wert von ab Yyleng
die Größe des aktuellen Tokens korrekt widerspiegelt, also dürfen Sie nicht ändern Yyleng wenn du
benutzen yymore(). Zweitens, das Vorhandensein von jjmehr() in der Aktion des Scanners beinhaltet a
geringfügige Leistungseinbußen bei der Anpassungsgeschwindigkeit des Scanners.

- ohne (n) gibt alle bis auf den ersten zurück n Zeichen des aktuellen Tokens zurück zum
Eingabestream, wo sie erneut gescannt werden, wenn der Scanner nach dem nächsten sucht
Spiel. jjtext und Yyleng entsprechend angepasst werden (z. Yyleng wird jetzt sein
gleich n ). Auf die Eingabe "foobar" wird beispielsweise Folgendes geschrieben
"foobarbar":

%%
foobar ECHO; ohne(3);
[az]+ ECHO;

Ein Argument von 0 bis ohne bewirkt, dass die gesamte aktuelle Eingabezeichenfolge gescannt wird
wieder. Sofern Sie nicht geändert haben, wie der Scanner seine Eingaben anschließend verarbeitet
(unter Verwendung von START, B.), führt dies zu einer Endlosschleife.

Beachten Sie, dass ohne ist ein Makro und kann nur in der Flex-Eingabedatei verwendet werden, nicht von anderen
Quelldaten.

- unput (c) setzt den Charakter c zurück in den Eingabestream. Es wird das nächste sein
Zeichen gescannt. Die folgende Aktion nimmt den aktuellen Token und verursacht ihn
erneut zu scannen, in Klammern eingeschlossen.

{
int i;
/* yytext kopieren, weil unput() yytext verwirft */
char *yycopy = strdup(yytext);
unput( ')' );
für ( i = yyleng - 1; i >= 0; --i )
unput(yycopy[i]);
unput( '(');
kostenlos (yycopy);
}

Beachten Sie, dass da jedes unput() setzt das angegebene Zeichen zurück an den Anfang dauert ebenfalls 3 Jahre. Das erste Jahr ist das sog.
Eingabestrom, das Zurückschieben von Zeichenfolgen muss von hinten nach vorne erfolgen.

Ein wichtiges potenzielles Problem bei der Verwendung unput() ist das, wenn Sie verwenden? %Zeiger (Das
Standard), ein Anruf an unput() zerstört Die Inhalte von jaytext, beginnend mit ganz rechts
Zeichen und verschlingt bei jedem Anruf ein Zeichen nach links. Wenn Sie den Wert benötigen
von yytext, der nach einem Aufruf von erhalten bleibt unput() (wie im obigen Beispiel) müssen Sie entweder
Kopieren Sie es zuerst woanders oder bauen Sie Ihren Scanner mit %Array stattdessen (siehe Wie die Eingabe ist
abgestimmt).

Beachten Sie schließlich, dass Sie nicht zurücksetzen können EOF um zu versuchen, den Eingabestream mit an . zu markieren
Ende der Datei.

- input () liest das nächste Zeichen aus dem Eingabestrom. Zum Beispiel die folgenden
ist eine Möglichkeit, C-Kommentare aufzufressen:

%%
"/*" {
int c;

zum ( ; ; )
{
while ( (c = input()) != '*' &&
c != EOF )
; /* Kommentartext auffressen */

wenn ( c == '*' )
{
während ( (c = input()) == '*' )
;
wenn ( c == '/' )
brechen; /* das Ende gefunden */
}

wenn ( c == EOF )
{
error( "EOF im Kommentar");
break;
}
}
}

(Beachten Sie, dass wenn der Scanner mit C ++, dann input () wird stattdessen verwiesen
zu als yyeingabe(), um einen Namenskonflikt mit dem . zu vermeiden C + + Stream mit dem Namen
Eingang.)

- YY_FLUSH_BUFFER leert den internen Puffer des Scanners, damit das nächste Mal die
Wenn der Scanner versucht, einen Token abzugleichen, füllt er zuerst den Puffer mit . auf YY_INPUT
(siehe Der generierte Scanner unten). Diese Aktion ist ein Sonderfall der mehr
General yy_flush_buffer() Funktion, beschrieben weiter unten im Abschnitt Mehrfacheingabe
Puffer.

- yyterminate() kann anstelle einer return-Anweisung in einer Aktion verwendet werden. Es
beendet den Scanner und gibt eine 0 an den Anrufer des Scanners zurück, was "all ." anzeigt
fertig". Standardmäßig yyterminate() wird auch aufgerufen, wenn ein Dateiende
angetroffen. Es ist ein Makro und kann neu definiert werden.

ERZEUGT SCANNER


Die Ausgabe von biegen ist die Datei lex.yy.c, die die Scan-Routine enthält yylex(), a
Anzahl von Tabellen, die von ihm zum Abgleichen von Token verwendet werden, und eine Reihe von Hilfsroutinen und
Makros. Standardmäßig, yylex() wird wie folgt deklariert:

int ylex()
{
... verschiedene Definitionen und die Aktionen hier ...
}

(Wenn Ihre Umgebung Funktionsprototypen unterstützt, lautet sie "int yylex( void )".)
Diese Definition kann durch die Definition des Makros "YY_DECL" geändert werden. Du könntest zum Beispiel
benutzen:

#define YY_DECL float lexscan( a, b ) float a, b;

um der Scan-Routine den Namen zu geben Lexscan, einen Schwimmer zurückgeben und zwei Schwimmer nehmen als
Argumente. Beachten Sie, dass, wenn Sie der Scan-Routine Argumente mit einem K&R-Stil/Nicht-
Prototyp-Funktionsdeklaration müssen Sie die Definition mit einem Semikolon (;) beenden.

Wann auch immer yylex() aufgerufen wird, scannt es Token aus der globalen Eingabedatei jjin (welche
standardmäßig auf stdin). Es wird fortgesetzt, bis es entweder ein Dateiende erreicht (an welchem ​​Punkt
es gibt den Wert 0) zurück oder eine seiner Aktionen führt a . aus Rückkehr Aussage.

Wenn der Scanner ein Dateiende erreicht, sind nachfolgende Aufrufe undefiniert, es sei denn, entweder jjin
auf eine neue Eingabedatei zeigt (in diesem Fall wird das Scannen von dieser Datei aus fortgesetzt) ​​oder
yyrestart() wird genannt. yyrestart() nimmt ein Argument, a FILE * Zeiger (der sein kann)
null, wenn du eingerichtet hast YY_INPUT um von einer anderen Quelle zu scannen als yyin), und initialisiert
jjin zum Scannen aus dieser Datei. Im Wesentlichen gibt es keinen Unterschied zwischen just
zuweisen jjin in eine neue Eingabedatei oder mit yyrestart() um dies zu tun; Letzteres ist verfügbar
zur Kompatibilität mit früheren Versionen von biegen, und weil man damit schalten kann
Eingabedateien während des Scannens. Es kann auch verwendet werden, um den Strom wegzuwerfen
Eingabepuffer, indem Sie ihn mit einem Argument von aufrufen yyin; aber besser ist zu benutzen YY_FLUSH_BUFFER
(siehe oben). Beachten Sie, dass yyrestart() die nicht setze die Startbedingung zurück auf URSPRÜNGLICHE (sehen
Startbedingungen, unten).

If yylex() stoppt das Scannen aufgrund der Ausführung von a Rückkehr Aussage in einer der Aktionen, die
Dann kann der Scanner erneut aufgerufen werden und der Scanvorgang dort fortgesetzt, wo er aufgehört hat.

Standardmäßig (und aus Effizienzgründen) verwendet der Scanner Blocklesevorgänge statt
einfach getc() Aufrufe zum Lesen von Zeichen aus jjin. Die Art, wie es seinen Input erhält, kann
gesteuert werden durch die Definition der YY_INPUT Makro. Die Aufrufsequenz von YY_INPUT ist
"YY_INPUT(buf,result,max_size)". Seine Aktion besteht darin, bis zu maximale Größe Zeichen in der
Zeichenarray buf und Rückkehr in die ganzzahlige Variable Folge entweder die Anzahl der
gelesenen Zeichen oder die Konstante YY_NULL (0 auf Unix-Systemen), um EOF anzuzeigen. Der Standard
YY_INPUT liest vom globalen Dateizeiger "yyin".

Eine Beispieldefinition von YY_INPUT (im Definitionsabschnitt der Eingabedatei):

%{
#define YY_INPUT(buf,result,max_size) \
{\
int c = getchar(); \
Ergebnis = (c == EOF) ? YY_NULL : (buf[0] = c, 1); \
}
%}

Diese Definition ändert die Eingabeverarbeitung, um ein Zeichen nach dem anderen auszuführen.

Wenn der Scanner eine Dateiende-Anzeige von YY_INPUT empfängt, überprüft er die
yywrap() Funktion. Wenn yywrap() gibt false (null) zurück, dann wird angenommen, dass die Funktion
ist vorangegangen und eingerichtet jjin um auf eine andere Eingabedatei zu verweisen, und das Scannen wird fortgesetzt. Wenn
es gibt true (nicht null) zurück, dann beendet der Scanner und gibt 0 an seinen Aufrufer zurück. Notiz
dass in jedem Fall die Startbedingung unverändert bleibt; es tut nicht zurück zu ANFÄNGLICH.

Wenn Sie keine eigene Version von . bereitstellen yywrap(), dann musst du entweder verwenden %Möglichkeit
noyywrap (in diesem Fall verhält sich der Scanner so, als ob yywrap() 1) zurückgegeben, oder Sie müssen
verbinden mit -NS um die Standardversion der Routine abzurufen, die immer 1 zurückgibt.

Es stehen drei Routinen zum Scannen aus speicherinternen Puffern anstelle von Dateien zur Verfügung:
yy_scan_string(), yy_scan_bytes(), und yy_scan_buffer(). Siehe die Diskussion über sie unten
im Abschnitt Mehrere Eingabepuffer.

Der Scanner schreibt seine ECHO Ausgabe an die du global (default, stdout), was sein kann
vom Benutzer neu definiert, indem er einfach einem anderen zugewiesen wird FILE Zeiger.

Starte das Spiel BEDINGUNGEN


biegen bietet einen Mechanismus zum bedingten Aktivieren von Regeln. Jede Regel, deren Muster ist
mit vorangestelltem " " ist nur aktiv, wenn sich der Scanner im genannten Startzustand befindet
"SC". Zum Beispiel,

[^"]* { /* den String-Körper auffressen ... */
...
}

wird nur aktiv, wenn sich der Scanner im Startzustand "STRING" befindet, und

\. { /* Escape behandeln ... */
...
}

ist nur aktiv, wenn die aktuelle Startbedingung entweder "INITIAL", "STRING" oder . ist
"ZITIEREN".

Startbedingungen werden im Definitionsabschnitt (erster) der Eingabe mit . deklariert
nicht eingerückte Zeilen, die mit entweder beginnen %s or %x gefolgt von einer Namensliste. Das Vorherige
erklärt einschließlich Startbedingungen, letztere exklusiv Bedingungen starten. Ein Anfang
Bedingung wird aktiviert mit dem START Handlung. Bis zum nächsten START Aktion ausgeführt wird,
Regeln mit der angegebenen Startbedingung werden aktiv und Regeln mit anderen Startbedingungen
wird inaktiv sein. Wenn die Startbedingung ist inklusive, dann Regeln ohne Start
Bedingungen überhaupt werden auch aktiv sein. Wenn es ist exklusiv, dann einzige Regeln qualifiziert mit
die Startbedingung wird aktiv. Ein Regelwerk, das vom gleichen exklusiven Start abhängig ist
Bedingung beschreibt einen Scanner, der unabhängig von allen anderen Regeln in der biegen
Eingang. Aus diesem Grund machen exklusive Startbedingungen es einfach, "Mini-
Scanner", die Teile der Eingabe scannen, die sich syntaktisch vom Rest unterscheiden
(zB Kommentare).

Wenn der Unterschied zwischen inklusiven und exklusiven Startbedingungen noch ein wenig ist
vage, hier ist ein einfaches Beispiel, das die Verbindung zwischen den beiden veranschaulicht. Der Satz von
Regeln:

%s Beispiel
%%

foo do_something();

bar etwas_else();

entspricht

%x Beispiel
%%

foo do_something();

bar etwas_else();

Ohne das Qualifizierer, der Bar Muster im zweiten Beispiel wäre nicht
aktiv (d. h. konnte nicht übereinstimmen) im Startzustand Beispiel. Wenn wir nur benutzt haben
qualifizieren Bar, aber dann wäre es nur aktiv in Beispiel und nicht in ANFÄNGLICH, während
im ersten Beispiel ist es in beiden aktiv, weil im ersten Beispiel die Beispiel Anfang
Bedingung ist ein einschließlich (%S) Startbedingung.

Beachten Sie auch, dass der spezielle Startbedingungsspezifizierer <*> entspricht jeder Startbedingung.
Somit könnte das obige Beispiel auch geschrieben worden sein;

%x Beispiel
%%

foo do_something();

<*>bar etwas_else();

Die Standardregel (to ECHO jedes nicht übereinstimmende Zeichen) bleibt unter Startbedingungen aktiv. Es
ist äquivalent zu:

<*>.|\n ECHO;

START(0) kehrt in den ursprünglichen Zustand zurück, in dem nur die Regeln ohne Startbedingungen gelten
aktiv. Dieser Zustand kann auch als Startbedingung "INITIAL" bezeichnet werden, also
BEGINNEN (ANFANG) entspricht START(0). (Die Klammern um die Startbedingung
Name sind nicht erforderlich, gelten aber als guter Stil.)

START Aktionen können auch als eingerückter Code am Anfang des Regelabschnitts angegeben werden.
Folgendes führt beispielsweise dazu, dass der Scanner in die Startbedingung "SPECIAL" wechselt
sobald yylex() heißt und die globale Variable enter_special ist wahr:

int enter_special;

%x SPEZIAL
%%
if (enter_special)
BEGINNEN (SPEZIAL);

blablabla
...weitere Regeln folgen...

Um die Verwendung von Startbedingungen zu veranschaulichen, ist hier ein Scanner, der zwei verschiedene
Interpretationen einer Zeichenfolge wie "123.456". Standardmäßig wird es als drei Token behandelt,
die ganze Zahl "123", einen Punkt ('.') und die ganze Zahl "456". Aber wenn der String vorangestellt ist
weiter oben in der Zeile durch die Zeichenfolge "expect-floats" wird es als einzelnes Token behandelt, das
Gleitkommazahl 123.456:

%{
#einschließen
%}
%s erwarten

%%
erwarten-Floats BEGIN(erwarten);

[0-9]+"."[0-9]+ {
printf( "Float gefunden, = %f\n",
atof(yytext));
}
\n {
/* Das ist das Ende der Zeile, also
* wir brauchen eine weitere "Expect-Nummer"
* bevor wir mehr erkennen
* Zahlen
*/
BEGINNEN (ANFANG);
}

[0-9]+ {
printf( "eine ganze Zahl gefunden, = %d\n",
atoi(yytext));
}

"." printf( "einen Punkt gefunden\n" );

Hier ist ein Scanner, der C-Kommentare erkennt (und verwirft) und gleichzeitig eine Zählung von . aufrechterhält
die aktuelle Eingabezeile.

%x Kommentar
%%
int line_num = 1;

"/*" BEGIN(Kommentar);

[^*\n]* /* alles essen, was kein '*' ist */
"*"+[^*/\n]* /* fressen '*'s nicht gefolgt von '/'s */
\n ++line_num;
"*"+"/" BEGIN(INITIAL);

Dieser Scanner gibt sich Mühe, mit jeder Regel so viel Text wie möglich abzugleichen.
Wenn Sie versuchen, einen Hochgeschwindigkeitsscanner zu schreiben, versuchen Sie im Allgemeinen, so viel wie möglich in
jede Regel, da es ein großer Gewinn ist.

Beachten Sie, dass Startbedingungsnamen wirklich ganzzahlige Werte sind und als solche gespeichert werden können.
Das Obige könnte also wie folgt erweitert werden:

%x Kommentar foo
%%
int line_num = 1;
int Kommentar_Aufrufer;

"/*" {
comment_caller = INITIAL;
BEGIN (Kommentar);
}

...

"/*" {
comment_caller = foo;
BEGIN (Kommentar);
}

[^*\n]* /* alles essen, was kein '*' ist */
"*"+[^*/\n]* /* fressen '*'s nicht gefolgt von '/'s */
\n ++line_num;
"*"+"/" BEGIN(comment_caller);

Darüber hinaus können Sie mit dem ganzzahligen auf die aktuelle Startbedingung zugreifen YY_START
Makro. Zum Beispiel die obigen Zuordnungen zu Kommentar_Anrufer könnte stattdessen geschrieben werden

comment_caller = YY_START;

Flex bietet YYSTAT als Alias ​​für YY_START (da dies von AT&T verwendet wird Lex).

Beachten Sie, dass Startbedingungen keinen eigenen Namensraum haben; Die Namen von %s und %x deklarieren
auf die gleiche Weise wie bei #define.

Zum Schluss noch ein Beispiel dafür, wie man Strings im C-Stil in Anführungszeichen mit exklusivem Start abgleicht
Bedingungen, einschließlich erweiterter Escape-Sequenzen (aber nicht einschließlich der Prüfung auf einen String
das ist zu lang):

%x str

%%
char string_buf[MAX_STR_CONST];
char *string_buf_ptr;

\" string_buf_ptr = string_buf; BEGIN(str);

\" { /* Schlusszitat gesehen - fertig */
BEGINNEN (ANFANG);
*string_buf_ptr = '\0';
/* String-Konstanten-Token-Typ zurückgeben und
* Wert für Parser
*/
}

\n {
/* Fehler - nicht beendete String-Konstante */
/* Fehlermeldung generieren */
}

\\[0-7]{1,3} {
/* Oktale Escape-Sequenz */
int-Ergebnis;

(void) sscanf( yytext + 1, "%o", &result );

if ( Ergebnis > 0xff )
/* Fehler, Konstante ist außerhalb des zulässigen Bereichs */

*string_buf_ptr++ = Ergebnis;
}

\\[0-9]+ {
/* Fehler generieren - falsche Escape-Sequenz; etwas
* wie '\48' oder '\0777777'
*/
}

\\n *string_buf_ptr++ = '\n';
\\t *string_buf_ptr++ = '\t';
\\r *string_buf_ptr++ = '\r';
\\b *string_buf_ptr++ = '\b';
\\f *string_buf_ptr++ = '\f';

\\(.|\n) *string_buf_ptr++ = yytext[1];

[^\\\n\"]+ {
char *yptr = yytext;

während ( *yptr )
*string_buf_ptr++ = *yptr++;
}

Oftmals, wie in einigen der obigen Beispiele, schreiben Sie eine ganze Reihe von Regeln
allen gehen die gleiche(n) Startbedingung(en) voraus. Flex macht das etwas einfacher und sauberer
durch Einführung eines Begriffs der Startbedingung Umfang. Ein Startbedingungsumfang wird begonnen mit:

{

woher SCs ist eine Liste mit einer oder mehreren Startbedingungen. Innerhalb des Startbedingungsbereichs
jede Regel hat automatisch das Präfix darauf angewendet, bis a '}' was zu dem passt
Anfangs- '{'. Also zum Beispiel

{
"\\n" Rückgabe '\n';
"\\r" return '\r';
"\\f" return '\f';
"\\0" gibt '\0' zurück;
}

ist äquivalent zu:

"\\n" return '\n';
"\\r" return '\r';
"\\f" return '\f';
"\\0" gibt '\0' zurück;

Startbedingungsbereiche können verschachtelt sein.

Zur Manipulation von Stapeln von Startbedingungen stehen drei Routinen zur Verfügung:

ungültig yy_push_state(int neuer_zustand)
schiebt die aktuelle Startbedingung oben auf den Startbedingungsstapel und
wechselt zu neuer_zustand als hättest du gebraucht START neuer_zustand (Erinnere dich an diesen Anfang
Bedingungsnamen sind auch ganze Zahlen).

ungültig yy_pop_state()
öffnet die Spitze des Stapels und wechselt zu ihm über START.

int yy_top_state()
gibt die Spitze des Stapels zurück, ohne den Inhalt des Stapels zu ändern.

Der Startbedingungsstapel wächst dynamisch und hat daher keine eingebaute Größenbeschränkung. Wenn
Speicher ist erschöpft, Programmausführung bricht ab.

Um Startbedingungsstapel verwenden zu können, muss Ihr Scanner Folgendes enthalten: %Möglichkeit Stapel Richtlinie (siehe
Optionen unten).

MEHRERE SPEISUNG PUFFER


Einige Scanner (z. B. diejenigen, die "include"-Dateien unterstützen) erfordern das Lesen von mehreren
Eingangsströme. Wie biegen Scanner puffern viel, man kann nicht kontrollieren, wo
der nächste Eingang wird durch einfaches Schreiben von a . gelesen YY_INPUT die empfindlich auf die
Kontext scannen. YY_INPUT wird nur aufgerufen, wenn der Scanner das Ende seines Puffers erreicht hat,
was lange dauern kann, nachdem eine Anweisung gescannt wurde, z. B. ein "einschließen", das erfordert
Umschalten der Eingangsquelle.

Um solche Probleme zu lösen, biegen bietet einen Mechanismus zum Erstellen und Umschalten
zwischen mehreren Eingabepuffern. Ein Eingabepuffer wird erstellt mit:

YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )

was dauert ein FILE Zeiger und eine Größe und erstellt einen Puffer, der mit der angegebenen Datei verknüpft ist
und groß genug um zu halten Größe Zeichen (verwenden Sie im Zweifelsfall YY_BUF_SIZE für die Größe).
Es kehrt zurück YY_BUFFER_STATE handle, das dann an andere Routinen übergeben werden kann (siehe
unter). Die YY_BUFFER_STATE type ist ein Zeiger auf ein opakes struct yy_buffer_state
-Struktur, sodass Sie YY_BUFFER_STATE-Variablen sicher zu ((YY_BUFFER_STATE) 0)
wenn Sie möchten, und beziehen Sie sich auch auf die undurchsichtige Struktur, um Eingaben korrekt zu deklarieren
Puffer in anderen Quelldateien als denen Ihres Scanners. Notiere dass der FILE Zeiger in
der Anruf an yy_create_buffer wird nur als Wert von verwendet jjin gesehen von YY_INPUT; wenn du
neu definieren YY_INPUT also wird es nicht mehr verwendet Yyin, dann kannst du sicher eine Null passieren FILE Zeiger
zu yy_create_buffer. Sie wählen einen bestimmten Puffer zum Scannen aus, indem Sie Folgendes verwenden:

void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )

schaltet den Eingabepuffer des Scanners um, sodass nachfolgende Token von kommen neuer_puffer. Note
zur Abwicklung, Integrierung, Speicherung und yy_switch_to_buffer() kann von yywrap() verwendet werden, um die Dinge für die Fortsetzung einzurichten
Scannen, anstatt eine neue Datei zu öffnen und darauf zu zeigen jjin daran. Beachten Sie auch, dass das Umschalten
Eingangsquellen über entweder yy_switch_to_buffer() or yywrap() die nicht den Anfang ändern
Zustand.

void yy_delete_buffer( YY_BUFFER_STATE Puffer )

wird verwendet, um den einem Puffer zugeordneten Speicher zurückzugewinnen. ( puffern kann null sein, in dem
Falls die Routine nichts tut.) Sie können auch den aktuellen Inhalt eines Puffers löschen
Verwendung:

void yy_flush_buffer( YY_BUFFER_STATE Puffer )

Diese Funktion verwirft den Inhalt des Puffers, sodass der Scanner das nächste Mal versucht,
Wenn ein Token aus dem Puffer übereinstimmt, wird der Puffer zuerst mit neu gefüllt YY_INPUT.

yy_new_buffer() ist ein Alias ​​für yy_create_buffer(), zur Kompatibilität mit den
C++-Verwendung von neu und löschen zum Erstellen und Zerstören dynamischer Objekte.

Schließlich wird der YY_CURRENT_BUFFER Makro gibt a . zurück YY_BUFFER_STATE Umgang mit dem Strom
Puffer.

Hier ist ein Beispiel für die Verwendung dieser Funktionen zum Schreiben eines Scanners, der Folgendes erweitert:
Dateien (die < > Funktion wird unten besprochen):

/* der Zustand "incl" wird verwendet, um den Namen zu übernehmen
* einer Include-Datei
*/
%x inkl

%{
#define MAX_INCLUDE_DEPTH 10
YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
int include_stack_ptr = 0;
%}

%%
enthalten BEGIN (inkl.);

[az]+ ECHO;
[^az\n]*\n? ECHO;

[ \t]* /* iss das Leerzeichen */
[^ \t\n]+ { /* hat den Include-Dateinamen */
if ( include_stack_ptr >= MAX_INCLUDE_DEPTH )
{
fprintf( stderr, "Enthält zu tief verschachtelte Dateien");
Ausgang ( 1 );
}

include_stack[include_stack_ptr++] =
YY_CURRENT_BUFFER;

yyin = fopen( yytext, "r" );

wenn ( ! yyin )
Error( ... );

yy_switch_to_buffer(
yy_create_buffer( yyin, YY_BUF_SIZE ) );

BEGINNEN (ANFANG);
}

< > {
if ( --include_stack_ptr < 0 )
{
yyterminate();
}

sonst
{
yy_delete_buffer ( YY_CURRENT_BUFFER );
yy_switch_to_buffer(
include_stack[include_stack_ptr]);
}
}

Es stehen drei Routinen zum Einrichten von Eingabepuffern zum Scannen von speicherinternen Zeichenfolgen zur Verfügung
statt Dateien. Alle erstellen einen neuen Eingabepuffer zum Scannen des Strings, und
ein entsprechendes zurückgeben YY_BUFFER_STATE handle (den du mit löschen solltest
yy_delete_buffer() wenn man damit fertig ist). Sie wechseln auch mit . auf den neuen Puffer
yy_switch_to_buffer(), also der nächste Anruf bei yylex() beginnt mit dem Scannen der Zeichenfolge.

yy_scan_string(const verkohlen *str)
scannt einen NUL-terminierten String.

yy_scan_bytes(const verkohlen *Byte, int len)
scannt len Bytes (einschließlich möglicherweise NULs) beginnend bei Position Bytes.

Beachten Sie, dass diese beiden Funktionen ein erstellen und scannen Kopieren des Strings oder der Bytes. (Dies
kann wünschenswert sein, da yylex() ändert den Inhalt des durchsuchten Puffers.) Sie
kann die Kopie vermeiden, indem Sie Folgendes verwenden:

yy_scan_buffer(Zeichen *Base, yy_size_t Größe)
die den Puffer beginnend bei scannt Base, bestehend aus Größe Bytes, die
die letzten zwei Bytes davon sollen be YY_END_OF_BUFFER_CHAR (ASCII-NULL). Diese letzten beiden
Bytes werden nicht gescannt; Somit besteht das Scannen aus basis[0] bis Basis[Größe-2],
inklusive

Wenn Sie die Einrichtung nicht durchführen Base auf diese Weise (dh vergiss die letzten beiden
YY_END_OF_BUFFER_CHAR Byte), dann yy_scan_buffer() gibt stattdessen einen Null-Zeiger zurück
einen neuen Eingabepuffer zu erstellen.

Der Typ yy_size_t ist ein ganzzahliger Typ, in den Sie einen ganzzahligen Ausdruck umwandeln können
die Größe des Puffers widerspiegelt.

ENDE DER DATEI REGELN


Die Sonderregel "< >" kennzeichnet Aktionen, die ausgeführt werden sollen, wenn ein Dateiende
angetroffen und yywrap() gibt einen Wert ungleich Null zurück (dh zeigt keine weiteren zu verarbeitenden Dateien an).
Die Aktion muss mit einem von vier Dingen abgeschlossen werden:

- zuordnen jjin in eine neue Eingabedatei (in früheren Versionen von flex, nachdem die
Aufgabe musste man die Sonderaktion aufrufen YY_NEUE_DATEI; das ist nicht mehr
notwendig);

- Ausführen von a Rückkehr Stellungnahme;

- Ausführung des Specials yyterminate() Aktion;

- oder Umschalten auf einen neuen Puffer mit yy_switch_to_buffer() wie im Beispiel gezeigt
zu teilen.

< > Regeln dürfen nicht mit anderen Mustern verwendet werden; sie dürfen nur mit einer Liste qualifiziert werden
der Startbedingungen. Wenn ein unqualifiziertes < > Regel ist gegeben, sie gilt für alle Anfang
Bedingungen, die noch nicht < > Aktionen. Um ein < . anzugeben > Regel nur für
die anfängliche Startbedingung, verwenden

< >

Diese Regeln sind nützlich, um Dinge wie nicht geschlossene Kommentare abzufangen. Ein Beispiel:

%x Zitat
%%

...weitere Regeln für den Umgang mit Zitaten...

< > {
error( "unterminiertes Zitat");
yyterminate();
}
< > {
if ( *++Dateiliste )
yyin = fopen( *Dateiliste, "r" );
sonst
yyterminate();
}

SONSTIGES MAKROS


Das Makro YY_USER_ACTION kann definiert werden, um eine Aktion bereitzustellen, die immer ausgeführt wird
vor der Aktion der übereinstimmenden Regel. Zum Beispiel könnte es #define'd sein, eine Routine aufzurufen
um yytext in Kleinbuchstaben umzuwandeln. Wann YY_USER_ACTION aufgerufen wird, die Variable yy_act
gibt die Nummer der übereinstimmenden Regel an (Regeln werden mit 1 beginnend nummeriert). Angenommen, Sie
ein Profil erstellen möchten, wie oft jede Ihrer Regeln abgeglichen wird. Folgendes würde das tun
Trick:

#define YY_USER_ACTION ++ctr[yy_act]

woher ctr ist ein Array, das die Zählungen für die verschiedenen Regeln enthält. Beachten Sie, dass das Makro
YY_NUM_RULES gibt die Gesamtzahl der Regeln an (einschließlich der Standardregel, auch wenn Sie
-S), also eine richtige erklärung für ctr ist:

int ctr[YY_NUM_RULES];

Das Makro YY_USER_INIT kann definiert werden, um eine Aktion bereitzustellen, die immer zuvor ausgeführt wird
beim ersten Scan (und bevor die internen Initialisierungen des Scanners durchgeführt werden). Zum Beispiel,
es könnte verwendet werden, um eine Routine zum Einlesen einer Datentabelle oder zum Öffnen einer Protokolldatei aufzurufen.

Das Makro yy_set_interactive(ist_interaktiv) kann verwendet werden, um zu steuern, ob der Strom
Puffer wird berücksichtigt interaktiv. Ein interaktiver Puffer wird langsamer verarbeitet, aber
muss verwendet werden, wenn die Eingangsquelle des Scanners tatsächlich interaktiv ist, um Probleme zu vermeiden
warten, um Puffer zu füllen (siehe die Diskussion der -I Flagge unten). Ein Wert ungleich Null in
der Makroaufruf markiert den Puffer als interaktiv, ein Nullwert als nicht interaktiv.
Beachten Sie, dass die Verwendung dieses Makros überschreibt %Möglichkeit interaktive , %Möglichkeit immer-interaktiv or
%Möglichkeit nie interaktiv (siehe Optionen unten). yy_set_interactive() muss vorher aufgerufen werden
zu beginnen, den Puffer zu scannen, der als interaktiv betrachtet werden soll (oder nicht).

Das Makro yy_set_bol(at_bol) kann verwendet werden, um zu steuern, ob das Scannen des aktuellen Puffers
Kontext für die nächste Tokenübereinstimmung erfolgt wie am Anfang einer Zeile. Ein Nicht-Null
Makroargument macht Regeln verankert mit

Das Makro YY_AT_BOL() gibt true zurück, wenn das nächste aus dem aktuellen Puffer gescannte Token
'^'-Regeln aktiv haben, sonst false.

Im generierten Scanner werden alle Aktionen in einer großen Switch-Anweisung zusammengefasst und
getrennt mit YY_BREAK, die neu definiert werden können. Standardmäßig ist es einfach eine "Pause", um
Trennen Sie die Aktion jeder Regel von der folgenden Regel. Neudefinition YY_BREAK gestattet
Beispiel, C++-Benutzer #define YY_BREAK, um nichts zu tun (und dabei sehr darauf zu achten, dass alle
Regel endet mit "break" oder "return"!), um nicht unter unerreichbaren Aussagen zu leiden
Warnungen, bei denen die Aktion einer Regel mit "Zurück" endet, die YY_BREAK ist unzugänglich.

WERTE VERFÜGBAR TO USER


Dieser Abschnitt fasst die verschiedenen Werte zusammen, die dem Benutzer in den Regelaktionen zur Verfügung stehen.

- verkohlen *yytext enthält den Text des aktuellen Tokens. Es kann geändert werden, aber nicht
verlängert (Sie können keine Zeichen an das Ende anhängen).

Wenn die Sonderrichtlinie %Array erscheint im ersten Abschnitt des Scanners
Beschreibung, dann jjtext wird stattdessen deklariert verkohlen yytext[YYLMAX], woher YYLMAX ist eine
Makrodefinition, die Sie im ersten Abschnitt neu definieren können, wenn Sie dies nicht mögen
Standardwert (in der Regel 8 KB). Verwenden von %Array führt zu etwas langsameren Scannern,
aber der Wert von jjtext wird immun gegen Anrufe an input () und unput(), welche
möglicherweise seinen Wert zerstören, wenn jjtext ist ein Zeichenzeiger. Das Gegenteil von
%Array is %Zeiger, das ist die Standardeinstellung.

Sie können nicht verwenden %Array beim Generieren von C++-Scannerklassen (die -+ Flagge).

- int Yyleng enthält die Länge des aktuellen Tokens.

- FILE *yyin ist die Datei, die standardmäßig biegen liest aus. Es kann neu definiert werden, aber
dies ist nur sinnvoll, bevor das Scannen beginnt oder nachdem ein EOF durchgeführt wurde
angetroffen. Eine Änderung während des Scannens führt zu unerwarteten Ergebnissen
da biegen puffert seine Eingabe; verwenden yyrestart() stattdessen. Sobald das Scannen beendet ist
weil ein Dateiende erkannt wurde, können Sie zuweisen jjin an der neuen Eingabedatei und
Rufen Sie dann den Scanner erneut auf, um mit dem Scannen fortzufahren.

- ungültig yyneustart( FILE *neue Datei ) darf auf den Punkt gebracht werden jjin an der neuen Eingabedatei.
Die Umschaltung auf die neue Datei erfolgt sofort (jegliche zuvor zwischengespeicherte Eingabe ist
hat verloren). Beachten Sie, dass Anrufe yyrestart() mit jjin als Argument wirft also die
aktuellen Eingabepuffer und fährt mit dem Scannen derselben Eingabedatei fort.

- FILE *yyouout ist die Datei, zu der ECHO Aktionen gemacht werden. Es kann neu zugewiesen werden durch
der Benutzer.

- YY_CURRENT_BUFFER gibt a zurück YY_BUFFER_STATE Handle auf den aktuellen Puffer.

- YY_START gibt einen ganzzahligen Wert zurück, der der aktuellen Startbedingung entspricht.
Sie können diesen Wert anschließend mit . verwenden START um zu diesem Startzustand zurückzukehren.

SCHNITTSTELLE MIT YACC


Eine der Hauptanwendungen von biegen ist als Begleiter für die jacc Parser-Generator. jacc Parser
erwarten, eine Routine namens . aufzurufen yylex() um das nächste Eingabetoken zu finden. Die Routine ist
soll den Typ des nächsten Tokens zurückgeben sowie einen zugehörigen Wert in
die globale Yylval. So verwenden Sie biegen mit jacc, man spezifiziert die -d Option zu jacc anweisen
es, um die Datei zu generieren y.tab.h mit Definitionen aller %token erscheint in der
jacc Eingang. Diese Datei wird dann in die biegen Scanner. Wenn beispielsweise einer der
tokens ist "TOK_NUMBER", ein Teil des Scanners könnte so aussehen:

%{
#include "y.tab.h"
%}

%%

[0-9]+ yylval = atoi(yytext); TOK_NUMBER zurückgeben;

OPTIONAL


biegen hat folgende Optionen:

-B, --Sicherung
Generieren Sie Sicherungsinformationen zu lex.backup. Dies ist eine Liste der Scannerstatus
die eine Sicherung erfordern, und die Eingabezeichen, für die sie dies tun. Beim Hinzufügen
Regeln kann man Backup-Zustände entfernen. Wenn alle Backup-Zustände werden eliminiert
und -Vgl or -CF verwendet wird, läuft der generierte Scanner schneller (siehe -p Flagge).
Nur Benutzer, die jeden letzten Zyklus aus ihren Scannern herausquetschen möchten, müssen sich Sorgen machen
über diese Möglichkeit. (Siehe den Abschnitt über Leistungsüberlegungen unten.)

-c ist eine veraltete Option, die für die POSIX-Konformität enthalten ist.

-D, --debuggen
lässt den generierten Scanner einlaufen debuggen Modus. Immer wenn ein Muster erkannt wird
und die globale yy_flex_debug ungleich Null ist (was die Standardeinstellung ist), wird der Scanner
schreiben an stderr eine Zeile des Formulars:

--akzeptiere die Regel in Zeile 53 ("der übereinstimmende Text")

Die Zeilennummer bezieht sich auf die Position der Regel in der Datei, die den Scanner definiert
(dh die Datei, die flex zugeführt wurde). Meldungen werden auch generiert, wenn die
Scanner sichert, akzeptiert die Standardregel, erreicht das Ende seines Eingabepuffers (oder
trifft auf eine NUL; An dieser Stelle sehen die beiden bis auf den Scanner gleich aus
betroffen) oder erreicht ein Dateiende.

-F, --voll
spezifiziert schnell Scanner. Es wird keine Tabellenkomprimierung durchgeführt und stdio wird umgangen. Die
Ergebnis ist groß, aber schnell. Diese Option ist äquivalent zu -Vgl (siehe unten).

-H, --help
erzeugt eine "Hilfe"-Zusammenfassung von flex's Optionen zu stdout und geht dann aus. -? und
--help sind Synonyme für -H.

-ich, --case-insensitive
weist an biegen generieren Groß- und Kleinschreibung wird nicht berücksichtigt Scanner. Die Groß-/Kleinschreibung der angegebenen Buchstaben
in England, biegen Eingabemuster werden ignoriert und Token in der Eingabe werden abgeglichen
unabhängig vom Fall. Der übereinstimmende Text in jjtext werde den erhaltenen Koffer haben
(dh es wird nicht gefaltet).

- l, --lex-kompat
schaltet maximale Kompatibilität mit dem Original AT&T ein lex Implementierung. Notiz
dass dies nicht bedeutet voller Kompatibilität. Die Nutzung dieser Option kostet a
beträchtliche Leistung und kann nicht mit dem -+, -F, -F, -Vgl.,
or -CF Optionen. Einzelheiten zu den angebotenen Kompatibilitäten finden Sie im Abschnitt
"Inkompatibilitäten mit Lex und POSIX" unten. Diese Option ergibt auch den Namen
YY_FLEX_LEX_COMPAT im generierten Scanner #definiert werden.

-n ist eine weitere veraltete Option, die nur für die POSIX-Konformität enthalten ist.

-P, --perf-report
generiert einen Leistungsbericht an stderr. Der Bericht besteht aus Kommentaren
zu den Funktionen des biegen Eingabedatei, die einen ernsthaften Verlust von
Leistung des resultierenden Scanners. Wenn du die Flagge zweimal gibst, wirst du es auch
Kommentare zu Funktionen erhalten, die zu geringfügigen Leistungseinbußen führen.

Beachten Sie, dass die Verwendung von ABLEHNEN, %Möglichkeit yylineno, und variabler Trailing-Kontext (siehe
der Abschnitt „Mängel/Fehler“ unten) eine erhebliche Leistungseinbuße nach sich zieht;
Verwendung von yymore(), ^ Betreiber, und die -I Flagge bringen geringfügige Leistung mit sich
Strafen.

-S, --kein Standard
verursacht die Standard regieren (diese nicht übereinstimmende Scannereingabe wird an Standard) sein
unterdrückt. Wenn der Scanner eine Eingabe findet, die keiner seiner Regeln entspricht,
es bricht mit einem Fehler ab. Diese Option ist nützlich, um Löcher in einem Scanner zu finden
Regelsatz.

-T, --stdout
weist an biegen um den generierten Scanner auf die Standardausgabe zu schreiben, anstatt auf
lex.yy.c.

-in, - ausführlich
gibt das an biegen sollte schreiben an stderr eine Zusammenfassung der Statistiken über die
Scanner erzeugt. Die meisten Statistiken sind für Gelegenheitsspieler bedeutungslos biegen
Benutzer, aber die erste Zeile identifiziert die Version von biegen (wie berichtet von -V),
und in der nächsten Zeile die Flags, die beim Generieren des Scanners verwendet wurden, einschließlich derer, die
sind standardmäßig aktiviert.

-w, --nunwarn
unterdrückt Warnmeldungen.

-B, --Charge
weist an biegen generieren Portion Scanner, das Gegenteil von interaktive Scanner
Erzeugt durch -I (siehe unten). Im Allgemeinen verwenden Sie -B wenn Sie es sind sicher dass Ihr
Scanner wird nie interaktiv verwendet, und Sie möchten einen wenig mehr
Leistung daraus. Wenn Ihr Ziel stattdessen darin besteht, a . herauszupressen Menge mehr
Leistung, sollten Sie die -Vgl or -CF Optionen (siehe unten), die
anmachen -B sowieso automatisch.

-F, --schnell
gibt an, dass die schnell Scanner-Tabellendarstellung verwendet werden (und stdio
umgangen). Diese Darstellung ist ungefähr so ​​schnell wie die vollständige Tabellendarstellung
(-F), und für einige Mustersätze erheblich kleiner sein (und für andere,
größer). Wenn der Mustersatz sowohl "Schlüsselwörter" als auch ein Catch-All enthält,
"Bezeichner"-Regel, wie im Set:

"Fall" gibt TOK_CASE zurück;
"switch" return TOK_SWITCH;
...
"Standard" gibt TOK_DEFAULT zurück;
[az]+ TOK_ID zurückgeben;

Dann ist es besser, die vollständige Tabellendarstellung zu verwenden. Wenn nur die
"Identifier" -Regel ist vorhanden und Sie verwenden dann eine Hash-Tabelle oder ähnliches, um sie zu erkennen
die Schlüsselwörter, verwenden Sie besser -F.

Diese Option ist äquivalent zu -CFr (siehe unten). Es kann nicht verwendet werden mit -+.

-ICH, --interaktiv
weist an biegen eine erzeugen interaktive Scanner. Ein interaktiver Scanner ist einer
die nur nach vorne schaut, um zu entscheiden, welcher Token abgeglichen wurde, wenn dies unbedingt erforderlich ist.
Es stellt sich heraus, dass man immer ein zusätzliches Zeichen vorausschaut, auch wenn der Scanner hat
bereits genug Text gesehen, um den aktuellen Token zu disambiguieren, ist etwas schneller als
nur bei Bedarf nach vorne schauen. Aber Scanner, die immer nach vorne schauen, geben
schreckliche interaktive Leistung; Wenn ein Benutzer beispielsweise einen Zeilenumbruch eingibt, ist dies
nicht als Newline-Token erkannt, bis sie eintreten ein anderer Token, was oft bedeutet
eine weitere ganze Zeile eintippen.

Flex Scanner standardmäßig auf interaktive es sei denn, Sie verwenden die -Vgl or -CF Tisch-
Komprimierungsoptionen (siehe unten). Denn wenn Sie auf der Suche nach High-
Leistung sollten Sie eine dieser Optionen verwenden. biegen
geht davon aus, dass Sie lieber ein wenig Laufzeitleistung gegen intuitive eintauschen
interaktives Verhalten. Beachten Sie auch, dass Sie kann keine - -I in Verbindung mit -Vgl or
-CF. Daher wird diese Option nicht wirklich benötigt; es ist standardmäßig für alle aktiviert
Fälle, in denen es erlaubt ist.

Beachten Sie, dass wenn isatty () gibt false für die Scannereingabe zurück, flex wird auf . zurückgesetzt
Batch-Modus, auch wenn -I angegeben wurde. Um den interaktiven Modus zu erzwingen, egal was passiert,
- %Möglichkeit immer-interaktiv (siehe Optionen unten).

Sie können einen Scanner zwingen, nicht Seien Sie interaktiv, indem Sie verwenden -B (siehe oben).

-L, --keine Linie
weist an biegen nicht zu generieren #Leitung Richtlinien. Ohne diese Möglichkeit biegen Paprika
der generierte Scanner mit #line-Anweisungen, damit Fehlermeldungen in den Aktionen angezeigt werden
in Bezug auf das Original richtig positioniert sein biegen Eingabedatei (wenn die
Fehler sind auf Code in der Eingabedatei zurückzuführen) oder lex.yy.c (wenn die Fehler sind flex's
Fehler -- Sie sollten diese Art von Fehlern an die unten angegebene E-Mail-Adresse melden).

-T, --verfolgen
macht biegen einlaufen Spur Modus. Es werden viele Nachrichten an stderr
bezüglich der Form der Eingabe und der resultierenden nicht-deterministischen und
deterministische endliche Automaten. Diese Option wird hauptsächlich für die Wartung verwendet biegen.

-V, --Version
druckt die Versionsnummer an stdout und geht. --Version ist ein Synonym für -V.

-7, --7 Bit
weist an biegen einen 7-Bit-Scanner zu generieren, also einen, der nur
7-Bit-Zeichen in seiner Eingabe. Der Vorteil der Verwendung -7 ist das der Scanner
Tabellen können bis zu halb so groß sein wie die, die mit dem erstellt wurden -8 Option (siehe
unter). Der Nachteil ist, dass solche Scanner oft hängen bleiben oder abstürzen, wenn ihre Eingaben
enthält ein 8-Bit-Zeichen.

Beachten Sie jedoch, dass, sofern Sie Ihren Scanner nicht mit dem -Vgl or -CF Tabelle
Komprimierungsoptionen, Verwendung von -7 spart nur wenig Tabellenplatz und
machen Ihren Scanner erheblich weniger portabel. Flex's Standardverhalten ist zu
Generieren Sie einen 8-Bit-Scanner, es sei denn, Sie verwenden die -Vgl or -CF, in welchem ​​Fall biegen
generiert standardmäßig 7-Bit-Scanner, es sei denn, Ihre Site war immer so konfiguriert
8-Bit-Scanner generieren (wie es oft bei Websites außerhalb der USA der Fall ist). Du kannst
sagen Sie, ob flex einen 7-Bit- oder einen 8-Bit-Scanner generiert hat, indem Sie das Flag überprüfen
Zusammenfassung im -v Ausgabe wie oben beschrieben.

Beachten Sie, dass, wenn Sie verwenden -Vgl or -CFe (diese Tabellenkomprimierungsoptionen, aber auch mit
Äquivalenzklassen (siehe unten), flex generiert immer noch standardmäßig ein
8-Bit-Scanner, da bei diesen Komprimierungsoptionen normalerweise volle 8-Bit-Tabellen sind
nicht viel teurer als 7-Bit-Tabellen.

-8, --8 Bit
weist an biegen einen 8-Bit-Scanner erzeugen, dh einen, der 8-Bit erkennen kann
Zeichen. Dieses Flag wird nur für Scanner benötigt, die mit generiert wurden -Vgl or -CF, as
andernfalls generiert flex sowieso standardmäßig einen 8-Bit-Scanner.

Siehe die Diskussion von -7 oben für das Standardverhalten von Flex und die Kompromisse
zwischen 7-Bit- und 8-Bit-Scannern.

-+, --c++
gibt an, dass flex eine C++-Scannerklasse generieren soll. Siehe den Abschnitt über
Weitere Informationen zum Generieren von C++-Scannern finden Sie unten.

-C[aefFmr]
steuert den Grad der Tabellenkomprimierung und allgemeiner Kompromisse zwischen
kleine Scanner und schnelle Scanner.

-Ca, --ausrichten ("align") weist flex an, größere Tabellen im generierten . abzuwägen
Scanner für schnellere Leistung, da die Elemente der Tabellen besser sind
für Speicherzugriff und Berechnung ausgerichtet. Auf einigen RISC-Architekturen wird das Abrufen
und das Bearbeiten von Langwörtern ist effizienter als mit kleineren Einheiten wie
kurze Worte. Diese Option kann die Größe der von Ihrem Scanner verwendeten Tabellen verdoppeln.

-Ce, --ecs leitet biegen konstruieren Gleichwertigkeit Klassen dh Zeichensätze
die identische lexikalische Eigenschaften haben (zum Beispiel, wenn das einzige Vorkommen von
Ziffern in der biegen Eingabe ist in der Zeichenklasse "[0-9]" dann die Ziffern '0',
'1', ..., '9' werden alle in die gleiche Äquivalenzklasse eingeordnet). Äquivalenzklassen
führen normalerweise zu drastischen Reduzierungen der endgültigen Tabellen-/Objektdateigrößen (normalerweise a
Faktor von 2-5) und sind in Bezug auf die Leistung ziemlich billig (eine Array-Suche pro
Zeichen gescannt).

-Vgl gibt an, dass die voller Scannertabellen sollen generiert werden - biegen sollte nicht
Komprimieren Sie die Tabellen, indem Sie die Vorteile ähnlicher Übergangsfunktionen für nutzen
verschiedene Staaten.

-CF gibt an, dass die alternative schnelle Scannerdarstellung (oben beschrieben
unter dem -F Flagge) verwendet werden. Diese Option kann nicht verwendet werden mit -+.

-Cm, --meta-ecs leitet biegen konstruieren Meta-Äquivalenz Klassen das sind Sätze
von Äquivalenzklassen (oder Zeichen, wenn Äquivalenzklassen nicht verwendet werden)
die häufig zusammen verwendet werden. Meta-Äquivalenzklassen sind oft ein großer Gewinn, wenn
komprimierte Tabellen verwenden, aber sie haben eine mäßige Auswirkung auf die Leistung (ein oder zwei
"if"-Tests und eine Array-Suche pro gescanntem Zeichen).

-Cr, --lesen bewirkt, dass der generierte Scanner umgehen Verwendung der Standard-I/O-Bibliothek
(stdio) für die Eingabe. Anstatt anzurufen Fread() or getc(), Der Scanner verwendet die
lesen() Systemaufruf, was zu einem Leistungsgewinn führt, der von System zu System variiert
System, aber im Allgemeinen ist es wahrscheinlich vernachlässigbar, es sei denn, Sie verwenden auch -Vgl or -CF.
Die richtigen -Cr kann seltsames Verhalten verursachen, wenn Sie zum Beispiel aus lesen jjin Verwendung von
stdio bevor Sie den Scanner aufrufen (da der Scanner jeden Text übersieht
Ihre vorherigen Lesevorgänge sind im stdio-Eingabepuffer geblieben).

-Cr hat keine Auswirkung, wenn Sie definieren YY_INPUT (siehe Der generierte Scanner oben).

Ein einsamer -C gibt an, dass die Scannertabellen komprimiert werden sollen, aber auch nicht
Äquivalenzklassen oder Metaäquivalenzklassen verwendet werden.

Die Optionen -Vgl or -CF und -Cm macht zusammen keinen Sinn - es gibt keine Gelegenheit
für Meta-Äquivalenzklassen, wenn die Tabelle nicht komprimiert wird. Ansonsten der
Optionen können frei gemischt werden und sind kumulativ.

Die Standardeinstellung ist -Cem, was spezifiziert, dass biegen sollte Äquivalenz erzeugen
Klassen und Meta-Äquivalenzklassen. Diese Einstellung bietet den höchsten Grad an
Tabellenkomprimierung. Sie können schnellere Scanner auf Kosten von
größere Tabellen, wobei im Allgemeinen Folgendes zutrifft:

am langsamsten & am kleinsten
-Cem
-Cm
-Das
-C
-C{f,F}e
-C{f,F}
-C{f,F}a
schnellste & größte

Beachten Sie, dass Scanner mit den kleinsten Tabellen normalerweise generiert und kompiliert werden
am schnellsten, daher sollten Sie während der Entwicklung normalerweise den Standardwert verwenden, maximal
Kompression.

-Vgl ist bei Produktionsscannern oft ein guter Kompromiss zwischen Geschwindigkeit und Größe.

-Ausgabe, --outputfile=DATEI
weist flex an, den Scanner in die Datei zu schreiben Möglichkeiten für das Ausgangssignal: statt lex.yy.c. Wenn Sie
kombinieren -o an. Nach der Installation können Sie HEIC-Dateien mit der -t Option, dann wird der Scanner beschrieben stdout aber es ist #Leitung
Richtlinien (siehe die -L Option oben) beziehen Sie sich auf die Datei Ausgabe.

-Ppräfix, --prefix=ZEICHENFOLGE
ändert die Standardeinstellung yy Präfix verwendet von biegen für alle global sichtbaren Variablen und
Funktionsnamen sollen stattdessen sein Präfix. Zum Beispiel, -Pfoo ändert den Namen von jjtext
zu Fußex. Es ändert auch den Namen der Standardausgabedatei von lex.yy.c zu
lex.foo.c. Hier sind alle betroffenen Namen:

yy_create_buffer
yy_delete_buffer
yy_flex_debug
yy_init_buffer
yy_flush_buffer
yy_load_buffer_state
yy_switch_to_buffer
jjin
Yyleng
Yylex
yylineno
du
jrestart
jjtext
jawrap

(Wenn Sie einen C++-Scanner verwenden, dann nur jawrap und yyFlexLexer sind betroffen.)
Innerhalb Ihres Scanners selbst können Sie weiterhin auf die globalen Variablen und
Funktionen, die eine der beiden Versionen ihres Namens verwenden; aber äußerlich haben sie die
geänderten Namen.

Mit dieser Option können Sie ganz einfach mehrere miteinander verknüpfen biegen Programme in das gleiche
ausführbar. Beachten Sie jedoch, dass die Verwendung dieser Option auch umbenannt wird yywrap(), also du jetzt
sollen entweder Ihre eigene (entsprechend benannte) Version der Routine für Ihre
Scanner oder verwenden %Möglichkeit noyywickel, als Verknüpfung mit -NS bietet keinen mehr für
Sie standardmäßig.

-Skelett_Datei, --skel=DATEI
überschreibt die Standard-Skelett-Datei, aus der biegen baut seine Scanner.
Sie werden diese Option nie brauchen, es sei denn, Sie tun es biegen Wartung oder Entwicklung.

-X, --posix-kompat
maximale Kompatibilität mit POSIX lex.

--yylineno
Track-Linien-Zählung in yylineno.

--yyclass=NAME
Name der C++-Klasse.

--header-file=DATEI
Erstellen Sie zusätzlich zum Scanner eine C-Header-Datei.

--tables-file[=DATEI]
schreibt Tabellen in DATEI.

-Dmakro[=defn]
#define Makro-Defn (Standard-Defn ist '1').

-R, --wiedereintretend
einen reentranten C-Scanner generieren

--Bison-Brücke
Scanner für Bison Pure Parser.

--Bison-Standorte
enthalten yylloc-Unterstützung.

--stdinit
yyin/yyout auf stdin/stdout initialisieren.

--noansi-definitionen im alten Stil Funktion Definitionen.

--noansi-prototypen
leere Parameterliste in Prototypen.

--nounistd
nicht einschließen .

--keine Funktion
keine bestimmte FUNKTION generieren.

biegen bietet auch einen Mechanismus zur Steuerung von Optionen innerhalb der Scannerspezifikation
selbst und nicht über die flex-Befehlszeile. Dies geschieht durch die Aufnahme %Möglichkeit
Anweisungen im ersten Abschnitt der Scannerspezifikation. Sie können mehrere angeben
Optionen mit einem einzigen %Möglichkeit Direktive und mehrere Direktiven im ersten Abschnitt von
Ihre Flex-Eingabedatei.

Die meisten Optionen werden einfach als Namen angegeben, optional mit dem Wort "no" (mit no
dazwischenliegende Leerzeichen), um ihre Bedeutung zu negieren. Eine Zahl entspricht Flex-Flags oder
ihre Verneinung:

7bit -7 Option
8bit -8 Option
ausrichten -Ca-Option
Backup-Option -b
Batch -B-Option
c++ -+ Option

fallweise oder
Groß-/Kleinschreibung im Gegensatz zu -i (Standard)

Groß-/Kleinschreibung nicht beachten oder
caseless -i Option

Debug-Option -d
Standard Gegenteil von -s Option
ecs -Ce-Option
schnelle -F-Option
volle Option -f
interaktive -I-Option
lex-compat -l Option
meta-ecs -Cm-Option
perf-report Option -p
lesen -Cr-Option
stdout -t Option
ausführliche -v Option
warnen gegenüber der Option -w
(verwenden Sie "%option nowarn" für -w)

Array entspricht "%array"
Zeiger äquivalent zu "%pointer" (Standard)

Manche %Optionen Funktionen bereitstellen, die sonst nicht verfügbar sind:

immer-interaktiv
weist flex an, einen Scanner zu generieren, der immer seine Eingabe berücksichtigt
"interaktiv". Normalerweise ruft der Scanner bei jeder neuen Eingabedatei auf isatty () in eine
Versuchen Sie festzustellen, ob die Eingabequelle des Scanners interaktiv ist und somit
sollte Zeichen für Zeichen gelesen werden. Wenn diese Option verwendet wird, dann nein
ein solcher Anruf erfolgt.

Haupt- weist flex an, eine Vorgabe bereitzustellen Main() Programm für den Scanner, das einfach
Anrufe yylex(). Diese Option impliziert noyywrap (siehe unten).

nie interaktiv
weist flex an, einen Scanner zu generieren, der seine Eingabe nie als "interaktiv" betrachtet
(wieder kein Anruf an isatty()). Dies ist das Gegenteil von immer-interaktiv.

Stapel ermöglicht die Verwendung von Startbedingungsstapeln (siehe Startbedingungen oben).

stdinit
falls gesetzt (dh %Möglichkeit Standard) initialisiert jjin und du zu Standard und Standard,
anstelle der Standardeinstellung von Null. Einige vorhandene lex Programme hängen von diesem Verhalten ab,
obwohl es nicht mit ANSI C konform ist, was nicht erfordert Standard und
stdout Kompilierzeit konstant sein.

yylineno
leitet biegen um einen Scanner zu generieren, der die Nummer der aktuellen Zeile beibehält
aus seinem Eingang in der globalen Variablen lesen yylineno. Diese Option wird impliziert durch
%Möglichkeit lex-kompat.

jawrap wenn nicht gesetzt (dh %Möglichkeit noyywrap), lässt den Scanner nicht anrufen yywrap() am Ende-
of-Datei, sondern gehen Sie einfach davon aus, dass keine weiteren Dateien zu scannen sind (bis der Benutzer
Punkte jjin bei einer neuen Datei und Aufrufe yylex() nochmal).

biegen scannt Ihre Regelaktionen, um festzustellen, ob Sie die ABLEHNEN or jjmehr() Funktionen.
Die ablehnen und mehr Es stehen Optionen zur Verfügung, um die Entscheidung, ob Sie verwenden, zu überschreiben
die Optionen, entweder indem Sie sie einstellen (z. %Möglichkeit ablehnen) um anzuzeigen, dass die Funktion
tatsächlich verwendet werden, oder sie werden deaktiviert, um anzuzeigen, dass sie tatsächlich nicht verwendet werden (z. %Möglichkeit
nein mehr).

Drei Optionen akzeptieren durch Zeichenfolgen getrennte Werte, versetzt mit '=':

%option outfile="ABC"

entspricht -oABC, und

%optionspräfix="XYZ"

entspricht -PXYZ. Schließlich

%option yyclass="foo"

gilt nur beim Generieren eines C++-Scanners ( -+ Möglichkeit). Es informiert biegen das du hast
abgeleitet foo als Unterklasse von yyFlexLexer, so biegen wird Ihre Aktionen im Mitglied platzieren
Funktion foo::yylex() statt yyFlexLexer::yylex(). Es erzeugt auch a
yyFlexLexer::yylex() Memberfunktion, die einen Laufzeitfehler ausgibt (durch Aufrufen von
yyFlexLexer::LexerError()) wenn angerufen. Weitere Informationen finden Sie unter Generieren von C++-Scannern weiter unten
Informationen.

Für Fusselpuristen, die das Erscheinungsbild von
unnötige Routinen im generierten Scanner. Jedes der folgenden, falls nicht gesetzt (z. B.
%Möglichkeit noun ), führt dazu, dass die entsprechende Routine nicht im generierten
Scanner:

Eingabe, Eingabe
yy_push_state, yy_pop_state, yy_top_state
yy_scan_buffer, yy_scan_bytes, yy_scan_string

(obwohl yy_push_state() und Freunde werden sowieso nicht angezeigt, es sei denn, Sie verwenden %Möglichkeit Stapel).

LEISTUNG ÜBERLEGUNGEN


Das Hauptdesignziel von biegen ist, dass es Hochleistungsscanner generiert. Es ist gewesen
optimiert für den guten Umgang mit großen Regelwerken. Abgesehen von den Auswirkungen auf den Scanner
Geschwindigkeit der Tabellenkompression -C oben beschriebenen Optionen gibt es eine Reihe von
Optionen/Aktionen, die die Leistung beeinträchtigen. Dies sind, vom teuersten bis zum billigsten:

ABLEHNEN
%option yylineno
beliebiger nachgestellter Kontext

Mustersätze, die ein Backup erfordern
%Array
%option interaktiv
%option immer-interaktiv

'^' Zeilenanfangsoperator
jjmehr()

wobei die ersten drei alle recht teuer und die letzten beiden recht günstig sind. Notiz
auch dass unput() wird als Routineaufruf implementiert, der potenziell einiges anrichtet
arbeiten, während jalos() ist ein recht günstiges Makro; Also, wenn du nur etwas überschüssigen Text zurückgibst
gescannt, verwenden yylos().

ABLEHNEN sollte um jeden Preis vermieden werden, wenn Leistung wichtig ist. Es ist ein besonders
teure Variante.

Backups loszuwerden ist chaotisch und kann oft eine enorme Arbeit für einen sein
komplizierter Scanner. Im Prinzip beginnt man mit der Verwendung der -b Flag zum Generieren von a
lex.backup Datei. Zum Beispiel am Eingang

%%
foo gibt TOK_KEYWORD zurück;
foobar gibt TOK_KEYWORD zurück;

die Datei sieht so aus:

Zustand #6 wird nicht akzeptiert -
zugehörige Regelzeilennummern:
2 3
Aus-Übergänge: [ o ]
Jam-Übergänge: EOF [ \001-n p-\177 ]

Zustand #8 wird nicht akzeptiert -
zugehörige Regelzeilennummern:
3
Aus-Übergänge: [ a ]
Jam-Übergänge: EOF [ \001-` b-\177 ]

Zustand #9 wird nicht akzeptiert -
zugehörige Regelzeilennummern:
3
Aus-Übergänge: [ r ]
Jam-Übergänge: EOF [ \001-q s-\177 ]

Komprimierte Tabellen werden immer gesichert.

Die ersten paar Zeilen sagen uns, dass es einen Scannerstatus gibt, in dem er einen Übergang machen kann
auf einem 'o', aber auf keinem anderen Zeichen, und dass in diesem Zustand das aktuell gescannte
Text entspricht keiner Regel. Der Zustand tritt auf, wenn versucht wird, die unter gefundenen Regeln zu erfüllen
Zeilen 2 und 3 in der Eingabedatei. Wenn sich der Scanner in diesem Zustand befindet und dann etwas liest
anders als ein 'o', muss ein Backup erstellt werden, um eine übereinstimmende Regel zu finden. Mit ein bisschen
Kopfkratzen kann man sehen, dass dies der Zustand sein muss, in dem es sich befindet, wenn es "fo" gesehen hat.
Wenn dies passiert ist und etwas anderes als ein weiteres 'o' zu sehen ist, hat der Scanner
zu sichern, um einfach dem 'f' zu entsprechen (durch die Standardregel).

Der Kommentar zu State #8 weist darauf hin, dass ein Problem beim Scannen von "foob" vorliegt.
In der Tat muss der Scanner bei jedem anderen Zeichen als einem 'a' ein Backup durchführen, um es zu akzeptieren
"foo". Ebenso betrifft der Kommentar für State #9, wann "fooba" gescannt wurde und
'r' folgt nicht.

Der letzte Kommentar erinnert uns daran, dass es keinen Sinn macht, sich die Mühe des Entfernens zu machen
Sichern von den Regeln, es sei denn, wir verwenden -Vgl or -CF, da gibt es keinen leistungsgewinn
dies mit komprimierten Scannern.

Sie können die Sicherung entfernen, indem Sie "Fehler"-Regeln hinzufügen:

%%
foo gibt TOK_KEYWORD zurück;
foobar gibt TOK_KEYWORD zurück;

foba |
foob ​​|
NS {
/* Fehlalarm, nicht wirklich ein Schlüsselwort */
TOK_ID zurückgeben;
}

Das Eliminieren von Backups zwischen einer Liste von Keywords kann auch mit einer "Catch-All"-Regel erfolgen:

%%
foo gibt TOK_KEYWORD zurück;
foobar gibt TOK_KEYWORD zurück;

[az]+ TOK_ID zurückgeben;

Dies ist in der Regel die beste Lösung, wenn es angebracht ist.

Das Sichern von Nachrichten neigt dazu, zu kaskadieren. Bei einem komplizierten Regelwerk ist es nicht ungewöhnlich
Hunderte von Nachrichten erhalten. Wenn man sie aber entziffern kann, braucht es oft nur ein Dutzend
oder so Regeln, um das Backup zu eliminieren (obwohl es leicht ist, einen Fehler zu machen und ein
Fehlerregel stimmen versehentlich mit einem gültigen Token überein. Eine mögliche Zukunft biegen Funktion wird sein
automatisch Regeln hinzufügen, um Backups zu vermeiden).

Es ist wichtig zu bedenken, dass Sie die Vorteile der Eliminierung von Backups nur nutzen können
wenn du eliminierst alles, Instanz der Sicherung. Wenn Sie nur einen lassen, gewinnen Sie nichts.

Variable nachfolgender Kontext (wobei sowohl der führende als auch der nachfolgende Teil keinen festen
Länge) bringt fast den gleichen Leistungsverlust mit sich wie ABLEHNEN (dh erheblich). Also wann
möglich eine Regel wie:

%%
Maus|Ratte/(Katze|Hund) run();

ist besser geschrieben:

%%
Maus/Katze|Hundelauf();
Ratte/Katze|Hundelauf();

oder als

%%
Maus|Ratte/Katze laufen();
Maus|Ratte/Hundelauf();

Beachten Sie, dass hier das spezielle '|' Aktion tut nicht bieten keine Einsparungen und können sogar machen
Dinge noch schlimmer (siehe Mängel / Bugs unten).

Ein weiterer Bereich, in dem der Benutzer die Leistung eines Scanners steigern kann (und der einfacher zu handhaben ist)
implementieren) ergibt sich aus der Tatsache, dass je länger die übereinstimmenden Token, desto schneller der Scanner
werde rennen. Dies liegt daran, dass bei langen Token die Verarbeitung der meisten Eingabezeichen dauert
Platz in der (kurzen) inneren Abtastschleife und muss nicht oft durch die
zusätzliche Arbeit zum Einrichten der Scanumgebung (z. B. jjtext) für die Aktion.
Rufen Sie den Scanner für C-Kommentare zurück:

%x Kommentar
%%
int line_num = 1;

"/*" BEGIN(Kommentar);

[^*\n]*
"*"+[^*/\n]*
\n ++line_num;
"*"+"/" BEGIN(INITIAL);

Dies könnte beschleunigt werden, indem Sie es wie folgt schreiben:

%x Kommentar
%%
int line_num = 1;

"/*" BEGIN(Kommentar);

[^*\n]*
[^*\n]*\n ++line_num;
"*"+[^*/\n]*
"*"+[^*/\n]*\n ++line_num;
"*"+"/" BEGIN(INITIAL);

Anstatt nun, dass jeder Zeilenumbruch die Verarbeitung einer anderen Aktion erfordert, wird der
newlines wird über die anderen Regeln "verteilt", um den übereinstimmenden Text so lange beizubehalten
möglich. Beachten Sie, dass Hinzufügen Regeln nicht verlangsamen Sie den Scanner! Die Geschwindigkeit der
Scanner ist unabhängig von der Anzahl der Regeln oder (modulo der Betrachtungen bei der
Anfang dieses Abschnitts), wie kompliziert die Regeln in Bezug auf Operatoren sind wie
'*' und '|'.

Ein letztes Beispiel für die Beschleunigung eines Scanners: Angenommen, Sie möchten eine Datei durchsuchen
mit Bezeichnern und Schlüsselwörtern, eine pro Zeile und ohne andere überflüssige Zeichen,
und alle Schlüsselwörter erkennen. Ein natürlicher erster Ansatz ist:

%%
asm |
automatisch |
Pause |
... usw ...
flüchtig |
während /* es ein Schlüsselwort ist */

.|\n /* es ist kein Schlüsselwort */

Um das Back-Tracking zu eliminieren, führen Sie eine Auffangregel ein:

%%
asm |
automatisch |
Pause |
... usw ...
flüchtig |
während /* es ein Schlüsselwort ist */

[az]+ |
.|\n /* es ist kein Schlüsselwort */

Wenn jetzt garantiert ist, dass es genau ein Wort pro Zeile gibt, können wir die
Gesamtzahl der Übereinstimmungen um die Hälfte durch Zusammenführung der Erkennung von Zeilenumbrüchen mit der von
die anderen Token:

%%
asm\n |
automatisch\n |
Pause\n |
... usw ...
flüchtig\n |
während\n /* es ist ein Schlüsselwort */

[az]+\n |
.|\n /* es ist kein Schlüsselwort */

Hier muss man aufpassen, da wir jetzt das Sichern in den Scanner wieder eingeführt haben. In
insbesondere, während we wissen, dass es nie irgendwelche Zeichen im Eingabestream geben wird
andere als Buchstaben oder Zeilenumbrüche, biegen kann das nicht herausfinden, und es wird möglicherweise geplant
Sie müssen ein Backup erstellen, wenn ein Token wie "auto" gescannt wurde und dann das nächste Zeichen ist
etwas anderes als ein Zeilenumbruch oder ein Buchstabe. Früher würde es dann nur mit dem übereinstimmen
"auto"-Regel und fertig, aber jetzt hat es keine "auto"-Regel, nur eine "auto\n"-Regel. Zu
eliminieren Sie die Möglichkeit der Sicherung, wir könnten entweder alle Regeln duplizieren, aber ohne
letzte Zeilenumbrüche, oder, da wir nie erwarten, auf eine solche Eingabe zu stoßen und daher nicht
wie es klassifiziert wird, können wir eine weitere Auffangregel einführen, diese, die es nicht tut
einen Zeilenumbruch einfügen:

%%
asm\n |
automatisch\n |
Pause\n |
... usw ...
flüchtig\n |
während\n /* es ist ein Schlüsselwort */

[az]+\n |
[az]+ |
.|\n /* es ist kein Schlüsselwort */

Zusammengestellt mit -Vgl., das ist so schnell wie möglich a biegen Scanner, um dafür zu gehen
bestimmtes Problem.

Eine letzte Anmerkung: biegen ist beim Abgleichen von NULs langsam, insbesondere wenn ein Token enthält
mehrere NULs. Am besten schreibst du Regeln, die passen kurz Textmengen, wenn es
erwartet, dass der Text oft NULs enthält.

Noch eine letzte Anmerkung zur Leistung: wie oben im Abschnitt Wie die Eingabe
ist angepasst, dynamisch skaliert jjtext riesige Token unterzubringen ist ein langsamer Prozess
weil es derzeit erfordert, dass der (riesige) Token von Anfang an erneut gescannt wird. Daher
Wenn die Leistung entscheidend ist, sollten Sie versuchen, "große" Textmengen abzugleichen, aber nicht
"riesige" Mengen, wobei der Cutoff zwischen den beiden bei etwa 8K Zeichen/Token liegt.

ERSTELLEN C + + SCANNER


biegen bietet zwei verschiedene Möglichkeiten zum Generieren von Scannern für die Verwendung mit C++. Der erste Weg ist
um einfach einen Scanner zu kompilieren, der von . generiert wurde biegen Verwenden eines C++-Compilers anstelle von C
Compiler. Es sollten keine Kompilierungsfehler auftreten (bitte melden Sie alle, die Sie finden an
die im Abschnitt Autor unten angegebene E-Mail-Adresse). Sie können dann C++-Code in Ihrem
Regelaktionen statt C-Code. Beachten Sie, dass die Standardeingangsquelle für Ihren Scanner
bleibt bestehen Yyin, und Standard-Echoing wird immer noch durchgeführt, um du. Beides bleibt FILE *
Variablen und nicht C++ Bächen.

Sie können auch biegen zum Generieren einer C++-Scannerklasse mit dem -+ Wahlmöglichkeit (bzw.
gleichwertig, %Möglichkeit c++), die automatisch angegeben wird, wenn der Name des flex
ausführbare Datei endet mit einem '+', wie zum Beispiel Flex++. Wenn Sie diese Option verwenden, ist flex standardmäßig auf
Generieren des Scanners für die Datei lex.yy.cc statt lex.yy.c. Der generierte Scanner
enthält die Header-Datei FlexLexer.h, die die Schnittstelle zu zwei C++-Klassen definiert.

Die erste Klasse, FlexLexer, stellt eine abstrakte Basisklasse bereit, die den allgemeinen Scanner definiert
Klasse Schnittstelle. Es bietet die folgenden Memberfunktionen:

const char * JJText()
gibt den Text des zuletzt übereinstimmenden Tokens zurück, das Äquivalent von jjtext.

int YYLeng()
gibt die Länge des zuletzt übereinstimmenden Tokens zurück, das Äquivalent von Yyleng.

int Linie Nr() const
gibt die aktuelle Eingabezeilennummer zurück (siehe %Möglichkeit yylineno), or 1 if %Möglichkeit
yylineno wurde nicht verwendet.

ungültig set_debug( int Flagge )
setzt das Debugging-Flag für den Scanner, äquivalent zur Zuweisung an yy_flex_debug
(siehe Abschnitt Optionen oben). Beachten Sie, dass Sie den Scanner mit erstellen müssen
%Möglichkeit debuggen um Debugging-Informationen aufzunehmen.

int debuggen() const
gibt die aktuelle Einstellung des Debugging-Flags zurück.

Außerdem werden Memberfunktionen bereitgestellt, die äquivalent zu sind yy_switch_to_buffer(), yy_create_buffer()
(obwohl das erste Argument ein . ist std::istream* Objektzeiger und nicht a DATEI*),
yy_flush_buffer(), yy_delete_buffer(), und yyrestart() (wieder ist das erste Argument a
std::istream* Objektzeiger).

Die zweite Klasse definiert in FlexLexer.h is yyFlexLexer, das ist abgeleitet von FlexLexer.
Es definiert die folgenden zusätzlichen Memberfunktionen:

yyFlexLexer( std::istream* arg_yyin = 0, std::ostream* arg_yyout = 0 )
konstruiert a yyFlexLexer -Objekt, das die angegebenen Streams für die Eingabe und Ausgabe verwendet. Wenn
nicht angegeben, die Streams sind standardmäßig cin und Cout, beziehungsweise.

virtuell int yylex()
erfüllt die gleiche Rolle ist yylex() tut für gewöhnliche Flex-Scanner: Es scannt die
Eingabestream, der Token verbraucht, bis die Aktion einer Regel einen Wert zurückgibt. wenn du
eine Unterklasse ableiten S für yyFlexLexer und auf die Memberfunktionen zugreifen möchten und
Variablen von S innerhalb yylex(), dann musst du verwenden %Möglichkeit yyclass="S" informieren
biegen dass Sie diese Unterklasse anstelle von verwenden werden yyFlexLexer. In diesem Fall
anstatt zu erzeugen yyFlexLexer::yylex(), biegen erzeugt S::yylex() (und auch
erzeugt einen Dummy yyFlexLexer::yylex() das ruft yyFlexLexer::LexerError() if
namens).

virtuell ungültig switch_streams(std::istream* neu in = 0,
std::ostream* neu_aus = 0) weist neu zu jjin zu neu in (wenn nicht null) und du zu
neu_aus (dito), Löschen des vorherigen Eingabepuffers, wenn jjin wird neu vergeben.

int yylex ( std::istream* neu in, std::ostream* neu_aus = 0 )
schaltet zuerst die Eingangsströme über switch_streams( neu in, neu_aus ) und dann
gibt den Wert von zurück yylex().

Zudem hat auch Frau yyFlexLexer definiert die folgenden geschützten virtuellen Funktionen, die Sie
in abgeleiteten Klassen neu definieren, um den Scanner anzupassen:

virtuell int LexerEingabe( char * buff, int maximale Größe )
liest bis maximale Größe Zeichen in buf und gibt die Anzahl der gelesenen Zeichen zurück.
Geben Sie 0 Zeichen zurück, um das Ende der Eingabe anzuzeigen. Beachten Sie, dass "interaktive" Scanner
(Siehe -B und -I Flags) definieren das Makro YY_INTERAKTIV. Wenn du neu definierst
LexerInput() und müssen unterschiedliche Maßnahmen ergreifen, je nachdem, ob die
Wenn der Scanner möglicherweise eine interaktive Eingabequelle scannt, können Sie die
Präsenz dieses Namens über #ifdef.

virtuell ungültig LexerAusgabe( const char * buff, int Größe )
schreibt aus Größe Zeichen aus dem Puffer buff, die, obwohl NUL-terminiert, möglicherweise
enthalten auch "interne" NULs, wenn die Regeln des Scanners Text mit NULs in abgleichen können
Them.

virtuell ungültig LexerFehler( const char * msg )
meldet eine fatale Fehlermeldung. Die Standardversion dieser Funktion schreibt die
Nachricht an den Stream cerr und geht.

Beachten Sie, dass ein yyFlexLexer Objekt enthält seine Scan-Zustand. So können Sie solche verwenden
Objekte, um wiedereintretende Scanner zu erstellen. Sie können mehrere Instanzen derselben instanziieren
yyFlexLexer -Klasse, und Sie können auch mehrere C++-Scanner-Klassen in der
gleiches Programm mit dem -P oben besprochene Option.

Beachten Sie schließlich, dass die %Array die Funktion ist für C++-Scannerklassen nicht verfügbar; du musst
- %Zeiger (der Standard).

Hier ist ein Beispiel für einen einfachen C++-Scanner:

// Ein Beispiel für die Verwendung der Flex-C++-Scannerklasse.

%{
int mylineno = 0;
%}

Zeichenfolge \"[^\n"]+\"

ws [\t]+

Alpha [A-Za-z]
graben [0-9]
Name ({alpha}|{dig}|\$)({alpha}|{dig}|[_.\-/$])*
num1 [-+]?{dig}+\.?([eE][-+]?{dig}+)?
num2 [-+]?{dig}*\.{dig}+([eE][-+]?{dig}+)?
Zahl {num1}|{num2}

%%

{ws} /* Leerzeichen und Tabulatoren überspringen */

"/*" {
int c;

while((c = yyinput()) != 0)
{
if(c == '\n')
++mylineno;

sonst if(c == '*')
{
if((c = yyinput()) == '/')
break;
sonst
unput(c);
}
}
}

{Zahl} cout << "Zahl" << YYText() << '\n';

\n mylineno++;

{name} cout << "name " << YYText() << '\n';

{string} cout << "string" << YYText() << '\n';

%%

int main( int /* argc */, char** /* argv */ )
{
FlexLexer* lexer = neuer yyFlexLexer;
while(lexer->yylex() != 0)
;
Rückkehr 0;
}
Wenn Sie mehrere (unterschiedliche) Lexer-Klassen erstellen möchten, verwenden Sie die -P Flagge (oder die
Präfix= Option), um jedes umzubenennen yyFlexLexer zu einem anderen xxFlexLexer. Dann kannst du
das in Ihren anderen Quellen einmal pro Lexer-Klasse, erste Umbenennung
yyFlexLexer wie folgt:

#undef yyFlexLexer
#define yyFlexLexer xxFlexLexer
#enthalten

#undef yyFlexLexer
#define yyFlexLexer zzFlexLexer
#enthalten

wenn Sie zum Beispiel verwendet haben %Möglichkeit Präfix="xx" für einen Ihrer Scanner und %Möglichkeit
Präfix="zz" für die anderen.

WICHTIG: Die aktuelle Form der Scanning-Klasse ist experimentell und kann sich ändern
erheblich zwischen den Hauptversionen.

INKOMPATIBILITÄTEN MIT LEX UND POSIX


biegen ist eine Neufassung des AT&T Unix lex Tool (die beiden Implementierungen teilen sich keine
Code), mit einigen Erweiterungen und Inkompatibilitäten, die beide besorgniserregend sind
diejenigen, die Scanner schreiben möchten, die für beide Implementierungen akzeptabel sind. Flex ist voll
konform mit dem POSIX lex Spezifikation, außer dass bei Verwendung %Zeiger (der Standard),
ein Anruf an unput() zerstört den Inhalt von jaytext, was dem POSIX widerspricht
Spezifikation.

In diesem Abschnitt besprechen wir alle bekannten Bereiche der Inkompatibilität zwischen Flex, AT&T
lex und die POSIX-Spezifikation.

flex's -l Option aktiviert maximale Kompatibilität mit dem ursprünglichen AT&T lex Implementierung,
auf Kosten eines erheblichen Leistungsverlustes des erzeugten Scanners. Wir vermerken darunter
Inkompatibilitäten können überwunden werden -l .

biegen ist kompatibel mit lex mit folgenden Ausnahmen:

- Die undokumentierten lex Scannerinterne Variable yylineno wird nicht unterstützt, es sei denn -l
or %Möglichkeit yylineno wird eingesetzt.

yylineno sollte auf Pufferbasis und nicht pro Scanner verwaltet werden
(einzelne globale Variable) Basis.

yylineno ist nicht Teil der POSIX-Spezifikation.

- Das input () Routine ist nicht umdefinierbar, kann aber aufgerufen werden, um Zeichen zu lesen
Befolgung dessen, was durch eine Regel abgeglichen wurde. Wenn input () trifft auf ein Ende
das normale ablegen yywrap() Verarbeitung erfolgt. Ein ``echtes'' Dateiende wird zurückgegeben von
input () as EOF.

Die Eingabe wird stattdessen durch die Definition des gesteuert YY_INPUT Makro.

Die biegen Einschränkung, dass input () nicht neu definiert werden kann, entspricht der
POSIX-Spezifikation, die einfach keine Möglichkeit zur Kontrolle der
Eingabe des Scanners, außer durch eine anfängliche Zuweisung zu jjin.

- Das unput() Routine ist nicht neu definierbar. Diese Einschränkung steht im Einklang mit
Posix.

- biegen Scanner sind nicht so reentrant wie lex Scanner. Insbesondere, wenn Sie ein
interaktiver Scanner und ein Interrupt-Handler, der weit aus dem Scanner springt,
und der Scanner anschließend erneut aufgerufen wird, erhalten Sie möglicherweise folgende Meldung:

Fataler interner Fehler des Flex-Scanners - Pufferende fehlt

Um den Scanner erneut zu betreten, verwenden Sie zuerst

yyrestart( yyin );

Beachten Sie, dass dieser Aufruf alle gepufferten Eingaben verwirft; normalerweise ist das nicht so
Problem mit einem interaktiven Scanner.

Beachten Sie auch, dass flex C++-Scannerklassen sind reentrant, also wenn die Verwendung von C++ eine Option ist
für Sie sollten Sie sie stattdessen verwenden. Siehe "Generieren von C++-Scannern" oben für
Details.

- Ausgang() wird nicht unterstützt. Ausgabe aus dem ECHO Makro wird auf den Dateizeiger ausgeführt
du (Standard Standard).

Ausgang() ist nicht Teil der POSIX-Spezifikation.

- lex unterstützt keine exklusiven Startbedingungen (%x), obwohl sie im POSIX enthalten sind
Spezifikation.

- Wenn Definitionen erweitert werden, biegen schließt sie in Klammern ein. Mit lex, dem
wie folgt vor:

NAME [AZ][A-Z0-9]*
%%
foo{NAME}? printf( "Gefunden\n" );
%%

stimmt nicht mit der Zeichenfolge "foo" überein, denn wenn das Makro erweitert wird, lautet die Regel
entspricht "foo[AZ][A-Z0-9]*?" und die Priorität ist so, dass das '?' ist
verknüpft mit "[A-Z0-9]*". Mit biegen, die Regel wird erweitert auf "foo([AZ][A-
Z0-9]*)?" und so wird die Zeichenfolge "foo" übereinstimmen.

Beachten Sie, dass wenn die Definition mit beginnt ^ oder endet mit $ Dann ist es nicht ergänzt
mit Klammern, damit diese Operatoren in Definitionen ohne Verlust erscheinen können
ihre besonderen Bedeutungen. Aber die , /, und < > Operatoren können nicht in a verwendet werden
biegen Definition.

Die richtigen -l Ergebnisse in der lex Verhalten ohne Klammern um die Definition.

Die POSIX-Spezifikation sieht vor, dass die Definition in Klammern eingeschlossen wird.

- Einige Implementierungen von lex erlauben, dass die Aktion einer Regel in einer separaten Zeile beginnt, wenn
Das Muster der Regel hat nachgestellte Leerzeichen:

%%
foo|bar
{foobar_action(); }

biegen unterstützt diese Funktion nicht.

- Das lex %r (Generieren eines Ratfor-Scanners) wird nicht unterstützt. Es ist nicht Teil von
die POSIX-Spezifikation.

- Nach einem Anruf bei unput(), jjtext ist undefiniert, bis das nächste Token übereinstimmt,
es sei denn, der Scanner wurde mit . gebaut %Array. Dies ist bei nicht der Fall lex oder unter der
POSIX-Spezifikation. Die -l Option beseitigt diese Inkompatibilität.

- Der Vorrang der {} (numerischer Bereich)-Operator ist anders. lex interpretiert
"abc{1,3}" als "entspricht einem, zwei oder drei Vorkommen von 'abc'", wohingegen biegen
interpretiert es als "match 'ab', gefolgt von einem, zwei oder drei Vorkommen von 'c'".
Letzteres stimmt mit der POSIX-Spezifikation überein.

- Der Vorrang der ^ Betreiber ist anders. lex interpretiert "^foo|bar" als "match
entweder 'foo' am Anfang einer Zeile oder 'bar' irgendwo", wohingegen biegen
interpretiert es als "entweder 'foo' oder 'bar', wenn sie am Anfang von a . kommen
line". Letzteres stimmt mit der POSIX-Spezifikation überein.

- Die speziellen Tabellengrößendeklarationen wie %a unterstützt durch lex werden nicht benötigt von
biegen Scanner; biegen ignoriert sie.

- Der Name FLEX_SCANNER ist #definiert, sodass Scanner für die Verwendung mit beiden geschrieben werden können
biegen or Lex. Scanner umfassen auch YY_FLEX_MAJOR_VERSION und YY_FLEX_MINOR_VERSION
angibt, welche Version von biegen generierte den Scanner (zum Beispiel für die 2.5
Release, diese Definitionen wären 2 bzw. 5).

Folgende biegen Funktionen sind nicht enthalten lex oder die POSIX-Spezifikation:

C++-Scanner
%Möglichkeit
Startbedingungsbereiche
Startbedingungsstapel
interaktive/nicht interaktive Scanner
yy_scan_string() und Freunde
yyterminate()
yy_set_interactive()
yy_set_bol()
YY_AT_BOL()
< >
<*>
YY_DECL
YY_START
YY_USER_ACTION
YY_USER_INIT
#line-Anweisungen
%{}s rund um Aktionen
mehrere Aktionen in einer Zeile

plus fast alle Flex-Flags. Das letzte Merkmal in der Liste bezieht sich darauf, dass
mit biegen Sie können mehrere Aktionen in derselben Zeile platzieren, durch Semikolons getrennt, während
mit die Ex, die folgende

foo handle_foo(); ++num_foos_seen;

ist (eher überraschend) gekürzt auf

foo handle_foo();

biegen schneidet die Aktion nicht ab. Aktionen, die nicht in geschweifte Klammern stehen, sind einfach
am Ende der Zeile beendet.

DIAGNOSE


Warnung, regieren kann keine be abgestimmt gibt an, dass die angegebene Regel nicht abgeglichen werden kann, weil sie
folgt anderen Regeln, die immer mit demselben Text übereinstimmen. Zum Beispiel in der
folgendes "foo" kann nicht abgeglichen werden, da es nach einer "catch-all"-Bezeichnerregel kommt:

[az]+ got_identifier();
foo got_foo();

Die richtigen ABLEHNEN in einem Scanner unterdrückt diese Warnung.

Warnung, -s zu erhalten gegeben aber Standard regieren können. be abgestimmt bedeutet, dass es möglich ist
(vielleicht nur in einer bestimmten Startbedingung), dass die Standardregel (entspricht einem einzelnen
Zeichen) ist das einzige, das einer bestimmten Eingabe entspricht. Schon seit -s wurde gegeben,
vermutlich ist dies nicht beabsichtigt.

ablehnen_used_but_not_detected undefiniert or yymore_used_but_not_detected undefiniert - Diese
Fehler können zur Kompilierzeit auftreten. Sie zeigen an, dass der Scanner ABLEHNEN or jjmehr()
aber das biegen habe die Tatsache nicht bemerkt, was bedeutet, dass biegen die ersten beiden Abschnitte gescannt
nach Vorkommen dieser Aktionen gesucht und keine gefunden, aber irgendwie hast du dich eingeschlichen
einige in (zum Beispiel über eine #include-Datei). Verwenden %Möglichkeit ablehnen or %Möglichkeit mehr zu
zeigen Sie flex an, dass Sie diese Funktionen wirklich nutzen.

biegen Scanner Verklemmt - ein Scanner kompiliert mit -s ist auf eine Eingabezeichenfolge gestoßen, die
wurde von keiner seiner Regeln erfüllt. Dieser Fehler kann auch aufgrund interner Probleme auftreten.

Zeichen auch groß, übersteigt YYLMAX - Ihr Scanner verwendet %Array und eine seiner Regeln stimmte überein
Saite länger als die YYLMAX konstant (standardmäßig 8 KB). Sie können den Wert erhöhen
von #define'ing YYLMAX im Definitionsbereich Ihres biegen Eingang.

Scanner erfordert -8 Flagge zu - Charakter 'x' - Ihre Scannerspezifikation beinhaltet
Erkennen des 8-Bit-Zeichens 'x' und Sie haben das Flag -8 nicht angegeben, und Ihr Scanner
Standardmäßig auf 7-Bit eingestellt, weil Sie die -Vgl or -CF Optionen zur Tabellenkomprimierung. Siehe die
Diskussion über die -7 Flagge für Details.

biegen Scanner zurückschieben Überlauf - du hast benutzt unput() so viel Text zurückschieben, dass die
Der Puffer des Scanners konnte nicht sowohl den zurückgeschobenen Text als auch den aktuellen Token aufnehmen jjtext.
Idealerweise sollte der Scanner in diesem Fall die Größe des Puffers dynamisch ändern, aber derzeit ist es
nicht.

Varianten des Eingangssignals: puffern Überlauf, kann nicht vergrößern puffern weil Scanner verwendet ABLEHNEN - der Scanner war
arbeiten an der Übereinstimmung mit einem extrem großen Token und mussten den Eingabepuffer erweitern. Dies
funktioniert nicht mit Scannern, die verwenden ABLEHNEN.

tödlich biegen Scanner intern Fehler - Ende of puffern vermisst - Dies kann in einem Scanner vorkommen
die wieder eingegeben wird, nachdem ein Weitsprung aus der Aktivierung des Scanners (oder über) gesprungen ist
Rahmen. Bevor Sie den Scanner erneut betreten, verwenden Sie Folgendes:

yyrestart( yyin );

oder wechseln Sie, wie oben erwähnt, zur Verwendung der C++-Scannerklasse.

auch viele Anfang Bedingungen in <> konstruieren! - du hast mehr Startbedingungen in einem <> . aufgelistet
konstruieren als existieren (Sie müssen also mindestens einen von ihnen zweimal aufgelistet haben).

Verwenden Sie freebsd-lex online mit den onworks.net-Diensten


Kostenlose Server & Workstations

Laden Sie Windows- und Linux-Apps herunter

Linux-Befehle

Ad