Bison
bison — генератор анализаторов синтаксиса (parser) выражений (заменяет yacc — Yet Another Compiler Compiler). Что же делает bison? Это программа, генерирующая программу, анализирующую структуру текстового файла. Вместо написания собственной программы пользователь указывает, как соотносятся объекты, и основываясь на данных правилах, создается анализатор. Существует множество примеров анализа синтаксиса, например калькулятор.
Человек легко получит результат 7. Почему? Because of the structure. Наш мозг знает, как интерпретировать выражение. Компьютер этого не знает, и bison инструмент, представляющий выражение компьютеру в следующем виде:
Начиная с вершины дерева и обрабатывая 2 and 3, соединенных знаком умножения, компьютер перемножает 2 и 3. Результат умножения запоминается и следующее, что обрабатывается — 2*3 и 1, соединенные знаком сложения. Сложение 1 и предыдущего результата дает 7. Все составные выражения могут быть преобразованы в подобное дерево и вычислены. Конечно же, bison используется не только в калькуляторах.
Bizon365 обучение. Как пользоваться Бизон 365. Настройка урок 1
yacc
Мы написали скрипт bash с именем yacc, вызывающий bison с опцией -y. Это необходимо для совместимости с программами, использующими yacc вместо bison.
Зависимости Bison
Последняя проверка: версия 1.31.
Bash: sh
Binutils: ar, as, ld, ranlib
Diffutils: cmp
Fileutils: chmod, cp, install, ln, ls, mkdir, mv, rm, rmdir
Gcc: cc, cc1, collect2, cpp0, gcc
Grep: egrep, fgrep, grep
Make: make
Sed: sed
Sh-utils: basename, dirname, echo, expr, hostname, sleep, uname
Texinfo: install-info
Textutils: cat, head, tr, uniq
Назад | Домой | Вперед |
Binutils | Наверх | Bzip2 |
Источник: www.linuxlib.ru
Bison что это за программа
Библиотека сайта rus-linux.net
Linux From Scratch (version 6.8) | ||
Назад | Глава 6. Установка программ базовой системы | Вперед |
6.25. Пакет Bison-2.4.3
В пакете Bison находится генератор парсеров.
Приблизительное время сборки: 1,1 SBU
Требуемое дисковое пространство: 19,2 MB
6.25.1. Установка пакета Bison
Подготовьте пакет Bison для компиляции:
Как провести вебинар через сервис Бизон 365 (Bizon365)
./configure —prefix=/usr
Пакет Bison настраивается так, что в случае, когда программа bison еще не указана в переменной $PATH, пакет будет собираться без поддержки интернационализации сообщений об ошибках. Это можно исправить следующим образом:
echo ‘#define YYENABLE_NLS 1’ >> lib/config.h
make
Чтобы проверить результаты (потребуется приблизительно 0,5 SBU), наберите:
make check
make install
6.25.2. Описание пакета Bison
Установленные программы: bison и yacc
Установленные библиотеки: liby.a
Установленные директории: /usr/share/bison
Краткое описание
Создает из серии правил программу анализа структуры текстовых файлов; Bison является заменой для Yacc (Yet Another Compiler Compiler — Еще один компилятор компиляторов)
Программа-обвертка (wrapper) для bison, необходимая в программах, в которых вместо bison все еще вызывает yacc; вызывает команду bison с параметром -y
Библиотека Yacc, в которой находятся Yacc-совместимые реализации функций yyerror и main ; этой библиотекой, как правило, пользуются редко, но она требуется в соответствии с POSIX
Источник: rus-linux.net
Парсим Python код с помощью Flex и Bison
Уже около двух лет я участвую в OpenSource проекте SourceAnalyzer, и вот появилась необходимость написать парсер для языка Python, который должен уметь строить граф вызовов (Call Graph) и граф зависимостей классов (Class Graph Dependency). Если точнее, граф строится с помощью других инструментов, а парсер должен лишь подготовить для этих инструментов данные.
Процесс работы над парсером был довольно занятным и мне бы хотелось поделиться с вами приобретенным опытом, а также поведать о некоторых подводных камнях, которые встретились на этапе разработки.
Терминология
Если вы уже работали с граматиками и знаете, как устроен компилятор, смело шагайте в следующий абзац, остальным Welcome.
- Анализ входного потока и разбиения его на токены (Лексический анализ)
- Разбор токенов набором синтаксических правил (Синтаксический Анализ)
3 + 4 * 15
Построим правила преобразования входного потока:
[1-9]* -> NUMBER + -> PLUS * -> MULT
Таким образом, после лексического анализа получим:
NUMBER(3) PLUS(+) NUMBER(4) MULT(*) NUMBER(15) EQUAL(=)
Далее следует пример грамматики, с помощью которой впоследствии, применяя правила, можно сделать разбор выражения:
exp: NUMBER | exp sign exp sign: PLUS | MULT * / + 15 / 3 4
В данном примере NUMBER, MULT, PLUS — по определению терминалы, или токены, определенные на этапе лексического анализа. expr, sign — не терминалы, так как являются составными единицами.
Данное введение не является сколь-либо исчерпывающим, поэтому за теорией следует обратиться к книге Flex #include %> %% start printf(«STARTn»); stop printf(«STOPn»); . ; /* игнорируем все остальное */ %%
Как скомпилировать данный пример:
% flex lexer.l gcc lex.yy.c -o lexer -lfl
ОК, теперь определимся с токенами. В грамматике мы уже использовали следующие:
CLASS, COLON, COMMA, DEF, DOT, ID, LBRACE, MESSAGE, RBRACE, OTHER, STAR
Еще нам понадобится DEFINED — зарезервированные слова Python.
Краткий разбор: комментарии, пустые строки и пробелы игнорируем. Все остальное (так называемый, поток токенов) отдаем на вход Bison.
Набор символов, который находит паттерн (например, по шаблону [ t]+ ), помещается в yytext . По умолчанию yytext — это char pointer, но если добавить ключ -l при компиляции, то yytext будет восприниматься как char array. Перед тем, как вернуть бизону токен, запишем определенное по шаблону значение в переменную yylval (подробнее — далее).
Самое время перейти к описанию грамматики для Бизона.
Bison
Я снова отсылаю вас к данной статье, потому что те, кто не может составить грамматику для бизона, без труда научатся с помощью материала по данной ссылке. Ну а кто умеет — отлично, идем дальше.
Итак, заглядывая в пункт статьи Грамматика, попробуем составить грамматику для бизона:
В правиле Bison каждая лексема имеет значение. Значение группы, собираемой текущим правилом, хранится в $ , значения остальных лексем — в $1, $2, …
test_rule: token1, token2, token3; $$ $1 $2 $3
Значение, хранящееся в $n есть не что иное, как значение переменной yylval в момент, когда лексер возвращает токен.
Запуская Bison с параметром -d , генерируется файл имя.tab.h , он содержит макроопределения типов лексем, которые используются в лексере. Каждой лексеме соответствует число > 257 . Данный файл следует включить в лексер, что мы и сделали: #include «pyparser.tab.h» .
Как работает анализатор. Происходит вызов функции yyparse из main , которая запускает анализ — читает лексемы, производит какие-то действия и завершает работу, если встречает конец входного текста ( return 0 ) или синтаксическую ошибку ( return 1 ).
Пробуем скомпилировать и затестить то, что имеем:
% bison -d pyparser.y —verbose flex lexer.l g++ -c lex.yy.c pyparser.tab.c g++ -o parser lex.yy.o pyparser.tab.o -ll -ly
Пример теста:
class Foo: pass class Test(Foo): class Test2: def __init__(self): pass def foo(): pass
>> CLASS: Foo() >> CLASS: Test(Foo) >> CLASS: Test2() >> FUNC: __init__(self) >> FUNC: foo()
В принципе, верно, хотя и не совсем. Хотелось бы видеть “полное имя” в определении функции, то есть:
>> CLASS: Foo() >> CLASS: Test(Foo) >> CLASS: Test2() >> FUNC: Test.Test2.__init__(self) >> FUNC: Test.Test2.foo()
Для этого поступим следующим образом: заведем стек, в который будем добавлять имя текущего класса. Как только встречается определение функции — постепенно достаем из стека имена классов, конкатенируя с именем функции. Если встречается новый класс глубже по уровню — добавляем в стек, иначе удаляем из стека элементы, пока не дойдем до текущего уровня вложенности (и еще на единицу меньше), и добавляем новый класс в стек.
Идея и реализация далее.
Особенности Python
Очевидная проблема — узнать уровень вложенности. Как известно, в Python для этого используется табуляция (или пробелы). Поэтому надо хранить текущий отступ в какой-то глобальной переменной, доступной и анализатору, и лексеру. Руководство Bison говорит, что функция yyparse ожидает, что положение только что разобранной лексемы в тексте находится в глобальной переменной yylloc .
yylloc — это структура из четрыех элементов: first_line, first_column, last_line и last_column . В first_line будем хранить номер текущей строки (пригодится для отладки, да и входит в мою задачу), в last_column будем хранить отступ.
Вносим изменения в код. В лексере определим тип переменной yylloc и значение по умолчанию для номера строки:
extern YYLTYPE yylloc; #define YY_USER_INIT yylloc.first_line=1; //иначе =0
Когда встречаем новую строку:
yylloc.first_line++; yylloc.last_column = 0; isNewLine = true;
Если строка начинается с пробелов:
if (isNewLine == true 0 == yyleng % SPACES_PER_INDENT) yylloc.last_column = yyleng / SPACES_PER_INDENT; isNewLine = false;
yyleng — длина найденной шаблоном лексемы. SPACES_PER_INDENT по умолчанию зададим равным 4 (по стандарту).
Если строка начинается с символа табуляции:
if (isNewLine == true) yylloc.last_column = yyleng; isNewLine = false;
Теперь подкорректируем подсчет строк. В питоне есть тройные кавычки, используются обычно для длинного комментария документации. Для игнора напишем функцию:
static string skipMessage(string _ch) < string ch; string str = _ch; _ch = _ch[0]; bool skip = false; int count = 1; for(;;ch = yyinput()) < str += ch; if (ch == _ch)< if (count == 3) return str; else count++; >else count = 1; if («n» == ch || «r» == ch) yylloc.first_line++; > >
Тут, на самом деле, можно было обойтись регулярным выражением, но тогда не получится верно определить номер строки — мы не сможем узнать количество съеденных регэкспом строк (или сможем? если да — пишите способ).
Также не забываем игнорить строку комментариев:
static void skipComments() < for(char ch = yyinput();;ch = yyinput()) < if (‘