2015-10-14 3 views
0

Я пишу lexer для препроцессора C среди некоторых других синтаксисов Си. В рамках этого я должен определить имена файлов в #include. Проблема, в которой я застрял, заключается в определении имени файла. Имя файла содержит две части: базовое имя и расширение. Базовое имя можно идентифицировать с помощью регулярного выражения «IDENTIFIER» lexer; так может быть "." разделяя их.Конкатенированные жетоны в Lex

Существует отдельное регулярное выражение для «IDENTIFIER» и для «.». Для имени файла я рассматриваю возможность написания другого регулярного выражения, которое будет в основном конкатенацией «IDENTIFIER», «.». и "h". Мой вопрос в том, что если я напишу регулярное выражение для имени файла, как я описал; как он будет обрабатываться. Учитывая тот факт, что уже существует правило для отдельных токенов; вместо идентификации имени файла он идентифицирует 3 токена (IDENTIFIER, DOT и IDENTIFIER) или будет ли он идентифицировать имя файла?

ответ

1

Существует, насколько я вижу, отсутствие веской причины для лексера препроцессора для просмотра имени файла в директиве include как ничего, кроме непрозрачной последовательности символов. Точное имя не относится к препроцессору; он может не содержать расширения или более одного . (при условии, что операционная система разрешает это, что в большинстве случаев делает в наши дни); он может включать специальные символы, такие как слэши; это может быть число; и т. д.

Кроме того, обработка угловых скобок и кавычек является особенным в аргументе директивы include. Следовательно, обычным способом решения включенных директив является использование контекстно-зависимого шаблона, например, с использованием (f) lex start conditions.

Поскольку новые строки также обрабатываются специально во всех директивах препроцессора, вам обычно понадобится контекстно-зависимый шаблон для них.

Грубый эскиз с использованием синтаксиса flex. Множество деталей не учтены.

%x PP_DIRECT PP_ARG PP_INCLUDE 
%% 

^[[:blank:]]*"#" { BEGIN(PP_DIRECT); } 
<PP_DIRECT>include { BEGIN(PP_INCLUDE); return T_INCLUDE; } 
    /* You might want to recognize other include directives as 
    * specific keyword tokens. In particular, the scanner needs 
    * to be aware of conditionals, since it might have to put itself 
    * into a mode where it skips to the matching #endif 
    */ 
<PP_DIRECT>[[:alpha:]]+ { BEGIN(PP_ARG); /* ... */ } 
    /* Normally newlines are not returned to the parser, but here we do. */ 
<PP_ARG>\n   { BEGIN(INITIAL); return '\n'; } 
    /* This should actually be done in a previous step */ 
<PP_ARG>\\\n  /* IGNORE */ 
<PP_INCLUDE>["][^"]*["] { yytext[yyleng-1] = 0; 
          do_include(yytext+1); 
          /* Really, should check that only whitespace follows */ 
          BEGIN(PP_ARG); 
         } 
<PP_INCLUDE>[<][^>]*[>] { yytext[yyleng-1] = 0; 
          do_system_include(yytext+1); 
          BEGIN(PP_ARG); 
         } 
+0

спасибо. Я не знал о контекстно-зависимой грамматике, и предыдущие поисковые запросы были бесполезны. Спасибо alot – Sharad

+0

@sharad: вы также можете посмотреть раздел [flex manual для нескольких буферов] (http://flex.sourceforge.net/manual/Multiple-Input-Buffers.html#Multiple-Input-Buffers), который содержит пример кода для использования стека буферов для реализации функциональности «включить». – rici

Смежные вопросы