leg - Online in der Cloud

Dies ist der Befehlszweig, der beim kostenlosen Hosting-Anbieter OnWorks mit einer unserer zahlreichen kostenlosen Online-Workstations wie Ubuntu Online, Fedora Online, dem Windows-Online-Emulator oder dem MAC OS-Online-Emulator ausgeführt werden kann

PROGRAMM:

NAME/FUNKTION


Peg, Leg - Parser-Generatoren

ZUSAMMENFASSUNG


Wirbel [-hvV -Ausgabe] [Dateiname ...]
Bein [-hvV -Ausgabe] [Dateiname ...]

BESCHREIBUNG


Wirbel und Bein sind Werkzeuge zum Generieren rekursiv absteigender Parser: Programme, die
Musterabgleich auf Text. Sie verarbeiten eine Parsing Expression Grammar (PEG) [Ford 2004] zu
ein Programm erstellen, das Rechtssätze dieser Grammatik erkennt. Wirbel verarbeitet PEGs
geschrieben unter Verwendung der von Ford beschriebenen Originalsyntax; Bein verarbeitet PEGs, die mit . geschrieben wurden
etwas andere Syntax und Konventionen, die es attraktiv machen sollen
Ersatz für Parser, die mit erstellt wurden lex(1) und jacc(1). nicht wie lex und jacc, Wirbel und Bein
unbegrenztes Backtracking unterstützen, geordnete Auswahlmöglichkeiten als Mittel zur Begriffsklärung bieten und
kann Scanning (lexikalische Analyse) und Parsing (syntaktische Analyse) zu einem einzigen kombinieren
Aktivität.

Wirbel liest das angegebene Dateinamens, oder Standardeingabe, wenn nein Dateinamens sind gegeben, für a
Grammatik, die den zu generierenden Parser beschreibt. Wirbel erzeugt dann eine C-Quelldatei, die
definiert eine Funktion yyparse(). Diese C-Quelldatei kann eingebunden oder kompiliert werden und dann
verbunden mit einem Client-Programm. Jedes Mal, wenn das Client-Programm aufruft yyparse() der Parser
verbraucht Eingabetext gemäß den Parsing-Regeln, beginnend mit der ersten Regel im
Grammatik. yyparse() gibt einen Wert ungleich null zurück, wenn die Eingabe gemäß der
Grammatik; es gibt null zurück, wenn die Eingabe nicht geparst werden konnte.

Das Präfix 'yy' oder 'YY' wird allen extern sichtbaren Symbolen im generierten . vorangestellt
Parser. Dies soll das Risiko der Namensraumverschmutzung in Clientprogrammen verringern.
(Die Wahl von 'yy' ist historisch; siehe lex(1) und jacc(1) zum Beispiel.)

OPTIONAL


Wirbel und Bein bieten die folgenden Optionen:

-h druckt eine Zusammenfassung der verfügbaren Optionen und wird dann beendet.

-Ausgabe
schreibt den generierten Parser in die Datei Möglichkeiten für das Ausgangssignal: anstelle der Standardausgabe.

-v schreibt während der Arbeit ausführliche Informationen in den Standardfehler.

-V schreibt Versionsinformationen in den Standardfehler und wird dann beendet.

A Schlicht BEISPIEL


Folgende Wirbel input gibt eine Grammatik mit einer einzigen Regel (genannt 'Start') an, die
erfüllt, wenn die Eingabe die Zeichenfolge "Benutzername" enthält.

start <- "Benutzername"

(Die Anführungszeichen sind nicht Teil des übereinstimmenden Textes; sie dienen zur Angabe eines wörtlichen
abzugleichende Zeichenfolge.) Mit anderen Worten, yyparse() in der generierten C-Quelle wird zurückgegeben
ungleich Null nur, wenn die nächsten acht Zeichen, die aus der Eingabe gelesen werden, das Wort "Benutzername" buchstabieren.
Wenn die Eingabe etwas anderes enthält, yyparse() gibt null zurück und es wird keine Eingabe gemacht
verbraucht. (Nachfolgende Anrufe an yyparse() gibt auch null zurück, da der Parser ist
die Suche nach der Zeichenfolge "Benutzername" effektiv blockiert.) Um den Fortschritt zu gewährleisten, können wir eine
alternative Klausel zur 'start'-Regel, die jedem einzelnen Zeichen entspricht, wenn "Benutzername"
wurde nicht gefunden.

start <- "Benutzername"
/.

yyparse() gibt jetzt immer einen Wert ungleich Null zurück (außer ganz am Ende der Eingabe). Machen
etwas Nützliches können wir den Regeln Aktionen hinzufügen. Diese Aktionen werden ausgeführt, nachdem a
vollständige Übereinstimmung gefunden wird (ausgehend von der ersten Regel) und entsprechend der
'Pfad' durch die Grammatik, um der Eingabe zu entsprechen. (Linguisten würden diesen Weg a
'Phrasenmarker'.)

start <- "Benutzername" { printf("%s\n", getlogin()); }
/ < . > { putchar(yytext[0]); }

Die erste Zeile weist den Parser an, den Login-Namen des Benutzers zu drucken, wenn er sieht
"Benutzername" in der Eingabe. Wenn diese Übereinstimmung fehlschlägt, weist die zweite Zeile den Parser an echo
das nächste Zeichen an der Eingabe die Standardausgabe. Unser Parser ist jetzt nützlich
Arbeit: Es kopiert die Eingabe in die Ausgabe und ersetzt alle Vorkommen von "Benutzername" durch
der Kontoname des Benutzers.

Beachten Sie die spitzen Klammern ('<' und '>'), die der zweiten Alternative hinzugefügt wurden. Diese
haben keinen Einfluss auf den Sinn der Regel, sondern dienen der Abgrenzung des zur Verfügung gestellten Textes
die folgende Aktion in der Variablen jjtext.

Wenn die obige Grammatik in der Datei platziert ist Benutzername.peg, den Befehl ausführen

peg -o Benutzername.c Benutzername.peg

speichert den entsprechenden Parser in der Datei Benutzername.c. Um ein komplettes Programm zu erstellen
dieser Parser könnte wie folgt von einem C-Programm eingebunden werden.

#enthalten /* printf(), putchar() */
#enthalten /* getlogin() */

#include "Benutzername.c" /* yyparse() */

int Haupt ()
{
while (yyparse()) /* wiederholen bis EOF */
;
Rückkehr 0;
}

PEG GRAMMATIK


Eine Grammatik besteht aus einer Reihe von benannten Regeln.

Name <- Muster

Die Anleitungen enthält eines oder mehrere der folgenden Elemente.

Name Das Element steht für das gesamte Muster in der Regel mit dem gegebenen Name.

"Zeichen"
Ein in doppelte Anführungszeichen eingeschlossenes Zeichen oder eine Zeichenfolge wird buchstäblich abgeglichen. Die ANSI-C
Escape-Sequenzen werden innerhalb der erkannt Zeichen.

'Zeichen'
Ein in einfache Anführungszeichen eingeschlossenes Zeichen oder eine Zeichenfolge wird wie oben buchstäblich abgeglichen.

[Zeichen]
Ein Satz von Zeichen in eckigen Klammern entspricht jedem einzelnen Zeichen aus
der Satz, mit wie oben erkannten Escape-Zeichen. Wenn der Satz mit einem beginnt
Pfeil nach oben (^) dann wird die Menge negiert (das Element entspricht einem beliebigen Zeichen nicht an der
einstellen). Jedes Zeichenpaar, das durch einen Bindestrich (-) getrennt ist, repräsentiert den Bereich von
Zeichen vom ersten bis zum zweiten, einschließlich. Ein einzelnes alphabetisches Zeichen
oder Unterstrich wird durch den folgenden Satz abgeglichen.

[a-zA-Z_]

Entsprechend entspricht das Folgende jedem einzelnen nicht-stelligen Zeichen.

[^ 0-9]

. Ein Punkt entspricht einem beliebigen Zeichen. Beachten Sie, dass dies nur am Ende von fehlschlägt
Datei, in der kein übereinstimmendes Zeichen vorhanden ist.

( Anleitungen )
Klammern werden zum Gruppieren verwendet (Ändern der Rangfolge der Operatoren
nachstehend beschrieben).

{ Aktion }
Geschweifte Klammern umgeben Aktionen. Die Aktion soll beliebiger C-Quellcode sein
am Ende des Matchings ausgeführt. Alle Klammern innerhalb der Aktion müssen richtig sein
verschachtelt. Jeder Eingabetext, der vor der Aktion abgeglichen und durch Winkel abgegrenzt wurde
Klammern (siehe unten) wird innerhalb der Aktion als Inhalt der
Zeichenarray jjtext. Die Länge von (Anzahl der Zeichen in) jjtext is
verfügbar in der Variable Yyleng. (Diese Variablennamen sind historisch; siehe
lex(1).)

< Eine öffnende spitze Klammer stimmt immer überein (braucht keine Eingabe) und bewirkt, dass der Parser
um mit dem Sammeln von übereinstimmendem Text zu beginnen. Dieser Text wird für Aktionen in . zur Verfügung gestellt
Die Variable jjtext.

> Eine schließende spitze Klammer stimmt immer überein (braucht keine Eingabe) und bewirkt, dass der Parser
um das Ansammeln von Text zu stoppen für jjtext.

Die obige Elements können mit den folgenden Suffixen optional und/oder wiederholbar gemacht werden:

Element ?
Das Element ist optional. Wenn am Eingang vorhanden, wird es verbraucht und die Übereinstimmung
gelingt es. Wenn in der Eingabe nicht vorhanden, wird kein Text verbraucht und die Übereinstimmung ist erfolgreich
egyébként.

Element +
Das Element ist wiederholbar. Falls in der Eingabe vorhanden, ein oder mehrere Vorkommen von
Element verbraucht werden und das Spiel erfolgreich ist. Wenn kein Vorkommen von Element sind
am Eingang vorhanden ist, schlägt die Übereinstimmung fehl.

Element *
Das Element ist optional und wiederholbar. Falls am Eingang vorhanden, eine oder mehrere
Vorkommen von Element verbraucht werden und das Spiel erfolgreich ist. Wenn kein Vorkommen von
Element am Eingang vorhanden sind, ist die Übereinstimmung trotzdem erfolgreich.

Die obigen Elemente und Suffixe können in Prädikate umgewandelt werden (die auf beliebige
Text eingeben und anschließend erfolgreich sein oder fehlschlagen ohne diesen Input verbrauchen) mit dem
folgende Präfixe:

& Element
Das Prädikat ist nur erfolgreich, wenn Element abgestimmt werden kann. Gescannten Text eingeben, während
Abstimmung Element wird nicht vom Input verbraucht und bleibt verfügbar für
anschließende Übereinstimmung.

! Element
Das Prädikat ist nur erfolgreich, wenn Element kann nicht abgeglichen werden. Gescannten Text eingeben, während
Abstimmung Element wird nicht vom Input verbraucht und bleibt verfügbar für
anschließende Übereinstimmung. Ein beliebtes Idiom ist

!.

was mit dem Dateiende übereinstimmt, nachdem das letzte Zeichen der Eingabe bereits vorhanden ist
verzehrt worden.

Eine Sonderform des Prädikats '&' wird bereitgestellt:

&{ Ausdruck }
In diesem Prädikat ist das einfache C Ausdruck (nicht Aussage) wird sofort ausgewertet
wenn der Parser das Prädikat erreicht. Wenn die Ausdruck ergibt ungleich Null (wahr)
die 'Übereinstimmung' ist erfolgreich und der Parser fährt mit dem nächsten Element im Muster fort.
Besitzt das Ausdruck ergibt null (false) die 'Übereinstimmung' schlägt fehl und der Parser sichert sich auf
Suchen Sie nach einer alternativen Analyse der Eingabe.

Mehrere Elemente (mit oder ohne Präfixe und Suffixe) können zu einem kombiniert werden Reihenfolge
indem Sie sie nacheinander schreiben. Die gesamte Sequenz stimmt nur dann überein, wenn jedes Individuum
Element darin übereinstimmt, von links nach rechts.

Sequenzen können durch den Alternationsoperator '/' in disjunkte Alternativen zerlegt werden.

Sequenz-1 / Sequenz-2 / ... / Sequenz-N
Jede Sequenz wird der Reihe nach ausprobiert, bis eine von ihnen passt, dann passt es
denn das Gesamtmuster gelingt. Wenn keine der Sequenzen übereinstimmt, dann ist die Übereinstimmung
des Gesamtmusters schlägt fehl.

Schließlich leitet das Rautezeichen (#) einen Kommentar ein (verworfen), der bis zum Ende fortgesetzt wird
der Linie.

Um das Obige zusammenzufassen, versucht der Parser, den Eingabetext mit einem Muster abzugleichen
mit Literalen, Namen (die andere Regeln darstellen) und verschiedenen Operatoren (geschrieben als
Präfixe, Suffixe, Nebeneinanderstellung für die Sequenzierung und ein Infix-Wechseloperator), die
Ändern Sie, wie die Elemente innerhalb des Musters abgeglichen werden. Matches werden von links nach gemacht
richtig, "absteigend" in benannte Unterregeln, wenn sie angetroffen werden. Wenn der Matching-Prozess
schlägt fehl, der Parser 'zurückzuverfolgen' (die Eingabe wird dabei entsprechend 'zurückgespult')
Finden Sie den nächsten alternativen 'Pfad' durch die Grammatik. Mit anderen Worten, der Parser
führt eine Tiefensuche von links nach rechts nach dem ersten erfolgreich übereinstimmenden Pfad durch
durch die Regeln. Wenn gefunden, werden die Aktionen entlang des erfolgreichen Pfads ausgeführt (im
Reihenfolge, in der sie angetroffen wurden).

Beachten Sie, dass Prädikate ausgewertet werden sofort bei der Suche nach einem erfolgreichen Match,
da sie zum Erfolg oder Misserfolg der Suche beitragen. Aktionen sind jedoch
erst ausgewertet, nachdem eine erfolgreiche Übereinstimmung gefunden wurde.

PEG GRAMMATIK FÜR PEG GRAMMATIK


Die Grammatik für Wirbel Grammatiken ist unten gezeigt. Dies wird sowohl veranschaulichen als auch formalisieren
obige Beschreibung.

Grammatik <- Abstandsdefinition+ EndOfFile

Definition <- Bezeichner LINKER PFEIL Ausdruck
Ausdruck <- Sequenz ( SLASH-Sequenz )*
Sequenz <- Präfix*
Präfix <- UND Aktion
/ ( UND | NICHT )? Suffix
Suffix <- Primär ( QUERY / STAR / PLUS )?
Primärer <- Bezeichner !PFEIL LINKS
/ OPEN Ausdruck SCHLIESSEN
/ wörtlich
/ Klasse
/ PUNKT
/ Handlung
/ START
/ ENDE

Identifier <- < IdentStart IdentCont* > Abstand
IdentStart <- [a-zA-Z_]
IdentCont <- IdentStart / [0-9]
Literal <- ['] < ( !['] Char )* > ['] Abstand
/ ["] < ( !["] Char )* > ["] Abstand
Klasse <- '[' < ( !']' Bereich )* > ']' Abstand
Bereich <- Char '-' Char / Char
Zeichen <- '\\' [abefnrtv'"\[\]\\]
/ '\\' [0-3][0-7][0-7]
/ '\\' [0-7][0-7]?
/ '\\' '-'
/ !'\\' .
LINKER PFEIL <- '<-' Abstand
SLASH <- '/' Abstand
UND <- '&' Abstand
NICHT <- '!' Abstand
ABFRAGE <- '?' Abstand
STERNE <- '*' Abstand
PLUS <- '+' Abstand
OPEN <- '(' Abstand
SCHLIESSEN <- ')' Abstand
PUNKT <- '.' Abstand
Abstand <- ( Leerzeichen / Kommentar )*
Kommentar <- '#' ( !EndOfLine . )* EndOfLine
Leerzeichen <- ' ' / '\t' / EndOfLine
EndOfLine <- '\r\n' / '\n' / '\r'
EndOfFile <- !.
Aktion <- '{' < [^}]* > '}' Abstand
BEGIN <- '<' Abstand
END <- '>' Abstand

LEG GRAMMATIK


Bein ist eine Variante von Wirbel das fügt einige Funktionen von . hinzu lex(1) und jacc(1). Es unterscheidet sich von
Wirbel auf folgende Weise.

%{ Text... %}
Ein Deklarationsabschnitt kann überall dort erscheinen, wo eine Regeldefinition erwartet wird. Die
Text zwischen den Trennzeichen '%{' und '%}' wird wörtlich in das generierte C . kopiert
Parser-Code bevor der Code, der den Parser selbst implementiert.

Name = Anleitungen
Der 'Zuweisung'-Operator ersetzt den Linkspfeil-Operator '<-'.

Regelname
Bindestriche können in den Namen von Regeln als Buchstaben erscheinen. Jeder Bindestrich wird umgewandelt in
einen Unterstrich im generierten C-Quellcode. Ein einzelner Bindestrich '-' ist a
Rechtsregelname.

- = [\t\n\r]*
Zahl = [0-9]+ -
Name = [a-zA-Z_][a-zA_Z_0-9]* -
l-paren = '(' -
r-paren = ')' -

Dieses Beispiel zeigt, wie beim Lesen der Grammatik ignorierte Leerzeichen offensichtlich sein können
und doch unauffällig, wenn man es großzügig am Ende jeder damit verbundenen Regel platziert
ein lexikalisches Element.

seq-1 | seq-2
Der Wechseloperator ist ein vertikaler Strich '|' statt Schrägstrich '/'. Die
Wirbel regieren

Name <- Sequenz-1
/ Sequenz-2
/ Sequenz-3

wird daher geschrieben

Name = Sequenz-1
| Sequenz-2
| Sequenz-3
;

in Bein (wobei das abschließende Semikolon optional ist, wie im Folgenden beschrieben).

exp ~ { Aktion }
Ein Postfix-Operator ~{ Aktion } kann nach jedem Ausdruck platziert werden und verhält sich
wie eine normale Aktion (beliebiger C-Code), außer dass sie nur aufgerufen wird, wenn exp
scheitert. Es bindet weniger fest als jeder andere Operator außer Wechsel und
Sequenzierung und soll die Fehlerbehandlung und den Wiederherstellungscode vereinfachen
schreiben. Beachten Sie, dass jjtext und Yyleng sind in diesen Aktionen nicht verfügbar, aber die
Zeigervariable yy ist verfügbar, um dem Code Zugriff auf beliebige benutzerdefinierte
Mitglieder des Parser-Zustands (siehe "ANPASSEN DES PARSER" unten). Beachten Sie auch, dass
exp ist immer ein einzelner Ausdruck; um eine Fehleraktion für jeden Fehler innerhalb von . aufzurufen
einer Sequenz, müssen Klammern verwendet werden, um die Sequenz zu einer einzigen zu gruppieren
Ausdruck.

Regel = e1 e2 e3 ~{ error("e[12] ok; e3 ist fehlgeschlagen"); }
| ...

Regel = (e1 e2 e3) ~{ error("einer von e[123] ist fehlgeschlagen"); }
| ...

Anleitungen ;
Ein Semikolon-Satzzeichen kann optional a . terminieren Anleitungen.

%% Text...
Ein doppelter Prozentwert '%%' beendet den Abschnitt mit den Regeln (und Deklarationen) des
Grammatik. Alle Text nach '%%' wird wörtlich in den generierten C-Parser-Code kopiert
nachdem den Parser-Implementierungscode.

$$ = Wert
Eine untergeordnete Regel kann eine Semantik zurückgeben Wert aus einer Aktion, indem Sie sie dem
Pseudovariable '$$'. Alle semantischen Werte müssen den gleichen Typ haben (Standardeinstellung
zu 'int'). Dieser Typ kann geändert werden, indem YYSTYPE in einem Deklarationsabschnitt definiert wird.

Kennzeichnung:Name
Der von der Unterregel zurückgegebene semantische Wert (durch Zuweisung zu '$$') Name is
in Verbindung mit Kennzeichnung und kann in nachfolgenden Aktionen verwendet werden.

Das folgende Beispiel für einen Tischrechner veranschaulicht die Verwendung von '$$' und ':'.

LEG Beispiel: A DESK TASCHENRECHNER


Die Erweiterungen in Bein oben beschriebene nützliche Parser und Evaluatoren (einschließlich
Deklarationen, Grammatikregeln und unterstützende C-Funktionen wie 'main') bleiben innerhalb
eine einzige Quelldatei. Zur Veranschaulichung zeigen wir einen einfachen Tischrechner, der die
vier gängige arithmetische Operatoren und benannte Variablen. Die Zwischenergebnisse von
Die arithmetische Auswertung wird auf einem impliziten Stack akkumuliert, indem sie als . zurückgegeben werden
semantische Werte aus Unterregeln.

%{
#enthalten /* printf() */
#enthalten /* atoi() */
int-Variablen[26];
%}

Stmt = - e:Expr EOL { printf("%d\n", e); }
| ( !EOL . )* EOL { printf("Fehler\n"); }

Ausdr = i:ID ASSIGN s:Sum { $$ = vars[i] = s; }
| s:Summe { $$ = s; }

Summe = l:Produkt
( PLUS r:Produkt { l += r; }
| MINUS r:Produkt { l -= r; }
)* {$$ = l; }

Produkt = l:Wert
( MAL r:Wert { l *= r; }
| DIVIDE r:Wert { l /= r; }
)* {$$ = l; }

Wert = i:NUMBER { $$ = atoi(yytext); }
| i:ID !ASSIGN { $$ = vars[i]; }
| ÖFFNEN i:Expr SCHLIESSEN { $$ = i; }

ZAHL = < [0-9]+ > - { $$ = atoi(yytext); }
ID = < [az] > - { $$ = yytext[0] - 'a'; }
ZUWEISUNG = '=' -
PLUS = '+' -
MINUS = '-' -
ZEITEN = '*' -
TEILEN = '/' -
OFFEN = '(' -
SCHLIESSEN = ')' -

- = [\t]*
EOL = '\n' | '\r\n' | '\r' | ';'

%%

int Haupt ()
{
während (yyparse())
;
Rückkehr 0;
}

LEG GRAMMATIK FÜR LEG GRAMMATIK


Die Grammatik für Bein Grammatiken ist unten gezeigt. Dies wird sowohl veranschaulichen als auch formalisieren
obige Beschreibung.

Grammatik = -
( Erklärung | Definition )+
Anhänger? Ende der Datei

Deklaration = '%{' < ( !'%}' . )* > RPERCENT

Trailer = '%%' < .* >

Definition = Bezeichner EQUAL-Ausdruck SEMICOLON?

Ausdruck = Sequenz ( BAR-Sequenz )*

Sequenz = Fehler+

error = Präfix ( TILDE-Aktion )?

Präfix = UND Aktion
| ( UND | NICHT )? Suffix

Suffix = primär ( QUERY | STAR | PLUS )?

Primary = Bezeichner COLON-Bezeichner !GLEICH
| Kennung !GLEICH
| OPEN-Ausdruck SCHLIESSEN
| wörtlich
| Klasse
| PUNKT
| Handlung
| START
| ENDE

Kennung = < [-a-zA-Z_][-a-zA-Z_0-9]* > -

literal = ['] < ( !['] char )* > ['] -
| ["] < ( !["] Zeichen )* > ["] -

Klasse = '[' < ( !']' Bereich )* > ']' -

Bereich = Zeichen '-' Zeichen | verkohlen

char = '\\' [abefnrtv'"\[\]\\]
| '\\' [0-3][0-7][0-7]
| '\\' [0-7][0-7]?
| !'\\' .

Aktion = '{' < geschweifte Klammern* > '}' -

geschweifte Klammern = '{' geschweifte Klammern* '}'
| !'}' .

GLEICH = '=' -
Doppelpunkt = ':' -
SEMIKOLON = ';' -
BAR = '|' -
UND = '&' -
NICHT = '!' -
ABFRAGE = '?' -
STERN = '*' -
PLUS = '+' -
OFFEN = '(' -
SCHLIESSEN = ')' -
DOT = '.' -
BEGIN = '<' -
ENDE = '>' -
TILDE = '~' -
RPERCENT = '%}' -

- = ( Leerzeichen | Kommentar )*
Leerzeichen = ' ' | '\t' | Ende der Linie
Kommentar = '#' ( !Zeilenende . )* Zeilenende
Zeilenende = '\r\n' | '\n' | '\R'
Dateiende = !.

ANPASSUNG PARSER


Die folgenden Symbole können in Deklarationsabschnitten neu definiert werden, um die generierten
Parser-Code.

JYSTYP
Der semantische Werttyp. Die Pseudovariable '$$' und die Bezeichner 'gebunden' an
Regelergebnisse mit dem Doppelpunktoperator ':' sollten alle als deklariert betrachtet werden
diesen Typ zu haben. Der Standardwert ist 'int'.

YYPARSE
Der Name des Haupteinstiegspunkts zum Parser. Der Standardwert ist 'yyparse'.

YYPARSEVON
Der Name eines alternativen Einstiegspunkts für den Parser. Diese Funktion erwartet einen
Argument: die Funktion, die der Regel entspricht, aus der nach einer Übereinstimmung gesucht wird
sollte beginnen. Der Standardwert ist 'yyparsefrom'. Beachten Sie, dass yyparse() definiert ist als

int yyparse () { return yyparsefrom (yy_foo); }

wobei 'foo' der Name der ersten Regel in der Grammatik ist.

YY_INPUT(buf, Folge, maximale Größe)
Dieses Makro wird vom Parser aufgerufen, um mehr Eingabetext zu erhalten. buf weist auf eine
Speicherbereich, der höchstens fassen kann maximale Größe Zeichen. Das Makro sollte kopieren
Text eingeben in buf und weisen Sie dann die ganzzahlige Variable zu Folge um die anzuzeigen
Anzahl der kopierten Zeichen. Wenn keine Eingabe mehr vorhanden ist, sollte das Makro
0 zu . zuweisen Folge. Standardmäßig ist das Makro YY_INPUT wie folgt definiert.

#define YY_INPUT(buf, result, max_size)
{
int yyc= getchar();
result= (EOF == yyc) ? 0 : (*(buf)= yyc, 1);
}

Beachten Sie, dass, wenn YY_CTX_LOCAL definiert ist (siehe unten), ein zusätzliches erstes Argument,
der den Parserkontext enthält, wird an YY_INPUT übergeben.

YY_DEBUG
Wenn dieses Symbol definiert ist, wird zusätzlicher Code in den Parser aufgenommen, der
druckt riesige Mengen obskurer Informationen in den Standardfehler, während der Parser
läuft.

YY_BEGIN
Dieses Makro wird aufgerufen, um den Anfang des Eingabetextes zu markieren, der verfügbar gemacht wird
in Aktionen als 'yytext'. Dies entspricht dem Auftreten von '<' in der Grammatik.
Diese werden in Prädikate umgewandelt, von denen erwartet wird, dass sie erfolgreich sind. Der Standard
Definition

#define YY_BEGIN (yybegin= yypos, 1)

speichert daher die aktuelle Eingabeposition und gibt 1 ('true') als Ergebnis von
das Prädikat.

YY_END Dieses Makro entspricht '>' in der Grammatik. Auch hier ist es ein Prädikat, also die
Die Standarddefinition speichert die Eingabeposition vor dem 'Nachfolgen'.

#define YY_END (yyend= yypos, 1)

YY_PARSE(T)
Dieses Makro deklariert die Parser-Einstiegspunkte (yyparse und yyparsefrom) als vom Typ
T. Die Standarddefinition

#define YY_PARSE(T) T

lässt yyparse() und yyparsefrom() mit globaler Sichtbarkeit. Wenn sie es nicht sein sollten
extern in anderen Quelldateien sichtbar, kann dieses Makro neu definiert werden, um zu deklarieren
sie "statisch".

#define YY_PARSE(T) statisches T

YY_CTX_LOCAL
Wenn dieses Symbol während der Kompilierung eines generierten Parsers definiert wird, dann global
Parser-Zustand wird in einer Struktur vom Typ 'yycontext' gehalten, die deklariert werden kann
als lokale Variable. Dadurch können mehrere Instanzen von Parsern koexistieren und
fadensicher sein. Die Parsing-Funktion yyparse() wird erklärt, dass er eine erste erwartet
Argument vom Typ 'yycontext *', eine Instanz der Struktur, die das globale
Zustand für den Parser. Diese Instanz muss zugewiesen und auf Null initialisiert werden durch
der Kunde. Ein triviales, aber vollständiges Beispiel ist wie folgt.

#einschließen

#define YY_CTX_LOCAL

#include "the-generated-parser.peg.c"

int Haupt ()
{
yycontext-ctx;
memset(&ctx, 0, sizeof(yycontext));
while (yyparse(&ctx));
Rückkehr 0;
}

Beachten Sie, dass der kompilierte Parser statisch wird, wenn dieses Symbol nicht definiert ist
weist seinen globalen Status zu und ist weder reentrant noch Thread-sicher. Beachten Sie auch
dass der Parser yycontext-Struktur beim ersten Mal automatisch initialisiert wird
yyparse() wird genannt; diese Struktur sollen deshalb richtig auf Null initialisiert werden
vor dem ersten Anruf bei yyparse().

YY_CTX_MEMBERS
Wenn YY_CTX_LOCAL definiert ist (siehe oben), kann das Makro YY_CTX_MEMBERS definiert werden
um alle zusätzlichen Mitgliedsfelddeklarationen zu erweitern, die der Kunde wünscht
in der Deklaration des Strukturtyps 'yycontext' enthalten. Diese zusätzlichen
Member werden ansonsten vom generierten Parser ignoriert. Die Instanz von 'yycontext'
die mit dem aktuell aktiven Parser verknüpft ist, ist innerhalb von Aktionen als
Zeigervariable yy.

YY_BUFFER_SIZE
Die anfängliche Größe des Textpuffers in Byte. Der Standardwert ist 1024 und der Puffer
Die Größe wird verdoppelt, wenn dies erforderlich ist, um den Bedarf während des Parsens zu decken. Eine Bewerbung
die normalerweise viel längere Strings parst, könnte dies erhöhen, um unnötiges zu vermeiden
Neuzuweisung des Puffers.

YY_STACK_SIZE
Die Anfangsgröße der Variablen- und Aktionsstapel. Der Standardwert ist 128, also
verdoppelt, wann immer dies erforderlich ist, um die Nachfrage während des Parsings zu decken. Anwendungen, die
tiefe Aufrufstapel mit vielen lokalen Variablen oder die nach a . viele Aktionen ausführen
einzelnes erfolgreiches Match, könnte dies erhöhen, um unnötigen Puffer zu vermeiden
Umverteilung.

YY_MALLOC(YY, GRÖßE)
Der Speicherzuordner für den gesamten Parser-bezogenen Speicher. Die Parameter sind die
aktuelle yycontext-Struktur und die Anzahl der zuzuweisenden Bytes. Der Standard
Definition ist: malloc(GRÖßE)

YY_REALLOC(YY, PTR, GRÖßE)
Der Memory Relocator für dynamisch gewachsenen Speicher (wie Textpuffer und
variable Stapel). Die Parameter sind die aktuelle yycontext-Struktur, die
zuvor zugewiesener Speicher und die Anzahl der Bytes, auf die dieser Speicher
gewachsen sein. Die Standarddefinition ist: realloc(PTR, GRÖßE)

YY_FREE(YY, PTR)
Der Speicher-Delocator. Die Parameter sind die aktuelle yycontext-Struktur und die
Speicher aufzulösen. Die Standarddefinition ist: free(PTR)

YYFREIGABE
Der Name der Funktion, die alle Ressourcen freigibt, die von einer yycontext-Struktur gehalten werden.
Der Standardwert ist 'yyrelease'.

Auf die folgenden Variablen kann innerhalb von Aktionen Bezug genommen werden.

verkohlen *jjbuf
Diese Variable zeigt auf den Eingabepuffer des Parsers, der zum Speichern von Eingabetext verwendet wird, der
noch nicht abgestimmt.

int jap
Dies ist der Offset (in yybuf) des nächsten zu vergleichenden und zu konsumierenden Zeichens.

verkohlen *yytext
Der letzte übereinstimmende Text, getrennt durch '<' und '>', wird in dieser Variablen gespeichert.

int Yyleng
Diese Variable gibt die Anzahl der Zeichen in 'yytext' an.

yykontext *jj
Diese Variable zeigt auf die Instanz von 'yycontext', die mit der
aktuell aktiver Parser.

Programme, die alle einem Parser zugeordneten Ressourcen freigeben möchten, können die
folgende Funktion.

yyrelease(yycontext*yy)
Gibt den gesamten vom Parser zugewiesenen Speicher zurück, der mit verbunden ist yy zum System. Der Speicher
wird beim nächsten Anruf an neu vergeben yyparse().

Beachten Sie, dass der Speicher für die yycontext-Struktur selbst niemals zugewiesen oder zurückgefordert wird
implizit. Die Anwendung muss diese Strukturen im automatischen Speicher zuordnen oder verwenden
calloc() und kostenlos() um sie explizit zu verwalten. Das Beispiel im folgenden Abschnitt
zeigt einen Ansatz zum Ressourcenmanagement.

LEG Beispiel: VERLÄNGERN PARSER'S KONTEXT


Die yy Variable, die an Aktionen übergeben wird, enthält den Zustand des Parsers plus alle zusätzlichen
Felder, die von YY_CTX_MEMBERS definiert sind. Diese Felder können verwendet werden, um anwendungsspezifische
Informationen, die für einen bestimmten Aufruf von . global sind yyparse(). Eine triviale, aber vollständige Bein
Es folgt ein Beispiel, in dem die yycontext-Struktur mit a . erweitert wird zählen der Anzahl von
Zeilenumbruchzeichen, die bisher in der Eingabe gesehen wurden (die Grammatik wird ansonsten verbraucht und ignoriert
die gesamte Eingabe). Der Anrufer von yyparse() Verwendet zählen um die Anzahl der Zeilen zu drucken
Eingaben, die gelesen wurden.

%{
#define YY_CTX_LOCAL 1
#define YY_CTX_MEMBERS
int zählen;
%}

Char = ('\n' | '\r\n' | '\r') { yy->count++ }
| .

%%

#einschließen
#enthalten

int Haupt ()
{
/* einen lokalen Parser-Kontext im automatischen Speicher erstellen */
yyKontext yy;
/* der Kontext *muss* vor der ersten Verwendung auf Null initialisiert werden*/
memset(&yy, 0, sizeof(yy));

while (yyparse(&yy))
;
printf("%d Zeilenumbrüche\n", yy.count);

/* alle Ressourcen freigeben, die mit dem Kontext verknüpft sind */
yyFreigabe(&yy);

Rückkehr 0;
}

DIAGNOSE


Wirbel und Bein warnen Sie vor den folgenden Bedingungen, während Sie eine Grammatik in einen Parser umwandeln.

Syntax Fehler
Die Eingabegrammatik war in irgendeiner Weise fehlerhaft. Die Fehlermeldung enthält die
Text, der abgeglichen werden soll (oft wird eine große Menge vom tatsächlichen Standort des
den Fehler) und die Zeilennummer des zuletzt berücksichtigten Zeichens (das ist
oft der wahre Ort des Problems).

regieren 'foo' benutzt aber nicht definiert
Die Grammatik bezog sich auf eine Regel namens 'foo', aber es wurde keine Definition dafür gegeben.
Der Versuch, den generierten Parser zu verwenden, führt wahrscheinlich zu Fehlern vom Linker
aufgrund von undefinierten Symbolen, die mit der fehlenden Regel verbunden sind.

regieren 'foo' definiert aber nicht benutzt
Die Grammatik definierte eine Regel namens 'foo' und ignorierte sie dann. Der zugehörige Code
mit der Regel ist im generierten Parser enthalten, der in jeder anderen Hinsicht
gesund sein.

möglich unendlich links Rekursion in regieren 'foo'
Es existiert mindestens ein Pfad durch die Grammatik, der von der Regel 'foo' führt
zurück zu (einem rekursiven Aufruf) derselben Regel, ohne Eingaben zu verbrauchen.

Linksrekursionen, insbesondere in Standarddokumenten, sind oft „direkt“ und
impliziert triviale Wiederholung.

# (6.7.6)
direkter abstrakter Deklarator =
LPAREN Abstract-Deklarator RPAREN
| direkt-abstrakt-deklarator? LBRACKET Zuweisungsausdruck? RHALTERUNG
| direkt-abstrakt-deklarator? LBRACKET STAR RBRACKET
| direkt-abstrakt-deklarator? LPAREN Parameter-Typ-Liste? RPAREN

Die Rekursion kann leicht eliminiert werden, indem die Teile des Musters nachfolgend konvertiert werden
die Rekursion in ein wiederholbares Suffix.

# (6.7.6)
direkter abstrakter Deklarator =
direkt-abstrakter-Deklarator-Kopf?
direkter-abstrakter-Deklarator-Schwanz*

direkt-abstrakter-Deklarator-Kopf =
LPAREN Abstract-Deklarator RPAREN

direct-abstract-declarator-tail =
LBRACKET Zuweisungsausdruck? RHALTERUNG
| LHALTER STAR RHALTER
| LPAREN Parameter-Typ-Liste? RPAREN

VORSICHTEN


Ein Parser, der leere Eingaben akzeptiert, wird immer erfolgreich. Betrachten Sie das folgende Beispiel,
nicht untypisch für einen ersten Versuch, einen PEG-basierten Parser zu schreiben:

Programm = Ausdruck*
Ausdruck = "was auch immer"
%%
int main () {
während (yyparse())
puts("Erfolg!");
Rückkehr 0;
}

Dieses Programm durchläuft eine ewige Schleife, egal welche Eingabe (falls vorhanden) auf stdin bereitgestellt wird. Viele
Korrekturen sind möglich, am einfachsten ist es, darauf zu bestehen, dass der Parser immer etwas verbraucht
nicht leerer Eingang. Ändern der ersten Zeile in

Programm = Ausdruck+

bewerkstelligt dies. Wenn vom Parser erwartet wird, dass er die gesamte Eingabe verbraucht, dann explizit
Das Anfordern des Dateiendes wird ebenfalls dringend empfohlen:

Programm = Ausdruck+ !.

Dies funktioniert, weil der Parser überhaupt kein Zeichen ("!"-Prädikat) finden kann
("."-Ausdruck), wenn versucht wird, über das Ende der Eingabe hinaus zu lesen.

Nutzen Sie leg online über die Dienste von onworks.net



Neueste Linux- und Windows-Online-Programme