Flex может генерировать три вида лексеров:
Неинтерактивные лексеры являются наиболее эффективными; они читают входной буфер одновременно. Это отлично подходит для разбора файлов, но это раздражает для разбора ввода с консоли, особенно когда нужно ответить на каждую напечатанную строку. Интерактивные лексеры избегают этой проблемы, читая ввод по одному символу за раз, так что токен сообщается как можно скорее. Но это может быть неэффективно для ввода с большими токенами.
Лексер по умолчанию проверяет, является ли его ввод консольным, и использует эту информацию для выбора между интерактивной и неинтерактивной обработкой буфера. Единственная проблема этой стратегии состоит в том, что стандартная библиотека C не предоставляет никакого способа определить, является ли входной поток консольной. Unix (-подобные) системы имеют функцию, которая отвечает на этот вопрос, но она не работает со стандартными потоками C FILE*
; это требует основного "номера файла". Функция fileno
извлекает основной номер файла из FILE*
, но, очевидно, это не стандартная функция C.
Так что если у вас есть лексер по умолчанию, он должен вызвать fileno
. Тем не менее, fileno
не объявляется ни в одном стандартном заголовке, если вы не #define
макрос для проверки возможностей. Но вы должны определить эти макросы в самом начале C-программы, что трудно сделать, когда C-программа генерируется автоматически. Самое простое решение - добавить определение макроса в командной строке компилятора, используя параметр -D
:
g++ -c `llvm-config --cppflags` -D_POSIX_C_SOURCE -std=c++11 -o tokens.o tokens.cpp
Это только один из возможных макросов, который вы можете использовать; Я выбрал его здесь, потому что он в man fileno
, но я обычно использую -D_XOPEN_SOURCE=700
, который запрашивает интерфейсы для более новой версии Posix. Другая возможность - _GNU_SOURCE
, которая позволяет заголовкам Gnu довольно хорошо включать все, включая специфические для Gnu функции расширения.
В моей системе (linux) llvm-config --cppflags
включает -D_GNU_SOURCE
, но это не имеет значения, потому что текущие версии g ++ и clang ++ автоматически определяют _GNU_SOURCE
для целей C ++. Видимо, это не так с Cygwin. Смотрите, например:
оба варианта предлагают изменить -std=c++11
на -std=gnu++11
.
В качестве альтернативы можно обойти проблему, запросив неинтерактивный лексер, либо с помощью параметра командной строки flex:
flex --batch -o tokens.cpp tokens.l parser.hpp
Или добавив
%option batch
в ваш гибкий файл ввода. См. Руководство по Flex
(Очевидно, не запрашивайте пакетный лексер, если вы пишете интерактивный калькулятор. В этом случае вы, вероятно, захотите запросить всегда интерактивный лексер.)