
- •Содержание
- •1.Рабочая программа
- •2.Модуль Вводный
- •3.Модуль Формальные грамматики и языки
- •3.1.Языки и цепочки символов. Способы задания языков
- •3.1.1.Цепочки символов. Операции над цепочками символов
- •3.1.2.Понятие языка. Формальное определение языка
- •3.1.3.Способы задания языков
- •3.1.4.Синтаксис и семантика языка
- •3.2.Определение грамматики
- •3.2.1.Особенности языков программирования
- •3.2.2.Определение грамматики. Форма Бэкуса—Наура
- •3.2.3.Принцип рекурсии в правилах грамматики
- •3.2.4.Другие способы задания грамматик
- •3.3.Классификация языков и грамматик
- •3.3.1.Классификация грамматик
- •3.3.2.Классификация языков
- •3.4.Контроль
- •4.Модуль Распознаватели, механизм вывода цепочек символов
- •4.1.Цепочки вывода. Сентенциальная форма.
- •4.1.1.Сентенциальная форма грамматики. Язык, заданный грамматикой
- •4.1.2.Левосторонний и правосторонний выводы
- •4.1.3.Однозначные и неоднозначные грамматики
- •4.1.4.Эквивалентность и преобразование грамматик
- •4.2.Распознаватели. Задача разбора
- •4.2.1.Общая схема распознавателя
- •4.2.2.Виды распознавателей
- •4.2.3.Классификация распознавателей по типам языков
- •4.3.Контроль
- •5.Модуль Регулярные грамматики и языки
- •5.1.Регулярные языки и грамматики
- •5.2.Леволинейные и праволинейные грамматики. Автоматные грамматики
- •5.3.Алгоритм преобразования регулярной грамматики к автоматному виду
- •5.4.Конечные автоматы
- •5.4.1.Определение конечного автомата
- •5.4.2.Детерминированные и недетерминированные конечные автоматы
- •5.4.3.Преобразование конечного автомата к детерминированному виду
- •5.5.Контроль
- •6.Модуль Контекстно-свободные грамматики и языки
- •6.1.Контекстно-свободные языки
- •6.1.1.Распознаватели кс-языков. Автоматы с магазинной памятью. Определение мп-автомата
- •6.2.Классы кс-языков и грамматик. Класс ll(k) грамматик.
- •6.3.Принципы построения распознавателей для ll(k)-грамматик
- •6.4.Левая факторизация
- •6.5.Удаление левой рекурсии
- •6.6.Алгоритм разбора для ll(1)-грамматик
- •6.7.Алгоритм построения множества first(1,a)
- •6.8.Алгоритм построения множества follow(1,a)
- •6.9.Восходящие распознаватели кс-языков без возвратов
- •6.9.1.Определение lr(k)-грамматики
- •6.10.Принципы построения распознавателей для lr(k)-грамматик
- •6.10.1.Грамматики простого предшествования
- •6.11.Распознаватели для lr(0) и lr(1) грамматик
- •6.11.1.Распознаватель для lr(0)-грамматики
- •6.11.2.Распознаватель для lr(1) грамматики
- •6.12.Контроль
- •7.Модуль Инструментальные средства для построения трансляторов
- •7.1.Инструментальные средства для построения компиляторов
- •7.1.1.Построитель лексических анализаторов Lex
- •7.2.Контроль
- •8.Модуль Особенности программирование трансляторов
- •8.1.Использование значений произвольных типов, алгоритм разбора
- •8.1.1.Алгоритм синтаксического разбора
- •8.1.2.Семантический стек
- •8.2.Неоднозначности и конфликты
- •8.3.Старшинство операций
- •8.4.Дополнительные возможности программ yacc и lex
- •8.4.1.Обработка ошибок
- •8.5.Совместное использование lex и yacc
- •8.5.1.Кодировка лексем и интерфейс
- •8.5.2.Сборка yacc-программ
- •8.6.Советы по подготовке спецификаций
- •8.6.1.Стиль
- •8.6.2.Использование левой рекурсии
- •8.6.3.Уловки анализа лексики
- •8.6.4.Входной синтаксис yacc'а
- •8.7.Контроль
- •9.Модуль Заключение
- •10.Обеспечение лабораторного практикума
- •11.Дополнительная информация. Примеры
- •11.4.Пример простейшего интерпретатора формул
- •11.5.Простой пример
- •11.6.Более сложный пример
- •11.7.Генераторы лексических и синтаксических анализаторов
- •11.8.Генераторы лексических и синтаксических анализаторов на java
- •11.9.Пакеты для разработки компиляторов
- •Список сокращений
- •Литература
- •Приложения Приложение 1. Учебно–методическая карта дисциплины “Системное программное обеспечение. Синтаксические анализаторы”
- •Приложение 2. Вопросы для зачета по дисциплине “Системное программное обеспечение. Синтаксические анализаторы”
- •Приложение 3. Методические указания к лабораторным работам по дисциплине «Системное программное обеспечение. Синтаксические анализаторы»
- •Порядок выполнения работы:
- •Контрольные вопросы
- •Лексический анализатор lex. Анализ структуры программ
- •Краткая теория:
- •Рассмотрим примеры:
- •Порядок выполнения работы:
- •Контрольные вопросы
- •Лексический анализатор lex, синтаксический анализатор yacc. Алгебраические вычисления
- •Краткая теория:
- •Порядок выполнения работы:
- •Контрольные вопросы
- •Лексический анализатор lex и синтаксический анализатор yacc. Изображение геометрических фигур
- •Краткая теория:
- •Создание метафайла и работа сним
- •Порядок выполнения работы:
- •Контрольные вопросы
- •Приложение 4. Организация рейтингового контроля по дисциплине «Системное программное обеспечение. Синтаксические анализаторы»
11.4.Пример простейшего интерпретатора формул
%token NAME
%left '+' '-'
%left '*' '/'
%%
s : e { printf( "%d\n", $1 ); }
e : e '+' e { $$ = $1 + $3; }
| e '-' e { $$ = $1 - $3; }
| e '*' e { $$ = $1 * $3; }
| e '/' e { $$ = $1 / $3; }
| '(' e ')'{ $$ = $2; }
| NAME ;
%%
#include
#include
int yylex() {
register int c, v;
while ((c = getchar()) == ' ');
if (isdigit(c)) {
for( v=c-'0'; isdigit( c=getchar() ); ) v=v*10+c-'0';
ungetc( c, stdin );
yylval = v;
return( NAME );
} else if( c=='\n' ) {
return( 0 );
} else {
yylval = c;
return( yylval=c );
}
}
int main() { for(;;) yyparse(); return 0; }
int yyerror(char *mes) { printf( "%s\n", mes ); return 0; }
11.5.Простой пример
Этот пример - полная yacc-спецификация, реализующая небольшой калькулятор; калькулятор имеет 26 регистров, помеченных буквами от a до z, и обрабатывает арифметические выражения, построенные при помощи операций
+, -, *, /, % (остаток от деления), & (побитное и), |
(побитное или)
и присваиваний. Если на вход калькулятору дается присваивание, оно выполняется; в противном случае выводится значение выражения. Как и в языке C, целая константа, если она начинается с 0 (нуль), трактуется как восьмеричная, иначе - как десятичная.
yacc-спецификация калькулятора содержит примеры неоднозначностей в грамматике, операций с различным приоритетом, демонстрирует несложную обработку ошибок. Наиболее упрощены лексический анализатор, который здесь гораздо примитивнее, чем в большинстве других применений, и выдача результата, выполняемая построчно. Отметим, что разбор десятичных и восьмеричных чисел осуществляется в грамматических правилах. Возможно, с этим лучше справился бы лексический анализатор.
%{
#include
#include
int regs [26];
int base;
%}
%start list
%token DIGIT LETTER
%left '|'
%left '&'
%left '+' '-'
%left '*' '/' '%'
%left UMINUS /* устанавливает приоритет унарного минуса */
%% /* начало секции правил */
list : /* пусто */
| list stat '\n'
| list error '\n'
{
yyerrok;
}
;
stat : expr
{
(void) printf ("%d\n", $1);
}
| LETTER '=' expr
{
regs [$1] = $3;
}
;
expr : '(' expr ')'
{
$$ = $2;
}
expr '+' expr
{
$$ = $1 + $3;
}
expr '-' expr
{
$$ = $1 - $3;
}
expr '*' expr
{
$$ = $1 * $3;
}
expr '/' expr
{
$$ = $1 / $3;
}
expr '/' expr
{
$$ = $1 / $3;
}
expr '%' expr
{
$$ = $1 % $3;
}
expr '&' expr
{
$$ = $1 & $3;
}
expr '|' expr
{
$$ = $1 | $3;
}
'-' expr %prec UMINUS
{
$$ = - $2;
}
LETTER
{
$$ = regs[$1];
}
number
;
number : DIGIT
{
$$ = $1; base = ($1==0) ? 8 : 10;
}
number DIGIT
{
$$ = base * $1 + $2;
}
;
%% /* начало секции подпрограмм */
int yylex () /* процедура лексического анализа */
{ /* возвращает значение LETTER для */
/* строчной буквы, yylval = от 0 до 25, */
/* возвращает значение DIGIT для цифры, */
/* yylval = от 0 до 9, для остальных */
/* символов возвращается их значение */
int c;
/* пропуск пробелов */
while ((c = getchar ()) == ' ')
;
/* c - не пробел */
if (islower (c)) {
yylval = c - 'a';
return (LETTER);
}
if (isdigit (c)) {
yylval = c - '0';
return (DIGIT);
}
return (c);
}