LEM: C++ библиотека поисковой машины - лексеры и парсеры

Базовый лексер - класс Base_Parser<...> (см. в файле base_lexer.h). Читает символы из абстрактного потока (любой потомок класса BaseStream). Позволяет читать поток полексемно - с помощью метода read(), который возвращает объект класса SrcToken<...>. Если лексеру задана таблица токенов (пар лексема-код), то читаемые лексемы токенизируются (код токена можно получить с помощью метода SrcToken::GetToken()). В любой момент можно запомнить положения курсора чтения в файле (объект класса SourceState, возвращается методами Base_Parser::tellp() и SrcToken::GetBegin()), и в последующем установить курсор чтения снова в эту позицию (метод Base_Parser::seekp(...)).

Для удобства использования в различных анализаторах текста (компиляторах прежде всего) класс Base_Parser постоянно отслеживает номер строки и номер символа в строке, где происходит чтение лексемы. Есть два способа узнать эти значения. Во-первых, вызвав Base_Parser::tellp(). Возвращенный объект (класса SourceState) содержит поля номера строки и символа в строке - они возвращаются методами ::GetLine() и  ::GetSymbolPos(). Также можно с помощью метода ::GetPos() определить позицию символа в файле.

Однако нет гарантии, что полученная таким образом позиция указывает на начало лексемы - вполне может быть, что курсор чтения стоит на пробеле или конце строки.

Если лексема считана, то позицию ее начала можно определить, вызвав метод SrcToken::GetBegin(). Он опять-таки возвращает объект класса SourceState, но уже гарантировано указывающий на начало лексемы.

Будучи шаблоном, класс Base_Parser и сопутствующие классы существуют в двух главных разновидностях: для однобайтовых символов char, и для строк из UNICODE-символов wchar_t. Кроме этого, для класса задается максимальное число символов в каждой лексеме (подробности - в описании класса BaseCString).

Для удобства использования объявлены специализации этого шаблона:

Text_Parser - лексер для char-символов, длина лексемы ограничена значением глобального макроса LEM_CSTRING_LEN (подробнее смотри описание шаблона BaseCString<...>).

UTextParser - лексер для wchar_t - символов, длина лексемы равна LEM_CSTRING_LEN.

Text_NC_Parser - шаблон для некэширующего лексера. Особенность его заключается в том, что в отличие от Base_Parser'а он не запоминает символы во внутреннем кэше, а считывает символы по одному из входного потока по мере необходимости.

Печать сообщений об ошибках в обрабатываемом тексте является важной для любых парсеров функцией. Удобная и информативная печать позволяет быстро устранять ошибки. В Проекте (в компиляторе Ygres) используется такой подход.

Пусть есть токен t (класса AToken), на котором парсинг прерывается из-за ошибки. Кусок кода:

Text_Parser txtfile;
...
AToken t = txtfile.read();
...
txtfile.seekp(t.GetBegin()); // позиционирование на начало токена t
txtfile.ToLineBegin(); // перемещаемся в начало текущей строки с токеном t
txtfile.PrintLine( &merr ); // печатаем строку с токеном в стандартный поток

выведет на печать полностью строку, содержащую токен, вызвавший ошибку парсинга. Более развитые средства отображения ошибок представлены в классе lem::Iridium::Macro_Parser.

Более высокий уровень - макропарсер, представленный классом Macro_Parser в пространстве имен lem::Iridium (см. файл macro_parser.h). Он читает с помощью Baser_Parser все лексемы из абстрактного потока, производит макроподстановки, выполняет макродирективы, и результат сохраняет как вектор лексем-токенов. Все эти манипуляции происходят в методе Open(...). Затем можно считывать запомненные лексемы одну за другой (метод read() возвращает BethToken), запоминать текущую позицию курсора чтения (метод tellp() возвращает BSourceState).

Класс Macro_Parser работает только с UNICODE-символами.

Подробное описание макродиректив Macro_Parser'а можно прочитать здесь.

Кроме того, есть отдельные реализации парсеров для ini-файлов разных форматов (см. здесь).

  © Козиев Илья 2019