Во время разбора, если я сталкиваюсь с токеном включения, я хочу дать указание YACC открыть файл, указанный как ввод, и начать разбор этого. Как только этот синтаксический анализ завершен, я хочу дать указание YACC вернуться к файлу и продолжить синтаксический анализ непосредственно после выражения include. Я ограничу уровень глубины включения до единицы.
Как я могу реализовать конструкторы #include с Flex и YACC?
Ответ 1
В руководстве flex описано, как это сделать, используя yypush_buffer_state() и yypop_buffer_state(). Здесь - это раздел руководства по использованию нескольких входных буферов. Существует несколько примеров кода.
Ответ 2
Это нормально для связи между лексической и синтаксической фазами вашего процессора.
Итак, узнайте синтаксис директивы 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
$