Как я могу реализовать конструкции #include с Flex и YACC? - PullRequest
11 голосов
/ 16 февраля 2010

Во время синтаксического анализа, если я сталкиваюсь с токеном включения, я хочу дать YACC команду открыть файл, указанный в качестве входных данных, и начать его анализ. Как только этот разбор закончен, я хочу дать YACC команду вернуться к файлу и продолжить разбор сразу после выражения include. Я ограничу уровень глубины включения до одного.

Ответы [ 2 ]

8 голосов
/ 16 февраля 2010

Руководство по флексам описывает, как это сделать, используя yypush_buffer_state () и yypop_buffer_state ().

Здесь - раздел официального руководства по использованию нескольких входных буферов. Вот пример кода.

5 голосов
/ 16 февраля 2010

Нормально общаться между лексической и синтаксической фазами вашего процессора.

Итак, узнайте синтаксис директивы include в вашем парсере (или, чтобы упростить задачу, просто узнайте его в лексере) и выполните переключение на лексическом уровне.

Например, вот простой язык, который распознает стандартные строки ввода, содержащие ab или cd или .file. Когда он видит .someString, он открывает someString как включаемый файл и затем возвращается к чтению стандартного ввода.

%{
#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;
}

И когда мы его запустим ...

$ 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
$ 
...