12 Stimmen

Wie kann ich #include-Konstrukte mit Flex und YACC implementieren?

Wenn ich während des Parsens auf ein Include-Token stoße, möchte ich YACC anweisen, die als Eingabe angegebene Datei zu öffnen und mit dem Parsen dieser Datei zu beginnen. Sobald dieses Parsing abgeschlossen ist, möchte ich YACC anweisen, zur Datei zurückzukehren und das Parsing direkt nach dem Include-Ausdruck fortzusetzen. Ich werde die Include-Tiefenstufe auf eins beschränken.

9voto

MtnViewJohn Punkte 673

Das Flex-Handbuch beschreibt, wie man dies mit yypush_buffer_state() und yypop_buffer_state() erreicht.

Hier ist der Abschnitt des offiziellen Handbuchs über die Verwendung von mehreren Eingangspuffern. Es gibt einige Beispielcodes.

1 Stimmen

Die Antwort von DigitilRoss war gründlich und genau genug. Aber bewährte Praktiken sind immer besser als Cleverness. Ich habe das vor 18 Minuten gesehen und jetzt habe ich funktionierende Includes. Danke für den Link. +1

5voto

DigitalRoss Punkte 138823

Es ist normal, dass zwischen der lexikalischen und der syntaktischen Phase Ihres Prozessors kommuniziert wird.

Erkennen Sie also die Syntax für eine Include-Direktive in Ihrem Parser (oder, um die Sache zu vereinfachen, erkennen Sie sie einfach im Lexer) und nehmen Sie die Umschaltung auf der lexikalischen Ebene vor.

Hier ist zum Beispiel eine einfache Sprache, die Standard-Eingabezeilen erkennt, die ab o cd o .file . Wenn es sieht .someString es öffnet sich someString als Include-Datei und kehrt dann zum Lesen der Standardeingabe zurück.

%{
#include <stdio.h>
#include <stdlib.h>
void start_include(char *); int yylex(void); void yyerror(void *);
#define YYSTYPE char *
%}
%%
all:          all others | others;
others:       include_rule | rule_1 | rule_2 | 'Z' { YYACCEPT; };
include_rule: '.' '\n' { start_include($1); };
rule_1:       'a' 'b' '\n' { printf("random rule 1\n"); };
rule_2:       'c' 'd' '\n' { printf("random rule 2\n"); };
%%
FILE * f = NULL;
void start_include(char *s) {
        if ((f = fopen(s, "r")) == NULL)
                abort();
}
int yylex(void) {
        int c;
        static char s[100];
        if (f == NULL)
                f = stdin;
        c = getc(f);
        if (c == EOF) {
                f = stdin;
                c = getc(f);
        }
        if (c == '.') {
                scanf(" %s", s);
                yylval = s;
        } else if (c == EOF)
                return 'Z';
        return c;
}

Und wenn wir es ausführen...

$ cat > toplevel
ab
.myinclude
ab
$ cat > myinclude
cd
cd
$ yacc ip.y && cc -Wall y.tab.c -ly && ./a.out < toplevel
random rule 1
random rule 2
random rule 2
random rule 1
$

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X