#c #parsing #packcc
#c #Синтаксический анализ #packcc
Вопрос:
Я сделал минимальный пример для генератора синтаксического анализа Packcc. Здесь анализатор должен распознавать числа с плавающей точкой или целые числа. Я пытаюсь напечатать местоположение обнаруженных чисел. Для простоты здесь нет количества строк / столбцов, только число из «ftell».
%auxil "FILE*" # The type sent to "pcc_create" for access in "ftell".
test <- line
/
_ EOL
line <- num _ EOL
num <- [0-9] '.'[0-9] {printf("Float at %lin", ftell(auxil));}
/
[0-9] {printf("Integer at %lin", ftell(auxil));}
_ <- [ t]*
EOL <- 'n' / 'rn' / 'r'
%%
int main()
{
FILE* file = fopen("test.txt", "r");
stdin = file;
if(file == NULL) {
// try to open.
puts("File not found");
}
else {
// parse.
pcc_context_t *ctx = pcc_create(file);
while(pcc_parse(ctx, NULL));
pcc_destroy(ctx);
}
return 0;
}
Файл для анализа может быть
2.0
42
Команда может быть
packcc test.peg amp;amp; cc test.c amp;amp; ./a.out
Проблема в том, что значение курсора всегда находится в конце файла, независимо от номера
положение.
Комментарии:
1.
stdin = file;
не работает во многих средах. Посмотритеman stdin
, используете ли вы Linux. Цитата: «Поскольку символыstdin
,stdout
иstderr
указаны как макросы, присвоение им не подлежит переносу. Стандартные потоки можно настроить так, чтобы они ссылались на разные файлы с помощью библиотечной функцииfreopen(3)
, специально введенной для переназначенияstdin
,stdout
иstderr
.»2. Packcc предоставляет специальную переменную «$ 0e» . Если я использую его вместо «ftell», результат будет лучше, курсор будет остановлен сразу после токена. Но я получаю странное предупреждение «[-Wimplicit-int]» для функции printf, независимо от того, использую ли я %d или %li… Вот почему я пока не отвечаю на свой вопрос.
3. Вы
#include <stdio.h>
? Если нет, вы, вероятно, получите это предупреждение (и некоторые другие). Если проблема не в этом, задайте новый вопрос с достаточной детализацией, чтобы можно было ответить, не гадая, что вы сделали или что вы видели, когда вы это делали.
Ответ №1:
Позиции могут быть получены с помощью специальных переменных. В приведенном выше примере «ftell» должен быть заменен на «$ 0s» или «$ 0e». $ 0s — это начало согласованного шаблона, $ 0e — это конец согласованного шаблона.
Ответ №2:
Не глядя более внимательно на сгенерированный код, может показаться, что анализатор настаивает на чтении всего текста в память перед выполнением любого из действий. Это кажется ненужным для этой грамматики, и это, конечно, не так, как будет работать типичный сгенерированный лексический сканер. Это особенно странно, поскольку кажется, что сгенерированный сканер использует getchar
для чтения по одному байту за раз, что не очень эффективно, если вы планируете прочитать весь файл.
Честно говоря, вы также не смогли бы использовать ftell
сканер, созданный с помощью flex, если только вы не переведете сканер в интерактивный режим. (Оригинальный AT amp; T lex, который также считывает по одному символу за раз, даст вам разумную ценность от ftell
. Но вы вряд ли найдете сканер, построенный с его помощью.)
Flex даст вам неправильный ответ, потому что он намеренно считывает свои входные данные фрагментами размером с его буфер, обычно 8 кб. Это намного эффективнее, чем чтение по символам за раз. Но это не работает для интерактивных сред — например, где вы выполняете синтаксический анализ непосредственно из пользовательского ввода — потому что вы не хотите читать дальше конца строки, введенной пользователем.
Вам нужно спросить того, кто поддерживает packcc, каков их предполагаемый подход к поддержанию исходного положения. Возможно, у них есть что-то встроенное.
Комментарии:
1. Я удалил знаки плюс в первом правиле, и функции ftell дали ожидаемый результат.
2. @Ploumploum: Интересно. Но тогда как вы анализируете входные данные с более чем одним числом? (Риторический вопрос; на самом деле я не планирую использовать этот генератор синтаксического анализа.)
3. Вы должны использовать принципы грамматики выражений синтаксического анализатора. Это альтернатива EBNF. PackCC имеет улучшенную привязку, поскольку поддерживает левую рекурсию. Что-то вроде: строка <- (строка _ число / num) _ EOL (не тестировалось)
4. Мой предыдущий пост неверен извините, после некоторых тестов рабочая грамматика выглядит так: test <- statement _ EOL {puts(«OK»);} / _ EOL затем statement <- statement _ num / num и затем вы можете анализировать строки с несколькими числами.
5. @Ploumploum: Если у вас есть строка с двумя числами, они оба отображаются в одной и той же позиции столбца. Но, может быть, этого достаточно:(