Лекции по конструированию компиляторов глава 2 лексический анализ


Содержание

Основы конструирования компиляторов

Автор Серебряков В.А. Галочкин М.П.
Издательство Едиториал УРСС
Год 1999
Формат PDF

Предлагаемая вниманию читателя книга основана на курсе лекций, прочитанных на факультете вычислительной математики и кибернетики Московского государственного университета и факультете управления и прикладной математики Московского физико-технического института в 1991-1999 гг. Авторы надеются, что издание книги восполнит существенный пробел в литературе на русском языке по разработке компиляторов.

Содержание книги представляет собой «классические» разделы предмета: лексический и синтаксический анализ, организация памяти компилятора (таблицы символов) и периода исполнения (магазина), генерация кода. Рассматриваются некоторые средства автоматизации процесса разработки трансляторов, такие как LEX, YACC, СУПЕР, методы генерации оптимального кода. Сделана попытка на протяжении всего изложения провести единую «атрибутную» точку зрения на процесс разработки компилятора. В книге не затрагиваются чрезвычайно важные вопросы глобальной оптимизации и разработки компиляторов для машин с параллельной архитектурой. Авторы надеются восполнить эти пробелы в будущем.

Книга будет полезной как студентам и аспирантам программистских специальностей, так и профессионалам в этих областях.

Основы проектирования и конструирования — курс лекций

Категория: Курсы лекций
Рубрика: Производство и технологии
Размер файла: 372 Kb
Количество загрузок:
Количество просмотров:
Описание работы: курс лекций на тему Основы проектирования и конструирования
Подробнее о работе: Читать или Скачать
ВНИМАНИЕ: Администрация сайта не рекомендует использовать бесплатные Курсы лекций для сдачи преподавателю, чтобы заказать уникальные Курсы лекций, перейдите по ссылке Заказать Курсы лекций недорого
Смотреть
Скачать
Заказать

Федеральное агентство по образованию

Государственное образовательное учреждение высшего

Основы проектирования и конструирования

1.2. Задачи конструирования

1.3. Общие сведения о машинах и механизмах

КОНСТРУИРОВАТЬ [лат. construere] — создавать конструкцию чего-л.

КОНСТРУКТЙВНЫЙ — 1) относящийся к конструкции; 2) такой, который можно положить в основу чего-л., плодотворный.

КОНСТРУКТОР — 1) лицо, занимающееся созданием конструкций различных устройств (машин, механизмов, сооружений и т.п.) или их отдельных частей; 2) детская игра, представляющая собой набор деталей, из которых можно собирать разные предметы, машины, сооружения.

КОНСТРУКЦИЯ [лат. constructio] — 1) строение, устройство, взаимное расположение частей какого-л. предмета, машины, прибора, сооружения и т.п., определяющееся его назначением; 2) сооружение или его часть, характеризующиеся каким-л. признаком, напр. железобетонные, деревянные, монолитные, сборные конструкции; 3) грам. сочетание слов, выступающее в качестве одной синтаксической единицы.

ПРОЕКТ [ 1 — 1) составлять проект 1; 2) предполагать сделать что-л., намечать план.

ПРОЕКТИРОВАТЬ 2 — 1) геом. отображать какую-л. фигуру или предмет на плоскость, чертить проекцию; 2) то же, что проецировать.

Решение задачи достижения наивысшего уровня науки, техники, экономики и производства будет способствовать увеличению производительности общественного труда и уменьшению удельного расхода энергии и сырья на единицу произведенной продукции. Основной задачей машиностроения является обеспечение быстрорастущего населения Земли разного рода изделиями, необходимыми для удовлетворения самых разных его потребностей (в жилище, питании, работе, досуге, средствах обороны, здравоохранении, воспитании и образовании и др.).

1.2. Задачи конструирования

Задача конструктора состоит в создании машин, полно отвечающих потребностям народного хозяйства, дающих наибольший экономический эффект и обладающих наиболее высокими технико-экономическими и эксплуатационными показателями, конкурентно-способными на внутреннем и внешнем рынках.

Главными показателями являются: высокая производительность, экономичность, прочность, надежность, малые масса и металлоемкость, габариты, энергоемкость, объем и стоимость ремонтных работ, расходы на оплату труда операторов, высокий технический ресурс и степень автоматизации, простота и безопасность обслуживания, удобство управления, сборки и разборки.

В конструкции машин необходимо соблюдать требования технической эстетики. Машины должны иметь красивый внешний вид, изящную, строгую отделку.

Значимость каждого из перечисленных факторов зависит от функционального назначения машины:

в машинах-генераторах и преобразователях энергии на первом плане стоит величина КПД, определяющего совершенство преобразования затрачиваемой энергии в полезную;

в машинах-орудиях — производительность, четкость и безотказность действия, степень автоматизации;

в металлорежущих станках — производительность, точность обработки, диапазон выполняемых операций;

в приборостроении — чувствительность, точность, стабильность показаний;

в транспортной технике, особенно в авиационной и ракетной, — малая масса конструкции, высокий КПД двигателя, обусловливающий малую массу бортового запаса топлива.

Проектируя машину, конструктор должен добиваться всемерного увеличения ее рентабельности и повышения экономического эффекта за весь период работы. Экономический эффект зависит от обширного комплекса технологических, организационно-производственных и эксплуатационных факторов. В данном курсе рассмотрены только те способы повышения экономичности, которые непосредственно связаны с конструированием и зависят от деятельности конструктора и используемых им средств конструирования.

1.3. Общие сведения о машинах и механизмах

Классификация машин. Современное производство немыслимо без всевозможных высокоэффективных машин.

Машина — это механическое устройство, предназначенное для выполнения требуемой полезной работы, связанной с процессом производства или транспортирования или же с процессом преобразования энергии, движения или информации.

Благодаря их использованию повышается производительность труда, облегчается физический и умственный труд человека и т.д.

По характеру рабочего процесса и назначению машины подразделяются на следующие группы (классы):

1.Энергетические машины, в которых какой-либо вид энергии (электрической, тепловой и т. п.) преобразуется в механическую работу и наоборот. К этой группе относятся как машины-двигатели (электродвигатели, тепловые и ядерные двигатели и т. п.), так и машины-преобразователи (компрессоры, электрические генераторы и др.).

2.Технологические или рабочие машины, предназначенные для выполнения производственных процессов по изменению формы, свойств и положения объектов труда (отраслевые машины, например металлорежущие и ткацкие станки, сельскохозяйственные машины, полиграфические, швейные, горнодобывающие и другие машины, роботы и т.п.).

3. Транспортные машины, предназначенные для перемещения объектов труда.

4.Информационные (контрольно-управляющие) машины, в которых происходит преобразование вводимой информации для контроля, регулирования и управления технологическими процессами (вычислительные, кибернетические машины и др.).

В зависимости от способа управления различают машины ручного управления (на встроенном рабочем месте или дистанционно), полуавтоматического и автоматического действия.

Машина, в которой преобразование энергии (материалов и информации) происходит без непосредственного участия человека, называется машиной — автоматом. Совокупность машин-автоматов, соединенных между собой автоматическими транспортными устройствами, управляемых единой системой управления и предназначенных для выполнения определенного технологического процесса, образует автоматическую линию.

Механизмы и их назначение. Механизм — часть машины, в которой рабочий процесс реализуется путем выполнении определенных механических движений.

Являясь носителем этих движений, механизм представляет собой совокупность (систему) взаимосвязанных тел, предназначенных для преобразования движения одного или нескольких тел в требуемые движения других тел.

Механизм осуществляет: передачу энергии (движения), как правило, с преобразованием сил и характеристик закона движения от источника, например двигателя, к одному или нескольким рабочим органам машины; преобразование и регулирование механического движения; заданную компоновку машины.

Если в преобразовании движения участвуют как твердые, так и жидкие или газообразные тела, то механизм называется соответственно гидравлическим или пневматическим.

Деталь — изделие, изготовленное из однородного по наименованию и марки материала без применения сборочных операция. К деталям можно отнести: валик из одного куска материала, литой корпус; пластину из биметаллического листа; печатную плату и т.д. Деталь может быть изготовлена с применением местных сварки, пайки, склеивании, сшивания и т.д. (трубка паянная или сваренная из одного куска листового материала, коробка склеенная из одного куска картона) и иметь защитное или декоративное покрытие.

Кинематическое звено — это деталь или несколько деталей связанных в работе между собой неподвижно или взаимно неподвижно. Выполнение звеньев не из одной, а из нескольких соединенных между собой деталей обеспечивает возможность:

изготовления деталей из разных материалов, например, вкладышей подшипников из бронзы или другого антифрикционного материала, а корпуса подшипника из чугуна;

удобной замены быстроизнашивающихся деталей;

сборки (например, установка коленчатого вала в коренные подшипники двигателя выполнима лишь при съемных крышках) и облегчения сборки машины;

облегчение изготовления деталей ввиду упрощения их формы и уменьшения размеров;

большей нормализации, стандартизации и централизованного изготовления деталей.

Кинематическая пара — это соединение двух звеньев обеспечивающее их относительную подвижность (рычаг — стойка, толкатель — направляющая, щуп — направляющая).

По характеру движения кинематические пары делятся на:

По характеру соприкосновения звеньев кинематические пары делятся:

Низшими кинематическими парами называют такие кинематические пары, в которых соприкосновение звеньев происходит по поверхности.

Высшими кинематическими парами называют пары, в которых соприкосновение звеньев происходит по линии или точке.

Изделием называется любой предмет производства (или набор предметов), подлежащих изготовлению на предприятии.

Изделия в зависимости от их назначения делят на изделия основного производства и вспомогательного.

К изделиям основного производства относятся изделия, предназначенные для поставки (реализации), к изделиям вспомогательного производства — изделия, предназначенные только для собственных нужд предприятия.

Установлены следующие виды изделий:

Сборочная единица — изделие, составные части которого подлежат соединению между собой на предприятии-изготовителе сборочными операциями (свинчиванием, сочленением, клепкой, сваркой, пайкой, опрессовкой и т.д.), например, автомобиль, станок, редуктор, сварной корпус, маховичок из пластмассы с металлической арматурой и др.

Комплекс — два или более специфицированных изделия, не соединенных на предприятии — изготовителе сборочными операциями, но предназначенные для выполнения взаимосвязанных эксплуатационных функций (автоматическая телефонная станция, бурильная установка; изделие, состоящее из метеорологической ракеты, пусковой установки и средств управления; корабль и т.п.).

Комплект — два или более изделия, не соединенных на предприятии- изготовителе сборочными операциями и представляющих собой набор изделий, имеющих общее эксплуатационное назначение вспомогательного характера (комплект запасных частей, комплект инструмента и принадлежностей, комплект измерительной аппаратуры, комплект упаковочной тары и т.д.).

2.1. Основные характеристики и требования, предъявляемые к машинам и механизмам

2.1. Основные характеристики и требования, предъявляемые к машинам и механизмам

Основными характеристиками машин являются: назначение и область применения, способ управления, мощность и производительность, коэффициент полезного действия, масса, габаритные размеры, стоимость и др.

Производительность машин измеряют в единицах, которые наиболее пригодны для данного оборудования. Например, производительность ткацких станков характеризуют количеством метров сотканной ткани, транспортера — массой транспортируемого груза в единицу времени и т.п.

Коэффициент полезного действия является характеристикой экономичности машин. Он показывает долю полезно реализуемой энергии и эффективность ее использования.

Массу и габаритные размеры необходимо знать для транспортирования машин и размещения их на производственных площадях.

Основные характеристики машин указывают в их техническом паспорте.

К машинам и механизмам предъявляют следующие основные требования: работоспособности; надежности; технологичности; экономичности; эргономичности.

Работоспособность. Работоспособностью называют состояние машин и механизмов, при котором они способны нормально выполнять заданные функции с параметрами, установленными нормативно-технической документацией (техническими условиями, стандартами и т. п.).

Надежность. Надежностью изделия называют свойство выполнять заданные функции, сохраняя во времени значения установленных эксплуатационных показателей в заданных пределах, соответствующих заданным режимам в условиях использования, технического обслуживания, ремонта, хранения и транспортирования.

Надежность является общей проблемой для всех отраслей машиностроения, приборостроения и других отраслей. Любая современная машина или прибор, какими бы высокими характеристиками они ни обладали, будут обесценены при ненадежной работе.

Надежность изделия зависит от необходимой нара6отки, которая может исчисляться в часах работы станка, налета самолета и т. д., в километрах пробега автомобиля, гектарах обработанной земли для сельскохозяйственной машины и т. д. Надежность зависит от всех этапов создания и эксплуатации изделий. Ошибки проектирования, погрешности в производстве, упаковке, транспортировке и эксплуатации изделия сказываются на его надежности.

Надежность изделий обуславливается их безотказностью, долговечностью, ремонтопригодностью и сохраняемостью.

Безотказность — свойство сохранять работоспособность в течение заданной наработки без вынужденных перерывов. Это свойство особенно важно для машин, отказы которых связаны с опасностью для жизни людей (например, самолеты) или с перерывом в работе большого комплекса машин.

Долговечность — свойство изделия сохранять работоспособность до предельного состояния с необходимыми перерывами для ремонтов и технического обслуживания.

Ремонтопригодность — приспособленность изделия к предупреждению, обнаружению и устранению отказов и неисправностей путем проведения технического обслуживания и ремонтов.


Сохраняемость — свойство изделия сохранять требуемые эксплуатационные показатели после установленного срока хранения и транспортирования.

Надежность деталей машин сильно зависит от того, насколько близок режим работы деталей по напряжениям, скоростям и температурам к предельным, т.е. от запасов по основным критериям работоспособности.

Надежность в значительной степени определяется качеством изготовления, которое может изменять ресурс в несколько раз.

Надежность статически определимых механизмов при одинаковых номинальных напряжениях выше, чем статически неопределимых, что связано с меньшим влиянием технологических погрешностей, а также температурных и силовых деформаций. Например, самоустанавливающиеся конструкции, как правило, более надежным, чем несамоустанавливающиеся.

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

Основным показателем безотказности является вероятность безотказной работы в течение заданного времени или заданной наработки. Экспериментально этот показатель может быть оценен как отношение числа образцов, сохранивших работоспособность, к общему числу испытанных образцов, если последнее достаточно велико.

В связи с тем, что отказ и безотказная работа взаимно противоположные события,

где Q(t)=- вероятность отказа за время t; f(t)- плотность вероятности отказов.

Основные показатели долговечности деталей: а) средний ресурс, т.е. средняя наработка до предельного состояния, и б) ресурс, который обеспечивается у заданного числа () процентов (например, 90%) изделий, так называемый гамма — процентный ресурс.

Вероятность безотказной работы системы равна по теореме умножения вероятностей безотказной работы элементов

Поэтому надежность сложных систем получается низкой, например, при числе элементов n = 10 с одинаковой вероятностью безотказной работы 0,9 общая вероятность 0,9=0,35.

В период нормальной эксплуатации машин износовые отказы еще не проявляются и надежность характеризуется внезапными отказами. Эти отказы называются неблагоприятным стечением многих обстоятельств и имеют постоянную интенсивность, не зависящую от продолжительности предшествующей эксплуатации изделия.

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

Технологичность зависит от масштаба и типа производства. Единичное и мелкосерийное производство предъявляют к технологичности одни требования, крупносерийное и массовое — другие. Признаки технологичности специфичны для деталей различных групп изготовления.

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

В массовом производстве штампованные «крышка» и «шкив» будут при всех других равных условиях, более предпочтительны, т.к. себестоимость изготовления единицы продукции будет меньше, чем при получении деталей литьем с последующей механической обработкой. При единичном и серийном производствах оборудование и технологическая оснастка для штамповки не окупится.

Экономичность. При оценке экономичности учитывают затраты на проектирование, изготовление, эксплуатацию и ремонт.

Экономичность машин достигается за счет снижения материалоемкости, энергоемкости и трудоёмкости производства, за счет максимального коэффициента полезного действия в эксплуатации при высокой надежности; высокой специализацией производства и т. д.

Эргономичность. Совершенство и красота внешних форм машины и удобство обслуживания существенно влияют на отношение к ней со стороны обслуживающего персонала и потребителей.

Красивый внешний вид деталям, узлам и машине придают форма и внешняя отделка конструкции (декоративная полировка, окраска, нанесение гальванических покрытии и оксидных пленок и т. д.). Существенное значение имеет и влияние машин на окружающую среду.

Выполнение указанных требований обеспечивается в результате создания и совершенствования машин в процессе эксплуатации, в котором участвуют не только инженеры-конструкторы, но и инженеры-технологи, инженеры по эксплуатации и ремонту, инженеры-экономисты и другие специалисты, а также техники и рабочие, занятые в технологических процессах.

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

3.1. Служебное назначение технологического оборудования

3.2. Содержание технических условий на оборудование

3.1. Служебное назначение технологического оборудования

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

Под служебным назначением оборудования понимается максимально уточненная и четко сформулированная технологическая задача, для решения которой оно предназначается.

Служебное назначение технологического оборудования должно отражать, в первую очередь, производственную необходимость для удовлетворения которой оно создается.

Оно должно учитывать уровень и состояние научно-технических разработок в данной конкретной области.

Ошибку на любом этапе жизненного цикла оборудования можно исправить, ошибку в формулировании служебного назначения исправить нельзя. Качество создаваемого оборудования зависит, прежде всего, от качества описания служебного назначения.

Общая формулировка служебного назначения должна выражать общую технологическую задачу, для решения которой создается оборудования, например: «токарный станок предназначен для обработки деталей типа тел вращения резанием». Но общая формулировка не раскрывает конкретного назначения оборудования и ее специфических особенностей. Формулировка служебного назначения должна выражать не только общую задачу, для решения которой создается оборудование, но и все дополнительные условия и требования, которые эту задачу максимально уточняют и конкретизируют.

Поэтому, формулируя служебное назначение токарного станка, необходимо уточнить размеры валов, для обработки которых станок предназначается.

Другое уточнение служебного назначения токарного станка может быть связано с его производительностью. Если станок предназначен для изготовления изделий широкой номенклатуры, выпускаемых в небольших количествах, то его конструкция должна быть универсальной; если для массового выпуска одинаковых изделий — то специальной.

Следующее уточнение служебного назначения может быть связано с требованиями к точности деталей, которые должны будут обрабатываться на станке, — точности размеров, относительного поворота, формы и чисто ты поверхностей.

К числу параметров, уточняющих служебное назначение токарного станка, необходимо отнести режимы обработки деталей, тип заготовок, их материал, условия, в которых предстоит работать станку: возможные колебания температуры окружающей среды, влажность и запыленность воздуха и т. д.

Любое оборудование создается для выполнения определенного технологического (рабочего) процесса. Поэтому определение служебного назначения оборудования надо начинать с изучения и описания, т.е. анализа этого процесса.

Под технологическим процессом, реализуемым оборудование или с его помощью, понимают совокупность последовательных действий, направленных на достижение определенного результата. Такой процесс практически всегда развивается в непрерывно изменяющихся условиях. Во времени не остаются постоянными качество исходного продукта и количество сообщаемой энергии, колеблются внешние параметры и состояние оборудования.

Качественное изучение технологического процесса включает четыре основных аспекта:

вид исходного продукта и существо нестабильности его качества;

вид энергии и ее количественные параметры;

факторы, изменяющие внешнюю среду, в которой предстоит работать оборудованию;

сущность изменений состояния оборудования.

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

Выполнение любого технологического процесса сопровождается всевозможными случайными отклонениями его параметров от установленных. Это характерно для следующих факторов:

качества исходного продукта (предметов производства);

вида и пределов изменения количества подводимой энергии;

изменений внешних условий (температуры, влажности, запыленности воздуха и т. д.).

При проектировании оборудования нет смысла устанавливать в каждом конкретном случае конкретную причину того или иного отклонения. Все случайности, нестабильности технологического процесса называют его стохастической неопределенностью.

В большинстве практических задач стохастическую неопределенность технологического процесса можно описать с помощью случайных величин, или случайных функций.

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

Для того чтобы оборудование нормально выполняло свои функции в соответствии со своим служебным назначением, необходимо установить границы варьирования случайностей, сопровождающих выполнение процесса.

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

Под риском понимают возможность наступления неблагоприятного исхода (события).

Существуют измерители риска. Один из них — вероятностная мера риска, равная вероятности наступления неблагоприятного исхода. Другой измеритель риска — экономическая мера риска, являющаяся функцией от вероятности наступления неблагоприятного исхода и размера экономического ущерба, вызванного неблагоприятным исходом.

Вероятностная мера риска раскрывает сущность взаимосвязи между объемом дополнительных ресурсов, привлекаемых для осуществления какого либо процесса, и опасностью наступления неблагоприятного события. То есть хочешь снизить риск, привлекай дополнительные ресурсы. Если же экономишь, то рискуй.

Риск может быть обусловлен не только стохастической неопределенностью, но также эпистемологической и лингвистической неопределенностями.

Эпистемологическая неопределенность обусловлена субъективностью оценок, суждений и поведения разработчиков проектных решений. Например, установление запаса прочности конструкции в условиях отсутствия методик расчета.

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

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

Другую группу данных могут составить показатели производительности. Они определяются при разработке технологии изготовления продукции и соответствующих технико-экономических расчетах. Сюда же можно отнести требования долговечности и надежности машины.

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

Формулировка служебного назначения оборудования может содержать ряд дополнительных сведений, таких, как требования к внешнему виду, безопасности работы, удобству и простоте обслуживания и управления, уровню шума, коэффициенту полезного действия, степени механизации и автоматизации и т. п.

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

3.2. Содержание технических условий на оборудование

Важнейший документ, отражающий служебное назначение изделия- это технические условия (ТУ). Технические условия — неотъемлемая часть технической документации на оборудование. Они должны содержать все требования к оборудованию, к его изготовлению, контролю, приемке, поставке, а также те, которые нецелесообразно указывать в конструкторской или другой технической документации.

ТУ является системным документом, так как любые ТУ, т.е. ТУ на любое изделие, должны содержать следующие разделы (кроме, разумеется, вводной части):

методы контроля (испытаний, анализа, измерений);

транспортирование и хранение;

указания по эксплуатации (применению);

ТУ тесно увязаны со служебным назначением изделий. Существует ГОСТ на ТУ. Это нормативный документ, обобщающий, унифицирующий и узаконивающий всю практику их разработки на самые разные изделия.

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

В разделе «Технические требования» указывают требования, «определяющие показатели качества и эксплуатационные характеристики изделия». Показатели и свойства продукции (изделий) обязательно приводятся применительно к условиям и режимам эксплуатации, а также к условиям и режимам испытаний.

Некоторые требования невозможно установить заранее, так как соответствующие показатели не могут быть выражены непосредственно, а лишь установлены при условии однозначного соблюдения каких-либо других требований (к организации производства, гигиенические требования к производственным помещениям и исполнителям, использование определенных элементов технологического процесса, материалов, покрытий, специального технологического оборудования или оснастки, длительная тренировка, обкатка, приработка, выдержка готовых изделий или материалов, рецептура и т. д.). В этом случае все эти требования должны быть также приведены в разделе «Технические требования».

В зависимости от характера и служебного назначения изделия в соответствующих ТУ должны быть предусмотрены требования к качеству, которым изделие должно соответствовать.

Термин «качество» неоднозначен. Чаще всего под качеством понимают степень соответствия заданным требованиям. Кроме того, качество это еще и совокупность разнообразных свойств, непосредственно вытекающих из специфики конкретного изделия, и им реализуемых, в нем «объединяемых». Первое качество реализуется через второе. Но это разные понятия, их не следует смешивать. В ТУ требования к «качеству» устанавливаются именно во втором смысле.

Требования к качеству устанавливаются в зависимости от служебного назначения. Они должны и могут учитывать следующие факторы:

физико-химические, механические и другие свойства, такие, как прочность, твердость, структура, шероховатость поверхности, химический состав, предельное содержание примесей, теплостойкость, термостойкость, износоустойчивость, чувствительность, точность и т. п.;

эксплуатационные показатели: производительность, скорость, коэффициент полезного действия, расход электроэнергии, топлива и масла и т. д.;

группа свойств «надежности», т.е. собственно надежность, а также долговечность, безотказность, сохраняемость и т. д.

требования к конструкции, эргономические, художественно-эстетические, органолептические, биологические, санитарно-гигиенические и другие показатели этого рода (скажем, безопасность в эксплуатации, уровень шума, помехозащищенность, усилия, требуемые для управления и обслуживания, запасы регулировки органов управления, время готовности после включения, запах, вкус, токсичность, маркировочные, защитные и другие виды покрытий и т. п.);

стабильность параметров при воздействии факторов внешней среды (климатических, механических, циклических изменений температуры, агрессивных сред и др.;

устойчивость к моющим средствам, средствам дезинфекции, средствам и условиям стерилизации, топливу, маслам; радиационная стойкость и т. д.);


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

4.1. Организация процесса проектирования-конструирования и освоения технологического оборудования

4.2. Стадии и этапы разработки конструкторской документации

4.1. Организация процесса проектирования-конструирования и освоения технологического оборудования

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

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

Опытно-конструкторская работа (ОКР) представляет собой, как правило, сложный процесс разработки одного или нескольких исполнений изделия, сочетающий собственно конструкторские разработки с большим объемом расчетно-экспериментальных исследований, изготовлением опытных образцов оборудования и их всесторонней экспериментальной проверкой и отработкой в процессе освоения промышленного производства.

Содержание ОКР обусловлено видом и назначением проектируемого оборудования, сложностью и новизной его конструкции, способами изготовления и использования его в условиях эксплуатации.

Основные фазы ОКР. Обычно выделяют три четко выраженные фазы ОКР:

1-я фаза — формулирование цели (разработка технического задания) — процесс осмысления конструкции на основе сопоставления и анализа данных производственного опыта и результатов научно-исследовательских работ с потребностями потребителей и формирования предварительных (возможных и желательных) очертаний объекта разработки, его существенных признаков, т.е. качественных особенностей, и количественного выражения этих признаков с учетом данных инженерного прогнозирования и параметрической оптимизации;

2-я фаза — информационное моделирование изделия (разработка проектной конструкторской документации: технического предложения, эскизного и технического проектов) — процесс последовательного углубления идеализированных знаний об объекте разработки, осуществляемый исходя из данных технического задания и практического опыта путем выполнения следующих работ:

а) многократного (многовариантного) моделирования (прорисовки) объекта посредством отображения его в документации, последующего сопоставления и анализа различных конструкций, построенных на различных сочетаниях составляющих конструктивных элементов, и выделения наиболее желательного (оптимального) варианта т.е. разработки технического предложения;

б) проработки и изучения основных составляющих элементов оптимального варианта конструкции и принципов их взаимодействия посредством отображения конструкции проектируемого оборудования в конструкторской документации, т.е. разработки эскизного проекта;

в) всесторонней проработки и изучения конструкции, всех ее элементов и их взаимосвязей посредством отображения их в документации, позволяющего получить полное представление об устройстве и принципе работы объекта, т.е. разработки технического проекта;

3-я фаза — материальное воплощение конструкторского замысла (разработка рабочей конструкторской документации опытного образца или партии) — процесс эмпирического познания объекта, осуществляемый путем изготовления и экспериментального исследования натурных образцов оборудования в период освоения его производства, сопоставления опытных данных с техническим заданием и документацией на него и внесения необходимых уточнений в эту документацию.

Важнейшая задача ОКР — обеспечение и поддержание качества проектируемого объекта на современном технико-экономическом уровне и максимально возможное сокращение сроков изготовления и освоения нового оборудования.

В результате проведения предпроектных исследований (поисковых, патентных и др.), инженерного прогнозирования и параметрической оптимизации объектов производства выявляются базовые показатели качества оборудования, которые служат ориентирами на всех этапах ОКР.

Использование в конструкторской практике эффективной системы управления качеством проектируемых изделий способствует повышению эффективности разработок, качества и конкурентоспособности изделий.

4.2. Стадии и этапы разработки конструкторской документации

Конструирование машин — творческий процесс со свойственными ему закономерностями построения и развития. Основные особенности этого процесса состоят в многовариантности решения, необходимости согласования принимаемых решений с общими и специфическими требованиями, предъявляемыми к конструкциям, а также с требованиями соответствующих ГОСТов, регламентирующих термины, определения, условные обозначения, систему измерений, методы расчета и т. п.

Детали, узлы, машины изготовляют по чертежам, выполненным на основе проектов — совокупности расчетов, графических материалов и пояснений к ним, предназначенных для обоснования и определения параметров конструкции (кинематических, динамических, геометрических и др.), ее производительности, экономической эффективности. Для особо ответственных конструкций проект дополняют макетом или действующей моделью.

Согласно ГОСТ 2.102 к конструкторским документам относятся графические и текстовые документы, которые в отдельности или в совокупности определяют состав и устройство изделия, содержат необходимые данные его разработки или изготовления, контроля, приемки, эксплуатации и ремонта.

В зависимости от стадии разработки конструкторские документы подразделяются на проектные (техническое предложение, эскизный проект и технический проект) и рабочие (рабочая документация).

Номенклатуру конструкторских документов, разрабатываемых на изделие, определяют в совокупности два фактора:

— вид изделия по ГОСТ 2.101-68 (деталь, сборочная единица, комплекс, комплект);

— стадия разработки конструкторской документации (технического предложения, эскизного проекта, технического проекта, рабочей документации

Стадии разработки конструкторской документации и этапы работ установлены стандартом. Он обобщает опыт, накопленный в передовых странах по проектированию машин, приборов и аппаратов.

Первая стадия — разработка технического задания — документа, содержащего наименование, основное назначение, технические требования, показатели качества, экономические показатели и специальные требования заказчика к изделию.

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

Вторая стадия. Разработка технического предложения предполагает создание конструкторских документов, которые содержат технические и технико-экономические обоснования целесообразности разработки нового оборудования на основании анализа технического задания заказчика и различных вариантов конструкции, сравнительной оценки проектных решений с учетом конструкторских и эксплуатационных особенностей проектируемого и существующего оборудования, а также патентных материалов.

Техническое предложение разрабатывается с целью выявления дополнительных или уточненных требований к изделию, его технических характеристик, показателей качества, которые не могли быть указаны в техническом задании, если это целесообразно сделать на основе предварительной проработки и анализа различных вариантов конструкции изделия.

Наиболее характерные виды работ, выполняемых при разработке технического предложения:

выявление и проработка возможных проектных решений, определение особенностей этих вариантов по составу, структуре, принципу действия и т.п.;

проверка вариантов на патентную чистоту и конкурентоспособность с последующим оформлением при необходимости заявок на изобретения;

проверка соответствия вариантов требованиям техники безопасности и производственной санитарии;

сравнительная оценка вариантов технических решений по всей совокупности выявленных свойств и показателей, конструктивным и эксплуатационным особенностям проектируемого и существующего оборудования;

выбор оптимального варианта конструкции и установление требований к последующей стадии разработки.

Особое внимание уделяется изучению тенденций и перспектив развития отечественной и зарубежной техники в соответствующей области.

В техническое предложение включают конструкторские документы в соответствии с ГОСТ 2.102.

В общем случае в него может входить чертеж общего вида, габаритный чертеж, схемы, таблицы, расчеты, патентный формуляр, ведомость технического предложения. В состав технического предложения целесообразно включать данные обзора и анализа аналогичных конструкций, имеющихся в отечественной и зарубежной практике, данные сравнения характеристик разрабатываемого изделия с характеристиками аналогов, общий вид изделия в оптимальном варианте и описание его устройства, компоновки и принципа действия.

Техническое предложение после его рассмотрения и согласования служит основанием для выполнения эскизного или технического проекта.

Третья стадия. Разработка эскизного проекта заключается в разработке комплекта документов, содержащих принципиальные решения и дающие более полное по сравнению с предыдущей стадией общее представление об устройстве и принципе работы изделия, а также технические данные, определяемые его назначением, основные параметры и размеры.

Эскизный проект разрабатывается с целью установления принципиальных технических решений, дающих общее представление об устройстве и принципе работы проектируемого оборудования, если такая разработка признается целесообразной до разработки технического проекта или рабочей конструкторской документации.

В эскизный проект включаются конструкторские документы по ГОСТ 2.102, к которым в общем случае, в зависимости от специфики проектируемого оборудования, его новизны и сложности, могут быть отнесены чертеж общего вида, теоретический разработки, габаритный чертеж, монтажный чертеж, схемы, ведомости покупных изделий и согласования их применения, программа и методика испытаний, таблицы, расчеты, патентный формуляр, ведомость эскизного проекта и пояснительная записка к нему.

Илон Маск рекомендует:  Русский дизассемблер

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

Эскизные проект после его рассмотрения и согласования служит основанием для разработки технического проекта или рабочей документации.

Четвертая стадия. Разработка технического проекта включает работы по разработке комплекта конструкторских документов, содержащих окончательные технические решения и дающие полное представление об устройстве и принципе работы изделия, а также исходные данные для разработки рабочей конструкторской документации.

Технический проект разрабатывают с целью подготовки необходимых для последующих работ технических данных как по изделию в целом, так и по его составным частям и основным материалам.

При разработке технического проекта в общем случае выполняются следующие основные работы:

разработка конструкции изделия и его составных частей, принципиальных схем, схем соединений и других схемных документов;

выполнение технико-экономических расчетов, подтверждающих соответствие предполагаемых решений техническому заданию и условиям производства изделия;

оценка эксплуатационных данных изделия (транспортабельности, взаимозаменяемости, удобства обслуживания, ремонтопригодности, контролепригодности и т.п.), а также его эстетичности и экономичности, соответствия принимаемых решений требованиям безопасности и производственной санитарии, промышленной аэрологии и охраны окружающей среды;

проведение экспериментальных работ (с разработкой, при необходимости, макетов и стендовых установок) для контроля показателей исходных материалов и составных (комплектующих) частей изделия;

Конструирование компиляторов

Детерминированный нисходящий и восходящий синтаксический анализ (СА), устройство и конфигурация LL(1) анализатора, условия для грамматик. Функции FIRST и FOLLOW и их интерпретация. Вычисления FOLLOW для нетерминала при k=1. Грамматики предшествования.

Рубрика Программирование, компьютеры и кибернетика
Вид шпаргалка
Язык русский
Дата добавления 24.06.2009
Размер файла 296,3 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

1. Детерминированный нисходящий СА. Устройство LL(1) анализатора. Конфигурация LL(1) анализатора. Структура управляющей таблицы разбора. 1предсказывающий алгоритм разбора

Детерминированный нисходящий СА — цепочка считывается один раз и процесс разбора полностью детерминирован (в отличие от алгоритмов с возвратом). Это накладывает ограничения на класс грамматик, для которых такой разбор возможен.

LL(k) — грамматики — для которых левый анализатор работает детерминировано, если видит на k символов вперед (то есть если видим следующие k символов, то можем однозначно выбрать подходящее правило выбора).

LR(k) — грамматики-то же самое, только для правого разбора.

КС-грамматика называется LL(k) грамматикой для некоторого фиксированного k, если из существования двух левых выводов:

для которых FIRSTk(x) = FIRSTk(y), вытекает, что .

Соответственно, LL(1) — грамматика позволяет просматривать только один символ из входного потока на каждом шаге. LL(1) анализатор представляет собой магазинный автомат, состоящий из входной ленты, входной головки, магазина, управляющей таблицы и выходной ленты.

При чтении цепочки головка может заглядывать вперед только на один символ u (аванцепочки). В магазине: X — верхний символ магазина, $ — маркер дна. Алфавит магазинных символов обозначается Г.

Конфигурация предсказывающего алгоритма представляется в виде тройки , где

1) x — неиспользованная часть входной цепочки.

2) — цепочка в магазине.

3) — цепочка на выходной ленте.

Работой 1-предсказывающего алгоритма руководит управляющая таблица M, задающая отображение множества в множество, в которое входят:

(1) , где , а i — номер правила ( — или правая часть этого правила, или некоторое его представление). (2) Выброс. (3) Допуск. (4) Ошибка.

На каждом такте считывается символ u и определяется верхний символ магазина Х. Потом рассматривается элемент управляющей таблицы M (u, X), который и подсказывает, что надо делать:

1) М (u, X)= , тогда (верхний символ магазина заменяется цепочкой, а в выход пишется номер правила).

2) М (u, X)=выброс и , тогда (символ в магазине совпал с входным символом — оба символа выбрасываются).

3) М (u, X)=допуск, значит, разбор завершен успешно и мы в конфигурации

4) М (u, X)=ошибка, значит, разбор не получится — выходим.

Детерминированный нисходящий СА — цепочка считывается один раз и процесс разбора полностью детерминирован (в отличие от алгоритмов с возвратом). Это накладывает ограничения на класс грамматик, для которых такой разбор возможен.

LL(k) — грамматики — для которых левый анализатор работает детерминировано, если видит на k символов вперед (то есть если видим следующие k символов, то можем однозначно выбрать подходящее правило выбора).

LR(k) — грамматики-то же самое, только для правого разбора.

Формально: КС-грамматика называется LL(k) грамматикой для некоторого фиксированного k, если из существования двух левых выводов:

для которых FIRSTk(x) = FIRSTk(y), вытекает, что .


Неформально: FIRSTk(a) — это множество всех терминальных префиксов длины k (или меньше, если из a выводится цепочка длины — конец основы, выполняется между последним символом цепочки b и первым символом цепочки w;

бXBb, что есть такие правила B=>+Yy;

б) X.>a: A=>бBYb; B=>+yX; Y=>*ab; (X.>a — всегда терминальный символ с права, так как конец основы)

в) X.=Y если в P есть правило A=>aXYb; XY — основа (элементы, между которыми имеется отношение эквивалентности)

Конспект лекций «Методы построения компиляторов»

Содержание

Литература

  1. Ахо А., Сети Р., Ульман Д. Компиляторы. Принципы, технологии, инструменты. — М.: Вильямс, 2001.
  2. Карпов Ю. Г. Основы построения трансляторов. — М.: BHV, 2005.
  3. Свердлов С. З. Языки программирования и методы трансляции. — М.: Питер, 2007.
  4. Опалева Э. А., Самойленко В.П. Языки программирования и методы трансляции. — М.: BHV, 2005.

Лекция 1

Введение в компиляцию

Что такое компилятор. Исходный и целевой язык.

Разновидности компиляторов

  • Интерпретаторы
  • Форматтеры текста
  • Статические анализаторы кода
  • Препроцессоры
    • макросы define
    • включение файлов #include
    • условная компиляция #ifdef
    • расширения языка, которые препроцессор переводит в код на языке

Фазы компиляции

  • Лексический анализ (сканирование)
  • Синтаксический анализ (разбор, „парсинг“)
  • Семантический анализ

На примере выражения p := i + r * 60

  • Обнаружение ошибок. Лексические, синтаксические и семантические ошибки.
  • Генерация промежуточного кода

На примере трехадресного кода

  • Оптимизация кода
  • Генерация кода (основное — назначение переменных регистрам)

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

Математическим обеспечением фаз лексического и синтаксического анализа является теория формальных языков. Обычно лексические анализаторы генерируются с помощью регулярных выражений.

Синтаксический анализ основывается на теории контекстно-свободных (КС) грамматик. Общая форма КС-грамматики не позволяет разбирать язык достаточно простым (в частности, автоматически сгенерированным) парсером, потому языки программирования обычно принадлежат одному из нескольких специальных подклассов КС-языков (LL, LR, LALR), которые проще разбирать и некоторые из которых будут подробно изучены в курсе.

Упомянутые достижения теории формальных языков насчитывают уже несколько десятков лет, и в этой области не ожидается каких-либо новых разработок, тем более что имеющиеся теоретические результаты хорошо решают практические задачи. По другому обстоит дело с изучением других двух разделов компиляции: семантическим анализом и оптимизацией. Работы по формальному описанию семантики языков программирования интенсивно появлялись в 70–80-х годах. Однако ни одна из построенных теорий не вошла в широкое употребление при построении компиляторов, и сегодня дело обстоит таким образом, что семантика вначале описывается на естественном языке, а затем реализуется в компиляторе большим набором вручную закодированных условных операторов.

Напротив, в последние годы растёт актуальность теории оптимизирующих преобразований — это объясняется появлением всё более высокоуровневых языков и разнообразных аппаратных платформ. Оптимизация также требует привлечения развитого математического аппарата (в частности, для решения вопроса о корректности преобразований). Многие из достижений активно внедряются в промышленные компиляторы. Всё больше это касается преобразований, связанных с распараллеливанием.

На этапе построения семантического дерева строится таблица символов — в нее заносятся имена, присутствовавшие в исходном тексте, к ним добавляются такие атрибуты как тип, отведённая память, область видимости.

Лекция 2

Группировка фаз

  • Front-end и back-end компиляторы.

Перечисленные выше фазы обычно группируются в два модуля — front-end и back-end, в зависимости от того, к какой стороне процесса компиляции они ближе, к исходному языку или к машинному коду для целевой платформы, соответственно. Возможность отдельно разрабатывать front-end и back-end повышает эффективность труда разработчиков компиляторов — насколько, зависит от эффективности используемого внутреннего представления, связывающего эти два модуля. В последнее время всё чаще выделяют middle-end — части компилятора, активно работающие с промежуточным представлением.

  • Проходы. Группировка фаз компилятора в проходы (например, объединение фаз лексического, синтаксического, семантического анализа и генерации кода).

Разбиение процесса компиляции на фазы является логическим. Есть и другой, физический подход к такому разбиению — на проходы. Проходом обычно считается одно чтение исходного потока (и, возможно, одна законченная генерация выходного). Разные фазы могут группироваться в один проход.

  • Уменьшение количества проходов (на примере предварительного описания подпрограмм). Технология обратных поправок.

Компиляция и многомодульность. Необходимость компилировать модуль в некоторый формат, содержащий правильную программу. Перемещаемые адреса. Редактор связей (линковщик).

Инструментарий для создания компиляторов

  • Генераторы лексических анализаторов (сканеров)
  • Генераторы синтаксических анализаторов (парсеров)
  • Автоматические генераторы кода

Компиляторы компиляторов

  • Lex + Yacc
  • Flex + Bison
  • CoCo
  • Antlr
  • Gold Parser Builder
  • GPLex + GPPG

Порождающие грамматики

Определение. Символы: терминалы и нетерминалы. Продукции (правила вывода). Стартовый символ.

Опр. формальной грамматики (порождающей грамматики Хомского)

V = Σ + N — множество всех нетерминалов и терминалов

X * — множество всех цепочек символов из X

Классификация формальных грамматик по Хомскому (1956 г.)

  • Грамматика типа 0 (общего вида). Правила имеют вид α→β
  • Грамматика типа 1 (контекстно зависимая, КЗ)

Правила имеют вид αAβ → αγβ. γ принадлежит V + , т.е. грамматика является неукорачивающей Добавляется также правило S → ε α,β называются левым и правым контекстом

  • Грамматика типа 2 (контекстно свободная, КС)

Правила имеют вид A → α. α ∊ V* Наиболее близкая к БНФ

  • Грамматика типа 3 (автоматная, регулярная)

Правила имеют вид A → aB, A → a, A → ε (правая регулярная грамматика) Автоматные языки содержатся в КС языках


Пример. Грамматика, порождающая язык правильных скобочных выражений.

Порождение (вывод)

Далее будем говорить только о КС-грамматиках.

Грамматика G порождает (выводит) цепочки из стартового символа, используя правила вывода.

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

Опр. Предложением (сентенцией) грамматики называется сентенциальная форма, состоящая из одних терминалов.

Опр. Языком над алфавитом (словарём) Σ называется подмножество L множества Σ * .

Опр. Языком L(G), порождаемым грамматикой G, называется множество всех ее предложений:

Опр. Две грамматики называются эквивалентными, если языки, ими порождаемые, совпадают:

Утв. Проблема эквивалентности КС-грамматик алгоритмически неразрешима.

Левый, правый вывод (порождение). Деревья вывода (разбора)

Опр. Если в процессе вывода заменяется всякий раз самый левый нетерминал, то такой вывод называется левым.

Левый и правый вывод для предложения i + i * i

Дерево вывода (дерево разбора) строки предложения. В отличие от порождения, из него исключена информация о порядке вывода.

Крона дерева разбора — цепочка меток листьев слева направо

Неоднозначные грамматики

Грамматика, которая дает более одного дерева разбора для некоторого предложения, называется неоднозначной.

Пример неоднозначной грамматики. Грамматика арифметических выражений.

Два дерева разбора для цепочки i + i * i

Преобразование в эквивалентную однозначную грамматику:

Пример неоднозначной грамматики. Грамматика условного оператора

Два дерева разбора для цепочки if b then if b then a

Преобразование в эквивалентную однозначную грамматику:

Утверждение. Проблема неоднозначности произвольной КС-грамматики алгоритмически не разрешима

Леворекурсивные грамматики, их проблемы. Алгоритм устранения левой рекурсии.

Перевод (трансляция)

Ранее мы решали вопрос о принадлежности некоторой цепочки α интересующему нас языку L, задаваемому грамматикой G. Но задача компиляции шире: не только распознать входную цепочку, но и сгенерировать выходную.

Определение. Пусть Σ и Δ — два алфавита (называемые „входным“ и „выходным“ соответственно). L1 ⊂ Σ*, L2 ⊂ Δ*. Переводом с языка L1 на язык L2 называется отображение τ: L1 → L2.

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

Схема синтаксически управляемого перевода (СУ-схема)

Неформальное определение. СУ-схема это грамматика, в которую с каждым синтаксическим правилом встроен элемент перевода.

Пример. Перевод алгебраического выражения в ПОЛИЗ (польская инверсная запись). Запишем правила грамматика вместе с элементами перевода.

Правило Элемент перевода
E → E + T E = E T +
E → T E = T
T → T * P T = T P *
T → P T = P
P → (E) P = E
P → P =

Выведем цепочку a * (b + c) и одновременно переведём её в ПОЛИЗ: a b c + * (как обычно, используем левый вывод):

Определение. Схема синтаксически управляемого перевода это пятёрка

Причём α и β в каждом конкретном правиле содержат одни и те же нетерминалы с точностью до перестановки.

Далее считаем, что задана некоторая СУ-схема T = (N, Σ, Δ, R, S).

Определение. Входная грамматика, соответствующая СУ-схеме T, это четвёрка

Определение. Выходная грамматика, соответствующая СУ-схеме T, это четвёрка

Определение. СУ-перевод (СУ-трансляция) это множество

обозначаемое обычно τ(T).

СУ-перевод можно понимать как трансформацию синтаксических деревьев (соответствующих выводу входной и выходной цепочек).

Транслирующие грамматики

Позволяют решать задачу перевода в более сложных случаях, чем СУ-схемы. ТГ это разновидность КС-грамматик, где символы (терминалы) разделены на два множества, Σi и Σa (a от action), называемые „входными“ и „операционными“ соответственно. При использовании ТГ, чтобы различать элементы Σi и Σa, будем заключать последние в фигурные скобки, ‘<’, ‘>’, считая получившиеся на письме три символа одним символом алфавита.

Пример. Перевод простого алгебраического выражения в ПОЛИЗ .

Определение. Пусть α ∊ (Σi ∪ Σa)*. Тогда α называется активной цепочкой. Входные (операционные) символы активной цепочки, записанные отдельно в том же порядке, как они встречались в ней, образуют входную (операционную) цепочку.

Операционные символы можно трактовать как имена процедур, выполняющих определённые действия. Пока — процедур без параметров. Операционные символы также могут использоваться для интерпретации кода. Операционные символы могут находиться в любой части результата продукции, не только в суффиксе, но это может сильно усложнить парсер (иногда придётся откатываться).

Атрибутные грамматики и трансляция

В АГ с каждым символом грамматики может быть связан один или несколько атрибутов. Для каждого синтаксического правила вводятся семантические правила, устанавливающие функциональные зависимости между атрибутами.

Дерево, содержащее атрибуты, называется аннотированным. Атрибуты придают смысл синтаксической структуре, описываемой деревом, и потому аннотированное дерево называется также семантическим деревом.

Пример. Вычисление простого арифметического выражения .

  1. Синтезированные — значения таких атрибутов зависят только от значений атрибутов потомков в дереве разбора.
  2. Унаследованные — значения таких атрибутов зависят от значений атрибутов родительского узла, узлов-братьев и сестёр (дочерних для родительского), а также других атрибутов самого узла.

Синтаксический анализ

Понятие синтаксического анализатора.

Нисходящие (top-down) и восходящие (bottom-up) синтаксические анализаторы

Нисходящий синтаксический анализ

Опр. Синтаксический анализатор, работающий методом рекурсивного спуска и не требующий откатов, называется предиктивным синтаксическим анализатором.

Нерекурсивный предиктивный анализ

Схема работы со стеком, таблицей разбора, входным буфером

Алгоритм нерекурсивного предиктивного анализа

Множества FIRST и FOLLOW

Алгоритм построения таблиц предиктивного анализа.

Определение LL(1) грамматики. Пояснение названия.

Утв. LL(1) грамматика не может быть леворекурсивной или неоднозначной.

Эквивалентное определение LL(1) грамматики.

Восстановление после ошибок в предиктивном анализе.

Восходящий синтаксический анализ

Наиболее распространенная разновидность — ПС-анализ (перенос-свертка — shift-reduce)

Понятие основы. Примеры.

Обращенное правое порождение и обрезка основ.

Стековая реализация ПС-анализа. Основные операции:

Утв. Основа всегда находится на вершине стека и никогда — внутри него. Доказательство.

Понятие активного префикса.

LR-анализаторы. SLR, канонический LR и LALR анализаторы.

Общая схема и алгоритм LR-анализа. Пример.

Неоднозначности вида shift-reduce и их разрешение.

Генераторы лексических и синтаксических анализаторов

Создание лексического анализатора (сканера) с помощью gplex

Общая структура .l файла

Особенности .l файла gplex

Возвращение типов лексем


Лексемы идентификаторов, чисел.

Начальные состояния сканера, их изменение, использование для вырезания комментариев:

Создание синтаксического анализатора с помощью gppg

Общая структура .y файла

Задание типов лексем

Таблица приоритетов и ассоциативности

Особенности .y файла gppg

  1. Простейший калькулятор
    • Простейший калькулятор с приоритетом операций
    • Создание дерева разбора программы
    • Преобразование в XML
    • Добавление переменных. Представление о таблице символов
    • Добавление присваивания
    • Добавление типов
    • Добавление управляющих конструкций

Лексический анализ

Лексический анализ – это процесс сканирования потока входных символов и разделения его на строки, называемые лексемами. Большинство книг по компиляторам начинаются с этого и посвящают несколько глав обсуждению различных методов построения сканеров. Такой подход имеет свое место, но, как вы уже видели, существуют множество вещей, которые вы можете сделать даже никогда не обращавшись к этому вопросу, и, фактически, сканер, который мы здесь закончим, не очень будет напоминать то, что эти тексты описывают. Причина? Теория компиляторов и, следовательно, программы следующие из нее, должны работать с большинством общих правил синтаксического анализа. Мы же не делаем этого. В реальном мире возможно определить синтаксис языка таким образом, что будет достаточно довольно простого сканера. И как всегда KISS – наш девиз.

Как правило, лексический анализатор создается как отдельная часть компилятора, так что синтаксический анализатор по существу видит только поток входных лексем. Теоретически нет необходимости отделять эту функцию от остальной части синтаксического анализатора. Имеется только один набор синтаксических уравнений, который определяет весь язык, поэтому теоретически мы могли бы написать весь анализатор в одном модуле.

Зачем необходимо разделение? Ответ имеет и теоретическую и практическую основы.

В 1956 Ноам Хомский определил «Иерархию Хомского» для грамматик. Вот они:

Тип 0. Неограниченные (например Английский язык)

Тип 1. Контекстно-зависимые

Тип 2. Контекстно-свободные

Тип 3. Регулярные.

Некоторые характеристики типичных языков программирования (особенно старых, таких как Фортран) относят их к Типу 1, но большая часть всех современных языков программирования может быть описана с использованием только двух последних типов и с ними мы и будем здесь работать.

Хорошая сторона этих двух типов в том, что существуют очень специфические пути для их анализа. Было показано, что любая регулярная грамматика может быть анализирована с использованием частной формы абстрактной машины, называемой конечным автоматом. Мы уже реализовывали конечные автоматы в некоторых их наших распознающих программ.

Аналогично грамматики Типа 2 (контекстно-свободные) всегда могут быть анализированы с использованием магазинного автомата (конечный автомат, дополненный стеком). Мы также реализовывали эти машины. Вместо реализации явного стека для выполнения работы мы положились на встроенный стек связанный с рекурсивным кодированием и это фактически является предочтительным способом для нисходящего синтаксического анализа.

Случается что в реальных, практических грамматиках части, которые квалифицируются как регулярные выражения, имеют склонность быть низкоуровневыми частями, как определение идентификатора:

Так как требуется различные виды абстрактных машин для анализа этих двух типов грамматик, есть смысл отделить эти низкоуровневые функции в отдельный модуль, лексический анализатор, который строится на идее конечного автомата. Идея состоит в том, чтобы использовать самый простой метод синтаксического анализа, необходимый для работы.

Имеется другая, более практическая причина для отделения сканера от синтаксического анализатора. Мы хотим думать о входном исходном файле как потоке символов, которые мы обрабатываем справа налево без возвратов. На практике это невозможно. Почти каждый язык имеет некоторые ключевые слова типа IF, WHILE и END. Как я упомянул ранее, в действительности мы не можем знать является ли данная строка ключевым словом до тех пор пока мы не достигнем ее конца, что определено пробелом или другим разделителем. Так что мы должны хранить строку достаточно долго для того, чтобы выяснить имеем мы ключевое слово или нет. Это ограниченная форма перебора с возвратом.

Поэтому структура стандартного компилятора включает разбиение функций низкоуровневого и высокоуровневого синтаксического анализа. Лексический анализатор работает на символьном уровне собирая символы в строки и т.п., и передавая их синтаксическому анализатору как неделимые лексемы. Также считается нормальным позволить сканеру выполнять работу по идентификации ключевых слов.

Лексический анализ. Конструирование компиляторов, алгоритмы решения задач

Согласно теореме Клини любому регулярному выражению можно поставить в соответствие конечный автомат, который является формальной моделью алгоритма распознавания лексем, обозначаемых данным регулярным выражением. В наиболее общих терминах конечный автомат -распознаватель определяется конечным множеством характерных для него состояний входного потока и переходов между ними. Изменение состояния происходит при получении символов входного потока из заданного алфавита в соответствии с функцией переходов , которая определяет возможные последующие состояния по входному символу и текущему состоянию. Среди возможных состояний выделяется исходное (начальное) и заключительные (допускающие) состояния в которых конечный автомат-распознаватель может находиться, соответственно, при начале и завершении обработки лексем входного потока. Если входная последовательность символов может порождать последовательность переходов, которая может переводить конечный автомат из начального состояния в одно из заключительных, то она считается допускающей и принадлежит распознаваемому им регулярному множеству.

1
Q1 Q4 Q2
Q2 Q3 Q1
Q3 Q2 Q4
Q4 Q1 Q3

Столбцы таблицы переходов обозначают символы входного алфавита, а строки соответствуют текущим состояниям ДКА . Элементы каждой строки указывают состояния ДКА , в которые он должен переходить из текущего состояния при получении соответствующих символов входного алфавита. В частности, из первой строки данной таблицы переходов следует, что получение символов 0 и 1 в начальном состоянии Q1 переводит ДКА в состояния Q4 и Q2, соответственно.

При распознавании входной последовательности по таблице переходов легко проследить изменения состояния ДКА с целью определить достигается или нет одно из допускающих состояний. В частности, для бинарного вектора 01001000 с четным числом нулей и единиц рассмотренный ДКА порождает следующую последовательность переходов, где каждый переход помечен вызывающим его символом входного алфавита:

Q1 0 Q4 1 Q3 0 Q2 0 Q3 1 Q4 1 Q1 0 Q4 0 Q1

Эта последовательность переходов завершается допускающим состоянием Q1, следовательно, бинарный вектор 01001000 принадлежит регулярному множеству, распознаваемому рассмотренным ДКА и удовлетворяет приведенному выше регулярному выражению.

В заключение следует отметить, что рассмотренный неформальный способ конструирования

Основные определения Регулярные выражения в алфавите Σ и регулярные множества, которые они обозначают, определяются рекурсивно следующим образом: 1) – регулярное выражение, обозначающее регулярное множество; 2) e – регулярное выражение, обозначающее регулярное множество ; 3) если a Σ, то a – регулярное выражение, обозначающее регулярное множество ; 4) если p и q – регулярные выражения, обозначающие регулярные множества P и Q, то а) (p+q) – регулярное выражение, обозначающее P Q; б) pq – регулярное выражение, обозначающее PQ; в) p* – регулярное выражение, обозначающее P*; 5) ничто другое не является регулярным выражением.

Основные определения Расстановка приоритетов: * (итерация) – наивысший приоритет; конкатенация; + (объединение). Таким образом, 0 + 10* = (0 + (1 (0*))). Примеры: 1. 01 означает <01>; 2. 0* – <0*>; 3. (0+1)* – <0, 1>*; 4. (0+1)* 011 – означает множество всех цепочек, составленных из 0 и 1 и оканчивающихся цепочкой 011; 5. (a+b) (a+b+0+1)* означает множество всех цепочек <0, 1, a, b>*, начинающихся с a или b.

Основные определения Леммы: 1) α + β = β + α 2) * = e 3) α + (β + γ) = (α + β) + γ 4) α(βγ) = (αβ)γ 5) α(β + γ) = αβ + αγ 6) (α + β)γ = αγ + βγ 7) αe = eα = α 8) α = 9) α+α* = α* 10) (α*)* = α* 11) α+α = α 12) α+ = α

Связь РВ и РМ РМ – языки, порождаемые РВ. Например: x = a+b, y = c+d, x X = , y Y = , x + y X Y = . Конкатенация: xy XY = . к(и+о)т <к><и, о> <т>= <кит, кот>или по леммам № 5 и № 6 к(и+о)т = кит + кот <кит, кот>. Итерация: x = a, x* X* = , т. е. x* = e + xxx + …

Связь РВ и РМ Итерация конкатенации и объединения: (xy)* = e + xyxyxy + … (x + y)* = e + (x + y)(x + y) + … = = e + xx + xy + yx + yy + xxx + … Пример: 0 + 1(0+1)* <0>( <1><0, 1>*) = <0, 1, 10, 11, 100, 101, 110, 111…>. Объединение коммутативно: x + y = y + x Конкатенация – нет: xy ≠ yx

Связь РВ и РМ Примеры на приоритет: x + yz , (x + y)z , x + y* , (x + y)* , (xy)* , xy* . Новые леммы: a* + e = a*; (a + e)* = a*; a*a* = a*; e* = e; и т. д.

Регулярные системы уравнений Уравнение с регулярными коэффициентами X = a. X + b имеет решение (наименьшую неподвижную точку) a*b: aa*b + b = (aa* + e)b = a*b Система уравнений с регулярными коэффициентами: X 1 = α 10 + α 11 X 1 + α 12 X 2 + … + α 1 n. Xn X 2 = α 20 + α 21 X 1 + α 22 X 2 + … + α 2 n. Xn …………………………. . Xn = αn 0 + αn 1 X 1 + αn 2 X 2 + … + αnn. Xn Неизвестные – Δ = .

Регулярные системы уравнений Алгоритм решения (метод Гаусса): Шаг 1. Положить i = 1. Шаг 2. Если i = n, перейти к шагу 4. Иначе записать уравнения для Xi в виде Xi = αXi + β (β = β 0 + βi+1 Xi+1 + … + βn. Xn). Затем в правых частях для уравнений Xi+1, …, Xn заменим Xi регулярным выражением α*β. Шаг 3. Увеличить i на 1 и вернуться к шагу 2. Шаг 4. Записать уравнение для Xn в виде Xn = αXn + β. Перейти к шагу 5 (при этом i = n). Шаг 5. Уравнение для Xi имеет вид Xi = αXi + β. Записать на выходе Xi = α*β, в уравнениях для Xi– 1, …, X 1 подставляя α*β вместо Xi. Шаг 6. Если i = 1, остановиться, в противном случае уменьшить i на 1 и вернуться к шагу 5.

Преобразование ДКА в РВ Для ДКА M = (Q, Σ, δ, q 0, F) составим систему с регулярными коэффициентами где Δ = Q: 1. полагаем αij: = ; 2. если δ(Xi, a) = Xj, a Σ, то αij: = αij + a; 3. если Xi F или δ(Xi,) = HALT, то αi 0: = e. После решения искомое РВ будет X 1 = q 0.

Преобразование ДКА в РВ Пример: для числа с фиксированной точкой получим систему q 0 = + q 0 + sq 1 + pq 2 + dq 3 + q 4 q 1 = + q 0 + q 1 + pq 2 + dq 3 + q 4 q 2 = + q 0 + q 1 + q 2 + q 3 + dq 4 q 3 = e + q 0 + q 1 + q 2 + dq 3 + pq 4 = e + q 0 + q 1 + q 2 + q 3 + dq 4 Здесь: s – знак числа, s = «+» + «–»; p – десятичная точка, p = «. «; d – цифры, d = «0» + «1» + … + «9».

Преобразование ДКА в РВ Решение: q 0 = *(sq 1 + pq 2 + dq 3 + q 4 +) = sq 1 + pq 2 + dq 3 q 1 = + q 0 + q 1 + pq 2 + dq 3 + q 4 = pq 2 + dq 3, q 2 = + q 0 + q 1 + q 2 + q 3 + dq 4 = dq 4, q 3 = e + q 0 + q 1 + q 2 + dq 3 + pq 4 = dq 3 + pq 4 + e, q 4 = e + q 0 + q 1 + q 2 + q 3 + dq 4 = dq 4 + e. Из третьего уравнения: q 3 = dq 3 + pq 4 + e = d*(pq 4 + e). Из четвертого уравнения: q 4 = dq 4 + e = d*.

Преобразование ДКА в РВ Обратный ход: q 3 = d*(pq 4 + e) = d*(pd* + e), q 2 = dq 4 = dd*, q 1 = pq 2 + dq 3 = pdd* + dd*(pd* + e), q 0 = sq 1 + pq 2 + dq 3 = s(pdd* + dd*(pd* + e)) + pdd* + dd*(pd* + e). Таким образом, данному ДКА соответствует РВ s(pdd* + dd*(pd* + e)) + pdd* + dd*(pd* + e). Упростим: s(pdd* + dd*(pd* + e)) + pdd* + dd*(pd* + e) = = spdd* + sdd*(pd* + e) + pdd* + dd*(pd* + e) = (s + e)(pdd* + dd*(pd* + e)) Для более короткой записи можно использовать положительную итерацию aa* = a*a = a+: (s + e)(pdd* + dd*(pd* + e)) = (s + e)(pd+ + d+pd* + d+)

Преобразование ДКА в РВ Сопоставление графа функции переходов ДКА основным операциям с регулярными выражениями: q 0 a b a q 1 q 2 q 1 q 0 a+b a b ab q 2 a*

Преобразование ДКА в РВ Более сложные комбинации операций: q 0 a q 1 b b b q 0 a q 2 q 1 (a + e)b c b q 0 q 2 ab(cab)* q 0 (a + b)* q 0 a q 1 aa* = a+ q 0 a q 1 a b a a a (ab)+ q 2 b q 1 c e + (a + b)c*

Преобразование ДКА в РВ Для РВ (s + e)(pd+ + d+(pd* + e)): q 0 p q 2 d s p q 1 d d q 3 d p q 4 d q 5 d

Программирование РВ Регулярные выражения: Встроены во многие языки программирования (PHP, Java. Script, …); Реализованы в виде подключаемых компонентов (например, класс Regex для платформы. NET). Отличия в формах записи: x? = x + e x <1, 3>= x + xxx и т. д.

Программирование РВ Конструкции класса Regex (System. Text. Regular. Expressions): Символ Интерпретация Escape-последовательности b При использовании его в квадратных скобках соответствует символу «←» (u 0008) t, r, n, a, f, v Табуляция (u 0009), возврат каретки (u 000 D), новая строка (u 000 A) и т. д. c. X Управляющий символ (например, c. C – это Ctrl+C, u 0003) e Escape (u 001 B) ooo Символ ASCII в восьмеричной системе xhh Символ ASCII в шестнадцатеричной системе uhhhh Символ Unicode Следующий символ не является специальным символом РВ. Этим символом нужно экранировать все специальные символы Пример (в примере приведен шаблон и строка поиска, в строке найденные совпадения подчеркнуты): @»rnw+» – «rn. Здесь имеютсяnдве строки».

Программирование РВ Подмножества символов. Любой символ, кроме конца строки (n) Любой символ из множества [^xxx] Любой символ, кроме символов из множества Любой символ из диапазона ] Вычитание одного множества или диапазона из другого p Любой символ, заданный категорией Unicode с именем name P Любой символ, кроме заданных категорией Unicode с именем name w Множество символов, используемых при задании идентификаторов W Множество символов, не используемых при задании идентификаторов s Пробелы S Все, кроме пробелов d Цифры D Не цифры Примеры: @». +» – «rn. Здесь имеютсяnдве строки»; @»+» – «0 xabcfx»; @»[^fx]+» – «0 xabcfx»; @»+» – «0 xabcfx»; @»[^a-f]+» – «0 xabcfx»; @»]+» – «0 xabcfx»; @»p» – «City Lights»; // Lu – прописные буквы @»P» – «City»; @»p» – «ха. OS»; // Is. Cyrillic – русские буквы

Программирование РВ Привязка ^, A В начале строки $, Z В конце строки или до символа «n» в конце строки z В конце строки G В том месте, где заканчивается предыдущее соответствие b Граница слова B Любая позиция не на границе слова Примеры: @»G(d)» – «(1)(3)(5)(9) «; // три соответствия (1), (2) и (3) @»bnS*ionb» – «nation donation»; @»Bendw*b» – «end sends endure lender».

Программирование РВ Операции (кванторы) *, *? Итерация +, +? Положительная итерация? , ? ? Ноль или одно соответствие , ? Точно n соответствий , ? По меньшей мере, n соответствий , ? От n до m соответствий Примеры (первые кванторы – жадные, ищут как можно большее число элементов, вторые – ленивые, ищут как можно меньшее число элементов): @»d<3, >» – «888 -5555»; @»^d<3>» – «913 -913″; @»-d<3>$» – «913 -913″; @»5+? 5» – «888 -5555″; // три совпадения – 55, 55 и 55 @»5+5» – «888 -5555».

Программирование РВ Группирование () Группа, автоматически получающая номер (? :) Не сохранять группу (?) или (? «имя») При обнаружении соответствия создается именованная группа (?) или Удаление ранее определенной группы и (? «имя– имя») сохранение в новой группе подстроки между ранее определенной группой и новой группой (? imnsx:) Включает или выключает в группе любую из пяти (? –imnsx:) возможных опций: i – нечувствительность к регистру; s – одна строка (тогда «. » – это любой символ); m – многострочный режим («^» , «$» – начало и конец каждой строки); n – не захватывать неименованные группы; x – исключить не преобразованные в escapeпоследовательность пробелы из шаблона и включить комментарии после знака номера (#) (? =) Положительное утверждение просмотра вперед нулевой длины

Программирование РВ (? !) Отрицательное утверждение просмотра вперед нулевой длины (?) Невозвращаемая (жадная) часть выражения Примеры: @»(an)+» – «bananas annals»; @»an+» – «bananas annals»; // сравните, три совпадения – an, an и ann @»(? i: an)+» – «ba. NAnas annals»; @»+(? =d)» – «abc xyz 12 555 w»; @»(?

Src=»https://сайт/presentation/-112203859_437213351/image-24.jpg» alt=»Программирование РВ Ссылки число Ссылка на группу k Ссылка на именованную группу Примеры: @»> Программирование РВ Ссылки число Ссылка на группу k Ссылка на именованную группу Примеры: @»(w)1″ – «deep»; @»(? w)k » – «deep». Конструкции изменения | Альтернатива (соответствует операции объединения) (? (выражение)да|нет) Сопоставляется с частью «да» , если выражение соответствует; в противном случае сопоставляется с необязательной частью «нет» (? (имя)да|нет), Сопоставляется с частью «да» , если названное имя (? (число)да|нет) захвата имеет соответствие; в противном случае сопоставляется с необязательной частью «нет» Пример: @»th(e|is|at)» – «this is the day»;

Программирование РВ Подстановки $число Замещается часть строки, соответствующая группе с указанным номером $ <имя>Замещается часть строки, соответствующая группе с указанным именем $$ Подставляется $ $& Замещение копией полного соответствия $` Замещение текста входной строки до соответствия $» Замещение текста входной строки после соответствия $+ Замещение последней захваченной группы $_ Замещение всей строки Комментарии (? #) Встроенный комментарий # Комментарий до конца строки

Программирование РВ Результаты работы Regex: Regex Matches() Match. Collection Match Groups() Group. Collection Group Captures() Capture. Collection Captures()

Программирование РВ Пример на языке C++ CLI (Visual C++/CLR/Консольное приложение CLR): int main() < Regex ^r = gcnew Regex(L"((\d)+)+"); Match ^m = r->Match(L»123 456″); int match. Count = 0; while (m->Success) < Console: : Write. Line(L"Соответствие <0>«, ++match. Count); for (int i = 1; i Groups->Count; i++) < Group ^g = m->Groups[i]; Console: : Write. Line(L» Группа <0>= «<1>«», i, g->Value); for (int j = 0; j Captures->Count; j++) < Capture ^c = g->Captures[j]; Console: : Write. Line(L» Захват <0>= «<1>«, позиция = <2>, длина = <3>«, j, c, c->Index, c->Length); > > m = m->Next. Match(); > return 0; > System: : Text: : Regular. Expressions

Включение действий и поиск ошибок Ограничение количества значащих цифр в числе: (s + e)(pd+ + d+(pd* + e)) s = +|p = . d = d s + e = s? = (+|-)? pd* + e = (pd*)? = (. d*)? @»(+|-)? (. d+|d+(. d*)?)» или @»^(+|-)? (. d+|d+(. d*)?)$» Regex r = new Regex(@»^(+|-)? (. (? «digit»d)+|(? «digit»d)+(. (? «digit»d)*)?)$»); Match m = r. Match(«+1. 23456789»); if (m. Success) < Group g = m. Groups["digit"]; if (g. Captures. Count

Включение действий и поиск ошибок Определение позиции ошибки: Regex r = new Regex(@»(+|-)? (. (? «digit»d)+|(? «digit»d)+(. (? «digit»d)*)?)»); string str = «+1. 2345!678»; Match m = r. Match(str); if (m. Success) < Group g = m. Groups["digit"]; if (g. Captures. Count 0) Console. Write. Line("Ошибка в позиции 1: неожиданный символ "<0>«», str); else if (m. Length

Включение действий и поиск ошибок Определение позиции ошибки: 1. первая позиция входной цепочки (1), если первое соответствие не начинается с позиции Index = 0; 2. позиция, следующая за последним соответствием (match. Length + 1), если она не совпадает с последней позицией входной цепочки; 3. позиция первого разрыва между соответствиями (match[i]. Index + match[i]. Length + 1), если символ, следующий за предыдущим соответствием, не является первым символом следующего соответствия.

Index) break; index = m[i]. Index + m[i]. Length; > Console. Write. Line(«Ошибка в позиции <0>«<1>«», index + 1, str); > «abc. xyz. pqr» – правильно; «+abc. xyz. pqr» – ошибка в позиции 1 («+»); «abc. xyz. pqr!» – ошибка в позиции 12 («!»); «abc. xyz!. pqr» – ошибка в позиции 8 («!»).

Включение действий и поиск ошибок Но! «abc. xyz. +pqr» – ошибка в позиции 8 («. »). Новый вариант шаблона: @»w+(. w+)*(. (? !$))? » Проверка: «abc. xyz. +pqr» – ошибка в позиции 9 («+»); «abc. xyz. pqr. » – ошибка в позиции 12 («. »).

Сбалансированные определения: «(? «x»)» добавляет в коллекцию с именем «x» один элемент; «(? «-x»)» убирает из коллекции «x» один элемент; «(? (x)(? !))» проверяет, что в коллекции «x» не осталось элементов. Язык L, описывающий вложенные операторы языка Pascal «begin end; »: @»^s*((? «begins+)+(? «-begin»ends*; s*)+)*(? (begin)(? !))$».

Для дальнейшего изучения свойств конечных автоматов и, в частности, для решения задачи синтеза важное значение имеет следующая теорема.

Теорема 7.7 (теорема о детерминизации). Для любого конечного автомата может быть построен эквивалентный ему детерминированный конечный автомат.

Для того чтобы доказать теорему, нужно, во-первых, описать алгоритм построения детерминированного конечного автомата по исходному; во-вторых, обосновать этот алгоритм, строго доказав, что он действительно дает конечный автомат, который является детерминированным и эквивалентным исходному. Здесь мы приведем только сам алгоритм построения детерминированного автомата.

Преобразование произвольного конечного автомата к эквивалентному детерминированному осуществляется в два этапа: сначала удаляются дуги с меткой \lambda , затем проводится собственно детерминизация.

1. Удаление λ-переходов (дуг с меткой \lambda ).

Чтобы перейти от исходного конечного автомата M=(V,Q,q_0,F,\delta) к эквивалентному конечному автомату M»=(V,Q»,q_0,F»,\delta») без λ-переходов, достаточно в исходном графе M проделать следующие преобразования.

а. Все состояния, кроме начального, в которые заходят только дуги с меткой \lambda , удаляются; тем самым определяется множество Q» конечного автомата M» . Понятно, что Q»\subseteq Q . При этом полагаем, что начальное состояние остается прежним.

Илон Маск рекомендует:  Что такое код getcurrentpdb

б. Множество дуг конечного автомата M» и их меток (тем самым и функция переходов M» ) определяется так: для любых двух состояний p,r\in Q»,

Таким образом, в M» сохраняются все дуги M , метки которых отличны от \lambda и которые соединяют пару (вершин) состояний из множества Q» (не удаляемых согласно п. а). Кроме этого, для любой тройки состояний p,q,r (не обязательно различных!), такой, что p,r\in Q» и существует путь ненулевой длины из p в q , метка которого равна \lambda (т.е. путь по λ-переходам), а из q в r ведет дуга, метка которой содержит символ a входного алфавита, в M» строится дуга из p в r , метка которой содержит символ a (см. рис. 7.11).

в. Множество заключительных состояний F» конечного автомата M» содержит все состояния q\in Q» , т.е. состояния конечного автомата M , не удаляемые согласно п. а, для которых имеет место q\Rightarrow_<\lambda>^<\ast>q_f для некоторого q_f\in F (т.е. либо состояние q само является заключительным состоянием конечного автомата M , либо из него ведет путь ненулевой длины по дугам с меткой \lambda в одно из заключительных состояний конечного автомата M ) (рис. 7.13).

2. Собственно детерминизация.

Пусть M=(Q,V,q_0,F,\delta) — конечный автомат без λ-переходов. Построим эквивалентный M детерминированный конечный автомат M_1 .

Этот конечный автомат определяется таким образом, что его множество состояний есть множество всех подмножеств множества состояний конечного автомата M . Это значит, что каждое отдельное состояние конечного автомата M_1 определено как некоторое подмножество множества состояний конечного автомата M . При этом начальным состоянием нового конечного автомата (т.е. M_1 ) является одноэлементное подмножество, содержащее начальное состояние старого конечного автомата (т.е. M ), а заключительными состояниями нового конечного автомата являются все такие подмножества Q , которые содержат хотя бы одну заключительную вершину исходного конечного автомата M .

Впредь, допуская некоторую вольность речи, мы будем иногда называть состояния конечного автомата M_1 состояниями-множествами. Важно, однако, четко усвоить, что каждое такое состояние-множество есть отдельное состояние нового конечного автомата, но никак не множество его состояний. В то же время для исходного («старого») конечного автомата M это именно множество его состояний. Образно говоря, каждое подмножество состояний старого конечного автомата «свертывается» в одно состояние нового конечного автомата*.

*Формально следовало бы определить множество Q_1 как множество, находящееся во взаимно однозначном соответствии с множеством 2^Q , но нам все-таки удобнее считать, что Q_1 совпадает с 2^Q , — ведь множеством состояний конечного автомата может быть любое непустое конечное множество.

Функция переходов нового конечного автомата определена так, что из состояния-множества S по входному символу а конечный автомат M_1 переходит в состояние-множество, представляющее собой объединение всех множеств состояний старого конечного автомата, в которые этот старый конечный автомат переходит по символу а из каждого состояния множества S . Таким образом, конечный автомат M_1 является детерминированным по построению.

Приведенное выше словесное описание можно перевести в формулы следующим образом: строим конечный автомат M_1 так, что


T\in2^Q\>,\\ (\forall S\subseteq Q)(\forall a\in V)\Bigl(\delta_1(S,a)= \bigcup\limits_\delta(q,a)\Bigr). \end

Обратим внимание на то, что среди состояний нового конечного автомата есть состояние \varnothing , причем, согласно (7.8), \delta_1(\varnothing,a)=\varnothing для любого входного символа a . Это значит, что, попав в такое состояние, конечный автомат M_1 уже его не покинет. Вообще же любое состояние q конечного автомата, такое, что для любого входного символа a имеем \delta(q,a)=q , называют поглощающим состоянием конечного автомата. Таким образом, состояние \varnothing детерминированного конечного автомата M_1 является поглощающим. Полезно заметить также, что \delta_1(S,a)=\varnothing тогда и только тогда, когда для каждого q\in S (состояния старого конечного автомата из множества состояний S ) \delta(q,a)=\varnothing , т.е. в графе M из каждого такого состояния q не выходит ни одна дуга, помеченная символом a .

Можно доказать, что полученный по такому алгоритму конечный автомат эквивалентен исходному.

Пример 7.9. Детерминизируем конечный автомат, изображенный на рис. 7.14.

Эквивалентный конечный автомат без λ-переходов изображен на рис. 7.15. Заметим, что вершина q_2 исчезает, так как в нее заходят только «пустые» дуги.

Чтобы детерминизировать полученный автомат, совершенно не обязательно выписывать все его 2^3=8 состояний, среди которых многие могут оказаться не достижимыми из начального состояния \ . Чтобы получить достижимые из \ состояния, и только их, воспользуемся так называемым методом вытягивания.

Этот метод в общем случае можно описать так.

В исходном конечном автомате (без пустых дуг) определяем все множества состояний, достижимых из начального, т.е. для каждого входного символа a находим множество \delta(q_0,a) . Каждое такое множество в новом автомате является состоянием, непосредственно достижимым из начального.

Для конечного автомата на рис. 7.15 имеем:

Так как новых состояний-множеств больше не появилось, процедура «вытягивания» на этом заканчивается, и мы получаем граф, изображенный на рис. 7.16.

Дополнение регулярного языка

Одним из важных теоретических следствий теоремы о детерминизации является следующая теорема.

Теорема 7.8. Дополнение регулярного языка есть регулярный язык.

Пусть L — регулярный язык в алфавите V . Тогда дополнение языка L (как множества слов) есть язык \overline=V^<\ast>\setminus L .

Согласно теореме 7.7, для регулярного языка L может быть построен детерминированный конечный автомат M , допускающий L . Поскольку в детерминированном автомате из каждой вершины по каждому входному символу определен переход в точности в одну вершину, то, какова бы ни была цепочка x в алфавите V , для нее найдется единственный путь в M , начинающийся в начальном состоянии, на котором читается цепочка x . Ясно, что цепочка x допускается автоматом M , то есть x\in L(M) , тогда и только тогда, когда последнее состояние указанного пути является заключительным. Отсюда следует, что цепочка x\notin L(M) тогда и только тогда, когда последнее состояние указанного пути не заключительное. Но нам как раз и нужен конечный автомат M» , который допускает цепочку x тогда и только тогда, когда ее не допускает исходный конечный автомат M . Следовательно, превращая каждое заключительное состояние M в не заключительное и наоборот, получим детерминированный автомат, допускающий дополнение языка L .

Доказанная теорема позволяет строить конечный автомат, не допускающий определенное множество цепочек, следующим методом: строим сначала автомат, допускающий данное множество цепочек, затем детерминизируем его и переходим к автомату для дополнения так, как это указано в доказательстве теоремы 7.8.

Пример 7.10. а. Построим конечный автомат, допускающий все цепочки в алфавите \ <0;1\>, кроме цепочки 101.

Сначала построим конечный автомат, допускающий единственную цепочку 101. Этот автомат приведен на рис. 7.17.

Этот автомат квазидетерминированный, но не детерминированный, так как он не полностью определен. Проведем его детерминизацию и получим детерминированный эквивалентный конечный автомат, изображенный на рис. 7.18.

И наконец, переходя к дополнению (и переименовывая состояния), получим автомат, изображенный на рис. 7.19.

Обратим внимание, что в полученном автомате все вершины, кроме вершины s_3 , являются заключительными.

Заметим также, что переход к дополнению, о котором идет речь в доказательстве теоремы 7.8, может быть проведен только в детерминированном автомате. Если бы мы поменяли ролями заключительные и незаключительные вершины в автомате, изображенном на рис. 7.17, то получили бы автомат, допускающий язык \ <\lambda,1,10\>, который не является — как нетрудно сообразить — множеством всех цепочек, отличных от цепочки 101.

Отметим также, что конечный автомат на рис. 7.19 допускает все цепочки, содержащие вхождение цепочки 101, но не совпадающие с самой этой цепочкой. Вот, например, путь, несущий цепочку 1011: s_0,s_1,s_2,s_3,t .

б. Построим конечный автомат, допускающий все цепочки в алфавите \ <0;1\>, кроме тех, которые содержат вхождение цепочки 101. Рассмотрим язык L , каждая цепочка которого содержит вхождение цепочки 101. Его можно задать так:

Нам нужно построить автомат для дополнения языка L .

Непосредственно по регулярному выражению в этом случае легко построить конечный автомат, допускающий язык L (рис. 7.20).

Затем методом «вытягивания» проведем детерминизацию. Результат детерминизации представлен на рис. 7.21.

Для полного решения задачи осталось только на рис. 7.21 поменять ролями заключительные и не заключительные вершины (рис. 7.22).

в. Обсудим идею построения конечного автомата, допускающего те и только те цепочки в алфавите \ <0;1\>, которые не начинаются цепочкой 01 и не заканчиваются цепочкой 11 (т.е. не разрешаются цепочки вида 01x и цепочки вида y11 , каковы бы ни были цепочки x,y\in\ <0;1\>).

В этом случае дополнением языка, для которого нужно построить конечный автомат, является множество всех таких цепочек нулей и единиц, которые начинаются цепочкой 01 или заканчиваются цепочкой 11. Допускающий это множество цепочек автомат строится как автомат для объединения 01(0+1)^<\ast>+(0+1)^<\ast>11 тем способом, который изложен при доказательстве теоремы Клини (см. теорему 7.6).

Из свойства замкнутости класса регулярных языков относительно дополнения (см. теорему 7.8) немедленно вытекает замкнутость этого класса относительно пересечения, теоретико-множественной и симметрической разности.

Следствие 7.3. Для любых двух регулярных языков L_1 и L_2 справедливы следующие утверждения:

1) пересечение L_1\cap L_2 регулярно;
2) разность L_1\setminus L_2 регулярна;
3) симметрическая разность L_1\vartriangle L_2 регулярна.

Справедливость утверждений вытекает из тождеств:

Во-первых, полученные результаты позволяют утверждать, что класс регулярных языков относительно операций объединения, пересечения и дополнения является булевой алгеброй, в которой единицей служит универсальный язык, а нулем — пустой язык. Во-вторых, эти алгебраические свойства семейства регулярных языков позволяют решить важную проблему распознавания эквивалентности двух произвольных конечных автоматов.

Согласно определению 7.10, конечные автоматы эквивалентны, если допускаемые ими языки совпадают. Поэтому, чтобы убедиться в эквивалентности автоматов M_1 и M_2 , достаточно доказать, что симметрическая разность языков L(M_1) и L(M_2) пуста. Для этого, в свою очередь, достаточно построить автомат, допускающий эту разность, и убедиться в том, что допускаемый им язык пуст. В общем случае проблему распознавания того, что язык конечного автомата пуст, называют проблемой пустоты для конечного автомата. Чтобы решить эту проблему, достаточно найти множество заключительных состояний автомата, достижимых из начального состояния. Так как конечный автомат — это ориентированный граф, то решить такую проблему можно, например, с помощью, поиска в ширину. Язык, допускаемый конечным автоматом, пуст тогда и только тогда, когда множество заключительных состояний, достижимых из начального состояния, пусто. Практически эквивалентность конечных автоматов предпочтительнее распознавать, используя алгоритм минимизации, но сейчас нам важно подчеркнуть, что принципиальная возможность решить проблему эквивалентности вытекает из теоремы 7.7 и ее алгебраических следствий.

Построение детерминированного конечного автомата по регулярному выражению

Приведем теперь алгоритм построения по регулярному выражению детерминированного конечного автомата, допускающего тот же язык [?].

Пусть дано регулярное выражение r в алфавите T. К регулярному выражению r добавим маркер конца: (r)#. Такое регулярное выражение будем называть пополненным. В процессе своей работы алгоритм будет использовать пополненное регулярное выражение.

Алгоритм будет оперировать с синтаксическим деревом для пополненного регулярного выражения (r)#, каждый лист которого помечен символом , а каждая внутренняя вершина помечена знаком одной из операций: (конкатенация),| (объединение), * (итерация).

Каждому листу дерева (кроме e -листьев) присвоим уникальный номер, называемый позицией, и будем использовать его, с одной стороны, для ссылки на лист в дереве, и, с другой стороны, для ссылки на символ, соответствующий этому листу. Заметим, что если некоторый символ используется в регулярном выражении несколько раз, он имеет несколько позиций.

Обойдем дерево T снизу-вверх слева-направо и вычислим четыре функции: nullable,firstpos, lastpos и followpos. Три первые функции — nullable, firstpos и lastpos — определены на узлах дерева, а followpos — на множестве позиций. Значением всех функций, кроме nullable, является множество позиций. Функция followpos вычисляется через три остальные функции.

Функция firstpos(n) для каждого узла n синтаксического дерева регулярного выражения дает множество позиций, которые соответствуют первым символам в подцепочках , генерируемых подвыражением с вершиной в n. Аналогично, lastpos(n) дает множество позиций, которым соответствуют последние символы в подцепочках , генерируемых подвыражениями с вершиной n. Для узла n, поддеревья которого (то есть деревья, у которых узел n является корнем) могут породить пустое слово, определимnullable(n)=true, а для остальных узлов nullable(n)=false.

Таблица для вычисления функций nullable, firstpos и lastpos приведена на рис. 3.11.

Пример 3.7 .На рис. 3.12 приведено cинтаксическое дерево для пополненного регулярного выражения (a|b) * abb# с результатом вычисления функций firstpos и lastpos. Слева от каждого узла расположено значение firstpos, справа от узла — значениеlastpos. Заметим, что эти функции могут быть вычислены за один обход дерева.

Если i — позиция, то followpos(i) есть множество позиций j таких, что существует некоторая строка. cd . входящая в язык, описываемый регулярным выражением, такая, что позиция i соответствует этому вхождению c, а позиция j — вхождениюd.

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

1. Пусть n — внутренний узел с операцией (конкатенация), u и v — его потомки. Тогда для каждой позиции i, входящей вlastpos(u), добавляем к множеству значений followpos(i) множество firstpos(v).

2. Пусть n — внутренний узел с операцией * (итерация), u — его потомок. Тогда для каждой позиции i, входящей вlastpos(u), добавляем к множеству значений followpos(i) множество firstpos(u).

Пример 3.8 . Результат вычисления функции followpos для регулярного выражения из предыдущего примера приведен на рис. 3.13.

Алгоритм 3.3 . Прямое построение ДКА по регулярному выражению.

Вход . Регулярное выражение r в алфавите T.

Выход . ДКА M = (Q, T, D, q 0 , F), такой что L(M) = L(r).

Метод . Состояния ДКА соответствуют множествам позиций.

Вначале Q и D пусты. Выполнить шаги 1-6:

(1) Построить синтаксическое дерево для пополненного регулярного выражения (r)#.

по общему количеству символов алфавита символов и знаков операций и скобок в записи r .

Базис . Автоматы для выражений длины 1: и показаны на следующем рисунке.

Заметим, что у каждого из этих трех автоматов множество заключительных состояний состоит из одного состояния.

Индукционный шаг . Предположим теперь, что для каждого регулярного выражения длины регулярное выражение r длины k+1 . В зависимости от последней операции оно может иметь один из трех видов: (r 1 + r 2), (r 1 r 2) или (r 1) * . Пусть и — это НКА, распознающие языки L r1 и L r2 , соответственно. Не ограничивая общности, мы будем предполагать, что у них разные состояния: .

Тогда НКА , диаграмма которого представлена на рис. 5.2 , распознает язык .

У этого автомата множество состояний , где q 0 — это новое начальное состояние, q f — новое (единственное!) заключительное состояние, а программа включает программы автоматов M 1 и M 2 и четыре новых команды -переходов: . Очевидно, что язык, распознаваемый НКА M , включает все слова из L < M 1 >и из L < M 2 >. С другой стороны, каждое слово переводит q 0 в q f , и после первого шага несущий его путь проходит через q 0 1 или q 0 2 . Так как состояния M 1 и M 2 не пересекаются, то в первом случае этот путь может попасть в q f только по -переходу из q f 1 и тогда . Аналогично, во втором случае .

Для выражения диаграмма НКА , распознающего язык L r , представлена на следующем рисунке.

У этого автомата множество состояний , начальное состояние q 0 = q 0 1 , заключительное состояние q f =q f 2 , а программа включает программы автоматов M 1 и M 2 и одну новую команду — -переход из заключительного состояния M 1 в начальное состояние M 2 , т.е. . Здесь также очевидно, что всякий путь из q 0 = q 0 1 в q f =q f 2 проходит через -переход из q f 1 в q 0 2 . Поэтому всякое слово , допускаемое M , представляет конкатенацию некоторого слова из L M1 > с некоторым словом из L M2 > , и любая конкатенация таких слов допускается. Следовательно, НКА M распознает язык .

Пусть r = r 1 * . Диаграмма НКА , распознающего язык L r =L r1* = L M1 * представлена на рис. 5.3 .

У этого автомата множество состояний , где q 0 — это новое начальное состояние, q f — новое (единственное!) заключительное состояние, а программа включает программу автомата M 1 и четыре новых команды -переходов: . Очевидно, . Для непустого слова w по определению итерации для некоторого k >= 1 слово w можно разбить на k подслов: w=w 1 w 2 . w k и все . Для каждого i= 1. ,k слово w i переводит q 0 1 в q f 1 . Тогда для слова w в диаграмме M имеется путь

Следовательно, . Обратно, если некоторое слово переводит q 0 в q f , то либо оно есть либо его несет путь , который, перейдя из q 0 в q 0 1 и затем пройдя несколько раз по пути из q 0 1 в q f 1 и вернувшись из q f 1 в q 0 1 по -переходу, в конце концов из q f 1 по -переходу завершается в q f . Поэтому такое слово .

Из теорем 4.2 и 5.1 непосредственно получаем

Следствие 5.1 . Для каждого регулярного выражения можно эффективно построить детерминированный конечный автомат , который распознает язык, представляемый этим выражением.

Это утверждение — один из примеров теорем синтеза : по описанию задания (языка как регулярного выражения ) эффективно строится программа (ДКА), его выполняющая. Справедливо и обратное утверждение — теорема анализа .

Теорема 5.2 . По каждому детерминированному (или недетерминированному) конечному автомату можно построить регулярное выражение , которое представляет язык, распознаваемый этим автоматом.

Доказательство этой теоремы достаточно техническое и выходит за рамки нашего курса.

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

Автомат M r , который строится в доказательстве теоремы 5.1

Лекции по конструированию компиляторов глава 2 лексический анализ

Лекции по
конструированию компиляторов

Предлагаемая вниманию читателя книга основана на курсе лекций, прочитанных автором на факультете вычислительной математики и кибернетики Московского государственного университета в 1991-1993 гг. Автор надеется, что издание книги восполнит существенный пробел в литературе на руссом языке по разработке компиляторов.

Содержание книги представляет собой «классические» разделы предмета: лексический и синтаксический анализ, организация памяти транслятора (таблицы символов) и периода исполнения (магазина), генерация кода, в частности генерация арифметических и логических выражений. Рассматриваются некоторые средства автоматизации процесса разработки трансляторов, такие как LEX, YACC, Супер, методы генерации оптимального кода. Сделана попытка на протяжении всего изложения провести единую «атрибутную» точку зрения на процесс разработки компилятора. В книге не затрагиваются чрезвычайно важные вопросы глобальной оптимизации и разработки компиляторов для машин с параллельной архитектурой. Автор надеется восполнить эти пробелы в будущем.

Книга будет полезной как студентам и аспирантам программистских специальностей, так и профессионалам в этих областях.

Глава 1. Введение 6

1.1. Место компилятора в программном обеспечении 6

1.2. Структура компилятора 7


Глава 2. Лексический анализ 11

2.1. Регулярные множества и регулярные выражения 13

2.2. Конечные автоматы 14

2.3. Построение детерминированного конечного
автомата по недетерминированному 16

2.4. Построение детерминированного конечного
автомата по регулярному выражению 18

2.5. Построение детерминированного конечного
автомата с минимальным числом состояний 21

2.6. Программирование лексических анализаторов 23

2.7. Конструктор лексических анализаторов LEX 27

Глава 3. Синтаксический анализ 32

3.1. Основные понятия и определения 32

3.2. Таблично-управляемый предсказывающий разбор 34

3.2.1. Алгоритм разбора сверху-вниз 34

3.2.2. Множества FIRST и FOLLOW 38

3.2.3. Конструирование таблиц
предсказывающего анализатора 40

3.2.4. LL(1)-грамматики 41

3.2.5. Удаление левой рекурсии 42

3.2.6. Левая факторизация 44

3.2.7. Рекурсивный спуск 45

3.2.8. Диаграммы переходов для рекурсивного спуска 46

3.2.9. Восстановление после синтаксических ошибок 49

3.3. Разбор снизу-вверх типа сдвиг-свертка 50

3.3.2. LR(k)-анализаторы 52

3.3.3. LR грамматики 57

3.3.4. Конфликты разбора типа сдвиг-свертка 63

3.3.5. Восстановление после синтаксических ошибок 64

Глава 4. Элементы теории перевода 65

4.1. Преобразователи с магазинной памятью 65

4.2. Синтаксически управляемый перевод 66

4.3. Атрибутные грамматики 70

4.3.1. Определение атрибутных грамматик 70

4.3.2. Атрибутированное дерево разбора 71

4.3.3. Язык описания атрибутных грамматик 72

4.3.4. Классы атрибутных грамматик и их реализация 75

Глава 5. Контекстные условия языков программирования 77

5.1. Описание областей видимости и блочной структуры 77

5.2. Структура среды Модулы-2 78

5.3. Занесение в среду и поиск объектов 81

Глава 6. Организация таблиц символов компилятора 89

6.1. Таблицы идентификаторов и таблицы символов 89

6.2. Таблицы идентификаторов 90

6.3. Таблицы символов и таблицы расстановки 93

6.4. Функции расстановки 94

6.5. Таблицы на деревьях 96

6.6. Реализация блочной структуры 100

6.7. Сравнение различных методов реализации таблиц 100

Глава 7. Промежуточные представления программы 102

7.1. Представление в виде ориентированного графа 102

7.2. Трехадресный код 102

7.3. Линеаризованные представления 107

7.4. Виртуальная машина Java 109

7.5. Организация информации в генераторе кода 113

7.6. Уровень промежуточного представления 115

Глава 8. Генерация кода 116

8.1. Модель машины 116

8.2. Динамическая организация памяти 119

8.2.1. Организация магазина со статической цепочкой 120

8.2.1. Организация магазина с дисплеем 124

8.3. Назначение адресов 126

8.4. Трансляция переменных 128

8.5. Трансляция целых выражений 134

8.6. Распределение регистров при вычислении
арифметических выражений 136

8.7. Трансляция логических выражений 145

8.8. Выделение общих подвыражений 153

8.9. Генерация оптимального кода методами
синтаксического анализа 157

8.9.1. Сопоставление образцов 157

8.9.2. Синтаксический анализ для Т-грамматик 160

8.9.3. Выбор дерева вывода наименьшей стоимости 168

Глава 1. Введение

1.1. Место компилятора в программном обеспечении

Компиляторы составляют существенную часть программного обеспечения ЭВМ. Это связано с тем, что языки высокого уровня стали основным средством разработки программ. Только очень незначительная часть программного обеспечения, требующая особой эффективности, программируется с помощью ассемблеров. В настоящее время распространено довольно много языков программирования. Наряду с традиционными языками, такими, как Фортран, широкое распространение получили так называемые «универсальные языки» (Паскаль, Си, Модула-2, Ада и другие), а также некоторые специализированные (например, язык обработки списочных структур Лисп). Кроме того, большое распространение получили языки, связанные с узкими предметными областями, такие, как входные языки пакетов прикладных программ.

Для некоторых языков имеется довольно много реализаций. Например, реализаций Паскаля, Модулы-2 или Си для ЭВМ типа IBM/PC на рынке десятки.

С другой стороны, постоянно растущая потребность в новых компиляторах связана с бурным развитием архитектур ЭВМ. Это развитие идет по различным направлениям. Совершенствуются старые архитектуры как в концептуальном отношении, так и по отдельным, конкретным линиям. Это можно проиллюстрировать на примере микропроцессора Intel-80X86. Последовательные версии этого микропроцессора 8086, 80186, 80286, 80386, 80486, 80586 отличаются не только техническими характеристиками, но и, что более важно, новыми возможностями и, значит, изменением (расширением) системы команд. Естественно, это требует новых компиляторов (или модификации старых). То же можно сказать о микропроцессорах Motorola 68010, 68020, 68030, 68040.

В рамках традиционных последовательных машин возникает большое число различных направлений архитектур. Примерами могут служить архитектуры CISC, RISC. Такие ведущие фирмы, как Intel, Motorola, Sun, DEC, начинают переходить на выпуск машин с RISC-архитектурами. Естественно, для каждой новой системы команд требуется полный набор новых компиляторов с распространенных языков.

Наконец , бурно развиваются различные параллельные архитектуры. Среди них отметим векторные, многопроцессорные, с широким командным словом (вариантом которых являются суперскалярные ЭВМ). На рынке уже имеются десятки типов ЭВМ с параллельной архитектурой, начиная от супер-ЭВМ (Cray, CDC и другие), через рабочие станции (например, IBM/RS-6000) и кончая персональными (например, на основе микропроцессора I-860). Естественно, для каждой из машин создаются новые компиляторы для многих языков программирования. Здесь необходимо также отметить, что новые архитектуры требуют разработки совершенно новых подходов к созданию компиляторов, так что наряду с собственно разработкой компиляторов ведется и большая научная работа по созданию новых методов трансляции.

1.2. Структура компилятора

Обобщенная структура компилятора и основные фазы компиляции показаны на рис. 1.1.

На фазе лексического анализа (ЛА) входная программа, представляющая собой поток символов, разбивается на лексемы — слова в соответствии с определениями языка. Основным формализмом, лежащим в основе реализации лексических анализаторов, являются конечные автоматы и регулярные выражения. Лексический анализатор может работать в двух основных режимах: либо как подпрограмма, вызываемая синтаксическим анализатором за очередной лексемой, либо как полный проход, результатом которого является файл лексем.

В процессе выделения лексем ЛА может как самостоятельно строить таблицы имен и констант, так и выдавать значения для каждой лексемы при очередном обращении к нему. В этом случае таблица имен строится в последующих фазах (например, в процессе синтаксического анализа).

анализ Поток лексем
таблицы имен
Конечные и констант
автоматы
Синтаксический Диагностика
анализ
Дерево разбора
Контекстно- + таблицы
свободные имен и констант
грамматики

Контекстный
анализ Диагностика
Атрибутированное
Атрибутные дерево +
грамматики таблица символов

Генерация Промежуточная форма
промежуточного (префиксная, пост-
представления фиксная,тройки идр.)

СУ-трансляция
Оптимизация
Промежуточная форма
Потоковый (ориентированный граф)
анализ


Генерация кода
Таблицы решений,
Объектный
динамическое модуль
программирование и др

Н а этапе ЛА обнаруживаются некоторые (простейшие) ошибки (недопустимые символы, неправильная запись чисел, идентификаторов и др.).

Основная задача синтаксического анализа — разбор структуры программы. Как правило, под структурой понимается дерево, соответствующее разбору в контекстно-свободной грамматике языка. В настоящее время чаще всего используется либо LL(1)-анализ (и его вариант — рекурсивный спуск), либо LR(1)-анализ и его варианты (LR(0), SLR(1), LALR(1) и другие). Рекурсивный спуск чаще используется при ручном программировании синтаксического анализатора, LR(1) — при использовании систем автоматизации построения синтаксических анализаторов.

Результатом синтаксического анализа является синтаксическое дерево со ссылками на таблицу имен. В процессе синтаксического анализа также обнаруживаются ошибки, связанные со структурой программы.

На этапе контекстного анализа выявляются зависимости между частями программы, которые не могут быть описаны контекстно-свободным синтаксисом. Это в основном связи «описание-использование», в частности анализ типов объектов, анализ областей видимости, соответствие параметров, метки и другие. В процессе контекстного анализа строится таблица символов, которую можно рассматривать как таблицу имен, пополненную информацией об описаниях (свойствах) объектов.

Основным формализмом, использующимся при контекстном анализе, являются атрибутные грамматики. Результатом работы фазы контекстного анализа является атрибутированное дерево программы. Информация об объектах может быть как рассредоточена в самом дереве, так и сосредоточена в отдельных таблицах символов. В процессе контекстного анализа также могут быть обнаружены ошибки, связанные с неправильным использованием объектов.

Затем программа может быть переведена во внутреннее представление. Это делается для целей оптимизации и/или удобства генерации кода. Еще одной целью преобразования программы во внутреннее представление является желание иметь переносимый компилятор. Тогда только последняя фаза (генерация кода) является машинно-зависимой. В качестве внутреннего представления может использоваться префиксная или постфиксная запись, ориентированный граф, тройки, четверки и другие.

Фаз оптимизации может быть несколько. Оптимизации обычно делят на машинно-зависимые и машинно-независимые, локальные и глобальные. Часть машинно-зависимой оптимизации выполняется на фазе генерации кода. Глобальная оптимизация пытается принять во внимание структуру всей программы, локальная — только небольших ее фрагментов. Глобальная оптимизация основывается на глобальном потоковом анализе, который выполняется на графе программы и представляет по существу преобразование этого графа. При этом могут учитываться такие свойства программы, как межпроцедурный анализ, межмодульный анализ, анализ областей жизни переменных и т.д.

Наконец , генерация кода — последняя фаза трансляции. Результатом ее является либо ассемблерный модуль, либо объектный (или загрузочный) модуль. В процессе генерации кода могут выполняться некоторые локальные оптимизации, такие как распределение регистров, выбор длинных или коротких переходов, учет стоимости команд при выборе конкретной последовательности команд. Для генерации кода разработаны различные методы, такие как таблицы решений, сопоставление образцов, включающее динамическое программирование, различные синтаксические методы.

Конечно, те или иные фазы транслятора могут либо отсутствовать совсем, либо объединяться. В простейшем случае однопроходного транслятора нет явной фазы генерации промежуточного представления и оптимизации, остальные фазы объединены в одну, причем нет и явно построенного синтаксического дерева.

Лекции по конструированию компиляторов глава 2 лексический анализ

| Таблицы решений, | || Объектный ||

На этапе ЛА обнаруживаются некоторые (простейшие) ошибки

идентификаторов и др.).

Основная задача синтаксического анализа — разбор структуры

программы. Как правило, под структурой понимается дерево,

соответствующее разбору в контекстно-свободной грамматике

языка. В настоящее время чаще всего используется либо LL(1)-

анализ (и его вариант — рекурсивный спуск), либо LR(1)-анализ

и его варианты (LR(0), SLR(1), LALR(1) и другие). Рекурсивный

спуск чаще используется при ручном программировании

синтаксического анализатора, LR(1) — при использовании систем

автоматизации построения синтаксических анализаторов.

Результатом синтаксического анализа является синтаксическое

дерево со ссылками на таблицу имен. В процессе синтаксического

анализа также обнаруживаются ошибки, связанные со структурой

На этапе контекстного анализа выявляются зависимости между

частями программы, которые не могут быть описаны контекстно-

свободным синтаксисом. Это в основном связи «описание-

использование», в частности анализ типов объектов, анализ

областей видимости, соответствие параметров, метки и другие. В

процессе контекстного анализа строится таблица символов,

которую можно рассматривать как таблицу имен, пополненную

информацией об описаниях (свойствах) объектов.

Основным формализмом, использующимся при контекстном

анализе, являются атрибутные грамматики. Результатом работы

фазы контекстного анализа является атрибутированное дерево

программы. Информация об объектах может быть как

рассредоточена в самом дереве, так и сосредоточена в отдельных

таблицах символов. В процессе контекстного анализа также могут

быть обнаружены ошибки, связанные с неправильным

Затем программа может быть переведена во внутреннее

представление. Это делается для целей оптимизации и/или

удобства генерации кода. Еще одной целью преобразования

программы во внутреннее представление является желание иметь

переносимый компилятор. Тогда только последняя фаза (генерация

кода) является машинно-зависимой. В качестве внутреннего

представления может использоваться префиксная или постфиксная

запись, ориентированный граф, тройки, четверки и другие.

Фаз оптимизации может быть несколько. Оптимизации обычно

делят на машинно-зависимые и машинно-независимые, локальные и

глобальные. Часть машинно-зависимой оптимизации выполняется на

фазе генерации кода. Глобальная оптимизация пытается принять

во внимание структуру всей программы, локальная — только

небольших ее фрагментов. Глобальная оптимизация основывается

на глобальном потоковом анализе, который выполняется на графе

программы и представляет по существу преобразование этого

графа. При этом могут учитываться такие свойства программы,

как межпроцедурный анализ, межмодульный анализ, анализ

областей жизни переменных и т.д.

Наконец, генерация кода — последняя фаза трансляции.

Результатом ее является либо ассемблерный модуль, либо

объектный (или загрузочный) модуль. В процессе генерации кода

могут выполняться некоторые локальные оптимизации, такие как

распределение регистров, выбор длинных или коротких переходов,

учет стоимости команд при выборе конкретной последовательности

команд. Для генерации кода разработаны различные методы, такие

как таблицы решений, сопоставление образцов, включающее

динамическое программирование, различные синтаксические

Конечно, те или иные фазы транслятора могут либо

отсутствовать совсем, либо объединяться. В простейшем случае

однопроходного транслятора нет явной фазы генерации

промежуточного представления и оптимизации, остальные фазы

объединены в одну, причем нет и явно построенного

Основы конструирования компиляторов. В.А.Серебряков, М.П.Галочкин

    Яков Алфимов 2 лет назад Просмотров:

1 Основы конструирования компиляторов В.А.Серебряков, М.П.Галочкин

2 2 Предисловие Предлагаемая вниманию читателя книга основана на курсе лекций, прочитанных на факультете вычислительной математики и кибернетики Московского государственного университета и факультете управления и прикладной математики Московского физико-технического института в гг. Авторы надеются, что издание книги восполнит существенный пробел в литературе на русском языке по разработке компиляторов. Содержание книги представляет собой классические разделы предмета: лексический и синтаксический анализ, организация памяти компилятора (таблицы символов) и периода исполнения (магазина), генерация кода. Рассматриваются некоторые средства автоматизации процесса разработки трансляторов, такие как LEX, YACC, СУПЕР, методы генерации оптимального кода. Сделана попытка на протяжении всего изложения провести единую атрибутную точку зрения на процесс разработки компилятора. В книге не затрагиваются чрезвычайно важные вопросы глобальной оптимизации и разработки компиляторов для машин с параллельной архитектурой. Авторы надеются восполнить эти пробелы в будущем. Книга будет полезной как студентам и аспирантам программистских специальностей, так и профессионалам в этих областях. Авторы с благодарностью примут все конструктивные замечания по содержанию книги. В.А.Серебряков, М.П.Галочкин,

3 Оглавление 1 Введение Место компилятора в программном обеспечении Структура компилятора Языки и их представление Алфавиты, цепочки и языки Представление языков Грамматики Формальное определение грамматики Типы грамматик и их свойства Лексический анализ Регулярные множества и выражения Конечные автоматы Алгоритмы построения конечных автоматов Построение недетерминированного конечного автомата по регулярному выражению Построение детерминированного конечного автомата по недетерминированному Построение детерминированного конечного автомата по регулярному выражению Построение детерминированного конечного автомата с минимальным числом состояний Регулярные множества и их представления Программирование лексического анализа Конструктор лексических анализаторов LEX Синтаксический анализ КС-грамматики и МП-автоматы Преобразования КС-грамматик Предсказывающий разбор сверху-вниз Алгоритм разбора сверху-вниз

4 4 ОГЛАВЛЕНИЕ Функции FIRST и F OLLOW Конструирование таблицы предсказывающего анализатора LL(1)-грамматики Удаление левой рекурсии Левая факторизация Рекурсивный спуск Восстановление после синтаксических ошибок Разбор снизу-вверх типа сдвиг-свертка Основа LR(1)-анализаторы Конструирование LR(1)-таблицы LR(1)-грамматики Восстановление после синтаксических ошибок Варианты LR-анализаторов Элементы теории перевода Преобразователи с магазинной памятью Синтаксически управляемый перевод Схемы синтаксически управляемого перевода Обобщенные схемы синтаксически управляемого перевода Атрибутные грамматики Определение атрибутных грамматик Классы атрибутных грамматик и их реализация Язык описания атрибутных грамматик Проверка контекстных условий Описание областей видимости и блочной структуры Занесение в среду и поиск объектов Организация таблиц символов Таблицы идентификаторов Таблицы расстановки Таблицы расстановки со списками Функции расстановки Таблицы на деревьях Реализация блочной структуры Сравнение методов реализации таблиц Промежуточное представление программы Представление в виде ориентированного графа Трехадресный код Линеаризованные представления Виртуальная машина Java Организация памяти

5 ОГЛАВЛЕНИЕ Набор команд виртуальной машины Организация информации в генераторе кода Уровень промежуточного представления Генерация кода Модельмашины Динамическая организация памяти Организация магазина со статической цепочкой Организация магазина с дисплеем Назначение адресов Трансляция переменных Трансляция целых выражений Трансляция арифметических выражений Трансляция логических выражений Выделение общих подвыражений Генерация оптимального кода методами синтаксического анализа Сопоставление образцов Синтаксический анализ для T-грамматик Выбор дерева вывода наименьшей стоимости Атрибутная схема для алгоритма сопоставления образцов Системы автоматизации построения трансляторов СистемаСУПЕР СистемаYacc

7 Глава 1 Введение 1.1 Место компилятора в программном обеспечении Компиляторы составляют существенную часть программного обеспечения ЭВМ. Это связано с тем, что языки высокого уровня стали основным средством разработки программ. Только очень незначительная часть программного обеспечения, требующая особой эффективности, программируется с помощью ассемблеров. В настоящее время распространено довольно много языков программирования. Наряду с традиционными языками, такими, как Фортран, широкое распространение получили так называемые универсальные языки (Паскаль, Си, Модула-2, Ада и другие), а также некоторые специализированные (например, язык обработки списочных структур Лисп). Кроме того, большое распространение получили языки, связанные с узкими предметными областями, такие, как входные языки пакетов прикладных программ. Для некоторых языков имеется довольно много реализаций. Например, реализаций Паскаля, Модулы-2 или Си для ЭВМ типа IBM PC на рынке десятки. С другой стороны, постоянно растущая потребность в новых компиляторах связана с бурным развитием архитектур ЭВМ. Это развитие идет по различным направлениям. Совершенствуются старые архитектуры как в концептуальном отношении, так и по отдельным, конкретным линиям. Это можно проиллюстрировать на примере микропроцессора Intel- 80X86. Последовательные версии этого микропроцессора 8086, 80186, 80286, 80386, 80486, отличаются не только техническими характеристиками, но и, что более важно, новыми возможностями и, значит, изменением (расширением) системы команд. Естественно, это требует новых компиляторов (или модификации старых). То же можно сказать о микропроцессорах Motorola 68010, 68020, 68030, В рамках традиционных последовательных машин возникает боль- 7

8 8 ГЛАВА 1. ВВЕДЕНИЕ шое число различных направлений архитектур. Примерами могут служить архитектуры CISC, RISC. Такие ведущие фирмы, как Intel, Motorola, Sun, начинают переходить на выпуск машин с RISC-архитектурами. Естественно, для каждой новой системы команд требуется полный набор новых компиляторов с распространенных языков. Наконец, бурно развиваются различные параллельные архитектуры. Среди них отметим векторные, многопроцессорные, с широким командным словом (вариантом которых являются суперскалярные ЭВМ). На рынке уже имеются десятки типов ЭВМ с параллельной архитектурой, начиная от супер-эвм (Cray, CDC и другие), через рабочие станции (например, IBM RS/6000) и кончая персональными (например, на основе микропроцессора I-860). Естественно, для каждой из машин создаются новые компиляторы для многих языков программирования. Здесь необходимо также отметить, что новые архитектуры требуют разработки совершенно новых подходов к созданию компиляторов, так что наряду с собственно разработкой компиляторов ведется и большая научная работа по созданию новых методов трансляции. 1.2 Структура компилятора Обобщенная структура компилятора и основные фазы компиляции показаны на рис На фазе лексического анализа входная программа, представляющая собой поток литер, разбивается на лексемы слова в соответствии с определениями языка. Основными формализмами, лежащим в основе реализации лексических анализаторов, являются конечные автоматы и регулярные выражения. Лексический анализатор может работать в двух основных режимах: либо как подпрограмма, вызываемая синтаксическим анализатором для получения очередной лексемы, либо как полный проход, результатом которого является файл лексем. В процессе выделения лексем лексический анализатор может как самостоятельно строить таблицы объектов (идентификаторов, строк, чисел и т.д.), так и выдавать значения для каждой лексемы при очередном к нему обращении. В этом случае таблицы объектов строятся в последующих фазах (например, в процессе синтаксического анализа). На этапе лексического анализа обнаруживаются некоторые (простейшие) ошибки (недопустимые символы, неправильная запись чисел, идентификаторов и др.). Основная задача синтаксического анализа разбор структуры программы. Как правило, под структурой понимается дерево, соответствующее разбору в контекстно-свободной грамматике языка. В настоящее время чаще всего используется либо LL(1)-анализ (и его вариант рекурсивный спуск), либо LR(1)-анализ и его варианты (LR(0), SLR(1), LALR(1) и другие). Рекурсивный спуск чаще используется при ручном программировании синтаксического анализатора, LR(1) при исполь-

Илон Маск рекомендует:  Что такое код getcurdir

9 1.2. СТРУКТУРА КОМПИЛЯТОРА 9 E_dkbq_kdbc ZgZeba Dhg_qgu_ Z\lhfZlu >bz]ghklbdz Ihlhde_dk_f lz[ebpuh[t_dlh\ KbglZdkbq_kdbc ZgZeba DK]jZffZlbdb >bz]ghklbdz >_j_\hjza[hjz lz[ebpuh[t_dlh\ Dhgl_dklguc ZgZeba :ljb[mlgu_ ]jzffzlbdb >bz]ghklbdz :ljb[mlbjh\zggh_^_j_\h lz[ebpuh[t_dlh\ =_g_jzpby ijhf_`mlhqgh]h ij_^klz\e_gby KMljZgkeypby Ijhf_`mlhqgZynhjfZ ij_nbdkgzyihkl nbdkgzyljhcdbb ^j HilbfbaZpby Ihlhdh\uc ZgZeba Ijhf_`mlhqgZynhjfZ hjb_glbjh\zgguc]jzn =_g_jzpbydh^z LZ[ebpuj_r_gbc ^bgzfbq_kdh_ ijh]jzffbjh\zgb_ H[t_dlgucfh^mev Рис. 1.1:

10 10 ГЛАВА 1. ВВЕДЕНИЕ зовании систем автоматического построения синтаксических анализаторов. Результатом синтаксического анализа является синтаксическое дерево со ссылками на таблицы объектов. В процессе синтаксического анализа также обнаруживаются ошибки, связанные со структурой программы. На этапе контекстного анализа выявляются зависимости между частями программы, которые не могут быть описаны контекстно-свободным синтаксисом. Это в основном связи описание-использование, в частности, анализ типов объектов, анализ областей видимости, соответствие параметров, метки и другие. В процессе контекстного анализа таблицы объектов пополняются информацией об описаниях (свойствах) объектов. Основным формализмом, использующимся при контекстном анализе, является аппарат атрибутных грамматик. Результатом контекстного анализа является атрибутированное дерево программы. Информация об объектах может быть как рассредоточена в самом дереве, так и сосредоточена в отдельных таблицах объектов. В процессе контекстного анализа также могут быть обнаружены ошибки, связанные с неправильным использованием объектов. Затем программа может быть переведена во внутреннее представление. Это делается для целей оптимизации и/или удобства генерации кода. Еще одной целью преобразования программы во внутреннее представление является желание иметь переносимый компилятор. Тогда только последняя фаза (генерация кода) является машинно-зависимой. В качестве внутреннего представления может использоваться префиксная или постфиксная запись, ориентированный граф, тройки, четверки и другие. Фаз оптимизации может быть несколько. Оптимизации обычно делят на машинно-зависимые и машинно-независимые, локальные и глобальные. Часть машинно-зависимой оптимизации выполняется на фазе генерации кода. Глобальная оптимизация пытается принять во внимание структуру всей программы, локальная только небольших ее фрагментов. Глобальная оптимизация основывается на глобальном потоковом анализе, который выполняется на графе программы и представляет по существу преобразование этого графа. При этом могут учитываться такие свойства программы, как межпроцедурный анализ, межмодульный анализ, анализ областей жизни переменных и т.д. Наконец, генерация кода последняя фаза трансляции. Результатом ее является либо ассемблерный модуль, либо объектный (или загрузочный) модуль. В процессе генерации кода могут выполняться некоторые локальные оптимизации, такие как распределение регистров, выбор длинных или коротких переходов, учет стоимости команд при выборе конкретной последовательности команд. Для генерации кода разработаны различные методы, такие как таблицы решений, сопоставление образцов, включающее динамическое программирование, различ-

11 1.2. СТРУКТУРА КОМПИЛЯТОРА 11 ные синтаксические методы. Конечно, те или иные фазы транслятора могут либо отсутствовать совсем, либо объединяться. В простейшем случае однопроходного транслятора нет явной фазы генерации промежуточного представления и оптимизации, остальные фазы объединены в одну, причем нет и явно построенного синтаксического дерева.

12 12 ГЛАВА 1. ВВЕДЕНИЕ

13 Глава 2 Языки и их представление 2.1 Алфавиты, цепочки и языки Алфавит, или словарь это конечное множество символов. Для обозначения символов мы будем пользоваться цифрами, латинскими буквами и специальными литерами типа #, $. Пусть V алфавит. Цепочка в алфавите V это любая строка конечной длины, составленная из символов алфавита V. Синонимом цепочки являются предложение, строка и слово. Пустая цепочка (обозначается e) это цепочка, в которую не входит ни один символ. Конкатенацией цепочек x и y называется цепочка xy. Заметим, что xe = ex = x для любой цепочки x. Пусть x, y, z произвольные цепочки в некотором алфавите. Цепочка y называется подцепочкой цепочки xyz. Цепочки x и y называются, соответственно, префиксом и суффиксом цепочки xy. Заметим, что любой префикс или суффикс цепочки является подцепочкой этой цепочки. Кроме того, пустая цепочка является префиксом, суффиксом и подцепочкой для любой цепочки. Пример 2.1. Для цепочки abbba префиксом является любая цепочка из множества L 1 = , суффиксом является любая цепочка из множества L 2 = , подцепочкой является любая цепочка из множества L 1 L 2. Длиной цепочки w (обозначается w ) называется число символов в ней. Например, abababa =7, а e =0. Язык в алфавите V это некоторое множество цепочек в алфавите V. Пример 2.2. Пусть дан алфавит V = . Вот некоторые языки в алфавите V : а) L 1 = пустой язык; 13

14 14 ГЛАВА 2. ЯЗЫКИ И ИХ ПРЕДСТАВЛЕНИЕ б) L 2 = язык, содержащий только пустую цепочку (заметим, что L 1 и L 2 различные языки); в) L 3 = язык, содержащий цепочки из a и b, длина которых не превосходит 2; г) L 4 язык, включающий всевозможные цепочки из a и b, содержащие четное число a и четное число b; д) L 5 = 0> язык цепочек из a, длины которых представляют собой квадраты натуральных чисел. Два последних языка содержат бесконечное число цепочек. Введем обозначение V для множества всех цепочек в алфавите V, включая пустую цепочку. Каждый язык в алфавите V является подмножеством V. Для обозначения множества всех цепочек в алфавите V, кроме пустой цепочки, будем использовать V +. Пример 2.3. Пусть V = <0, 1>. Тогда V = , V + = <0, 1, 00, 01, 10, 11, 000. >. Введем некоторые операции над языками. Пусть L 1 и L 2 языки в алфавите V. Конкатенацией языков L 1 и L 2 называется язык L 1 L 2 = . Пусть L язык в алфавите V. Итерацией языка L называется язык L, определяемый следующим образом: (1) L 0 = ; (2) L n = LL n 1, n 1; (3) L = n=0 L n. Пример 2.4. Пусть L 1 = и L 2 = . Тогда L 1L 2 = ,и L 1 = . Большинство языков, представляющих интерес, содержат бесконечное число цепочек. При этом возникают три важных вопроса. Во-первых, как представить язык (т.е. специфицировать входящие в него цепочки)? Если язык содержит только конечное множество цепочек, ответ прост. Можно просто перечислить его цепочки. Если язык бесконечен, необходимо найти для него конечное представление. Это конечное представление, в свою очередь, будет строкой символов над некоторым алфавитом вместе с некоторой интерпретацией, связывающей это представление с языком.

15 2.2. ПРЕДСТАВЛЕНИЕ ЯЗЫКОВ 15 Во-вторых, для любого ли языка существует конечное представление? Можно предположить, что ответ отрицателен. Мы увидим, что множество всех цепочек над алфавитом счетно. Язык это любое подмножество цепочек. Из теории множеств известно, что множество всех подмножеств счетного множества несчетно. Хотя мы и не дали строгого определения того, что является конечным представлением, интуитивно ясно, что любое разумное определение конечного представления ведет только к счетному множеству конечных представлений, поскольку нужно иметь возможность записать такое конечное представление в виде строки символов конечной длины. Поэтому языков значительно больше, чем конечных представлений. В-третьих, можно спросить, какова структура тех классов языков, для которых существует конечное представление? 2.2 Представление языков Процедура это конечная последовательность инструкций, которые могут быть механически выполнены. Примером может служить машинная программа. Процедура, которая всегда заканчивается, называется алгоритмом. Один из способов представления языка дать алгоритм, определяющий, принадлежит ли цепочка языку. Более общий способ состоит в том, чтобы дать процедуру, которая останавливается с ответом да для цепочек, принадлежащих языку, и либо останавливается с ответом нет, либо вообще не останавливается для цепочек, не принадлежащих языку. Говорят, что такая процедура или алгоритм распознает язык. Такой метод представляет язык с точки зрения распознавания. Язык можно также представить методом порождения. А именно, можно дать процедуру, которая систематически порождает в определенном порядке цепочки языка. Если мы можем распознать цепочки языка над алфавитом V либо с помощью процедуры, либо с помощью алгоритма, то мы можем и генерировать язык, поскольку мы можем систематически генерировать все цепочки из V, проверять каждую цепочку на принадлежность языку и выдавать список только цепочек языка. Но если процедура не всегда заканчивается при проверке цепочки, мы не сдвинемся дальше первой цепочки, на которой процедура не заканчивается. Эту проблему можно обойти, организовав проверку таким образом, чтобы процедура никогда не продолжала проверять одну цепочку бесконечно. Для этого введем следующую конструкцию. Предположим, что V имеет p символов. Мы можем рассматривать цепочки из V как числа, представленные в базисе p, плюс пустая цепочка e. Можно занумеровать цепочки в порядке возрастания длины и в числовом порядке для цепочек одинаковой длины. Такая нумерация для цепочек языка приведена на рис. 2.1, а.

16 16 ГЛАВА 2. ЯЗЫКИ И ИХ ПРЕДСТАВЛЕНИЕ Пусть P процедура для проверки принадлежности цепочки языку L. Предположим, что P может быть представлена дискретными шагами, так что имеет смысл говорить об i-ом шаге процедуры для любой данной цепочки. Прежде чем дать процедуру перечисления цепочек языка L, дадим процедуру нумерации пар положительных чисел. Все упорядоченные пары положительных чисел (x, y) можно отобразить на множество положительных чисел следующей формулой: z =(x + y 1)(x + y 2)/2+y Пары целых положительных чисел можно упорядочить в соответствии со значением z (рис. 2.1, б). 1 e 2 a 3 b 4 c 5 aa 6 ab 7 ac 8 ba 9 bb а y x z(x, y) б Рис. 2.1: Теперь можно дать процедуру перечисления цепочек L. Нумеруем упорядоченные пары целых положительных чисел (1,1), (2,1), (1,2), (3,1), (2,2). При нумерации пары (i, j) генерируем i-ю цепочку из V и применяем к цепочке первые j шагов процедуры P. Как только мы определили, что сгенерированная цепочка принадлежит L, добавляем цепочку к списку элементов L. Если цепочка i принадлежит L, это будет определено P за j шагов для некоторого конечного j. При перечислении (i, j) будет сгенерирована цепочку с номером i. Легко видеть, что эта процедура перечисляет все цепочки L. Если мы имеем процедуру генерации цепочек языка, то мы всегда можем построить процедуру распознавания предложений языка, но не всегда алгоритм. Для определения того, принадлежит ли x языку L, просто нумеруем предложения L и сравниваем x с каждым предложением. Если сгенерировано x, процедура останавливается, распознав, что x принадлежит L. Конечно, если x не принадлежит L, процедура никогда не закончится. Язык, предложения которого могут быть сгенерированы процедурой, называется рекурсивно перечислимым. Язык рекурсивно перечислим, если имеется процедура, распознающая предложения языка. Говорят,

17 2.3. ГРАММАТИКИ 17 что язык рекурсивен, если существует алгоритм для распознавания языка. Класс рекурсивных языков является собственным подмножеством класса рекурсивно перечислимых языков. Мало того, существуют языки, не являющиеся даже рекурсивно перечислимыми. 2.3 Грамматики Формальное определение грамматики Для нас наибольший интерес представляет одна из систем генерации языков грамматики. Понятие грамматики изначально было формализовано лингвистами при изучении естественных языков. Предполагалось, что это может помочь при их автоматической трансляции. Однако, наилучшие результаты в этом направлении достигнуты при описании не естественных языков, а языков программирования. Примером может служить способ описания синтаксиса языков программирования при помощи БНФ формы Бэкуса-Наура. Определение. Грамматика это четверка G =(N,T,P,S), где (1) N алфавит нетерминальных символов; (2) T алфавит терминальных символов, N T = ; (3) P конечное множество правил вида α β, где α (N T ) +, β (N T ) ; (4) S N начальный символ (или аксиома) грамматики. Мы будем использовать большие латинские буквы для обозначения нетерминальных символов, малые латинские буквы из начала алфавита для обозначения терминальных символов, малые латинские буквы из конца алфавита для обозначения цепочек из T и, наконец, малые греческие буквы для обозначения цепочек из (N T ). Будем использовать также сокращенную запись A α 1 α 2. α n для обозначения группы правил A α 1,A α 2. A α n. Определим на множестве (N T ) бинарное отношение выводимости следующим образом: если δ γ P,тоαδβ αγβ для всех α, β (N T ). Если α 1 α 2, то говорят, что цепочка α 2 непосредственно выводима из α 1. Мы будем использовать также рефлексивно-транзитивное и транзитивное замыкания отношения, а также его степень k 0 (обозначаемые соответственно, + и k ). Если α 1 α 2 (α 1 + α 2, α 1 k α 2 ), то говорят, что цепочка α 2 выводима (нетривиально выводима, выводима за k шагов)изα 1. Если α k β (k 0), то существует последовательность шагов γ 0 γ 1 γ 2. γ k 1 γ k

18 18 ГЛАВА 2. ЯЗЫКИ И ИХ ПРЕДСТАВЛЕНИЕ где α = γ 0 и β = γ k. Последовательность цепочек γ 0,γ 1,γ 2. γ k в этом случае называют выводом β из α. Сентенциальной формой грамматики G называется цепочка, выводимая из ее начального символа. Языком, порождаемым грамматикой G (обозначается L(G)), называется множество всех ее терминальных сентенциальных форм, т.е. L(G) = Грамматики G 1 и G 2 называются эквивалентными, если они порождают один и тот же язык, т.е. L(G 1 )=L(G 2 ). Пример 2.5. Грамматика G =(, , P, S), где P = , порождает язык L(G) =0>. Действительно, применяем n 1 раз правило 1 и получаем a n 1 S(BC) n 1, затем один раз правило 2 и получаем a n (BC) n, затем n(n 1)/2 раз правило 3 и получаем a n B n C n. Затем используем правило 4 и получаем a n bb n 1 C n. Затем применяем n 1 раз правило 5 и получаем a n b n C n. Затем применяем правило 6 и n 1 раз правило 7 и получаем a n b n c n. Можно показать, что язык L(G) состоит из цепочек только такого вида. Пример 2.6. Рассмотрим грамматику G =(, <0, 1>, , S). Легко видеть, что цепочка L(G), так как существует вывод S 0S1 00S Нетрудно показать, что грамматика порождает язык L(G) =<0 n 1>0>. Пример 2.7. Рассмотрим грамматику G = (, <0, 1>, ,S). Нетрудно показать, что грамматика порождает язык L(G) = <0 n 1 m n,>0> Типы грамматик и их свойства Рассмотрим классификацию грамматик (предложенную Н.Хомским), основанную на виде их правил. Определение. Пусть дана грамматика G =(N,T,P,S). Тогда (1) если правила грамматики не удовлетворяют никаким ограничениям, то ее называют грамматикой типа 0, или грамматикой без ограничений. (2) если а) каждое правило грамматики, кроме S e, имеет вид α β, где α β,и

19 2.3. ГРАММАТИКИ 19 б) в том случае, когда S e P, символ S не встречается в правых частях правил, то грамматику называют грамматикой типа 1, или неукорачивающей. (3) если каждое правило грамматики имеет вид A β, где A N, β (N T ), то ее называют грамматикой типа 2, или контекстносвободной (КС-грамматикой). (4) если каждое правило грамматики имеет вид либо A xb, либо A x, где A, B N, x T то ее называют грамматикой типа 3, или праволинейной. Легко видеть, что грамматика в примере 2.5 неукорачивающая, в примере 2.6 контекстно-свободная, в примере 2.7 праволинейная. Язык, порождаемый грамматикой типа i, называют языком типа i. Язык типа 0 называют также языком без ограничений, язык типа 1 контекстно-зависимым (КЗ), язык типа 2 контекстно-свободным (КС), язык типа 3 праволинейным. Теорема 2.1. Каждый контекстно-свободный язык может быть порожден неукорачивающей грамматикой. Доказательство. Пусть L контекстно-свободный язык. Тогда существует контекстно-свободная грамматика G = (N,T,P,S), порождающая L. Построим новую грамматику G =(N,T,P,S ) следующим образом: 1. Если в P есть правило вида A α 0 B 1 α 1. B k α k, где k 0, B i + e для 1 i k, и ни из одной цепочки α j (0 j k) не выводится e, то включить в P все правила (кроме A e) вида A α 0 X 1 α 1. X k α k где X i это либо B i, либо e. 2. Если S + e, то включить в P правила S S, S e и положить N = N . В противном случае положить N = N и S = S. Легко видеть, что G неукорачивающая грамматика. Можно показать по индукции, что L(G )=L(G). Пусть K i класс всех языков типа i. Доказано, что справедливо следующее (строгое) включение: K 3 K 2 K 1 K 0. Заметим, что если язык порождается некоторой грамматикой, это не означает, что он не может быть порожден грамматикой с более сильными ограничениями на правила. Приводимый ниже пример иллюстрирует этот факт.

20 20 ГЛАВА 2. ЯЗЫКИ И ИХ ПРЕДСТАВЛЕНИЕ Пример 2.8. Рассмотрим грамматику G = (, <0, 1>, , S). Эта грамматика является контекстносвободной. Легко показать, что L(G) = <0 n 1 m n,>0>. Однако, в примере 2.7 приведена праволинейная грамматика, порождающая тот же язык. Покажем что существует алгоритм, позволяющий для произвольного КЗ-языка L в алфавите T, и произвольной цепочки w T определить, принадлежит ли w языку L. Теорема 2.2. Каждый контекстно-зависимый язык является рекурсивным языком. Доказательство. Пусть L контекстно-зависимый язык. Тогда существует некоторая неукорачивающая грамматика G =(N, T, P, S), порождающая L. Пусть w T и w = n. Если n =0, т.е. w = e, то принадлежность w L проверяется тривиальным образом. Так что будем предполагать, что n>0. Определим множество T m как множество строк u (N T ) + длины не более n таких, что вывод S u имеет не более m шагов. Ясно, что T 0 = . Легко показать, что T m можно получить из T m 1 просматривая, какие строки с длиной, меньшей или равной n можно вывести из строк из T m 1 применением одного правила, т.е. T m = T m 1 . Если S u и u n, тоu T m для некоторого m. Если из S не выводится u или u >n,тоuне принадлежит T m ни для какого m. Очевидно, что T m T m 1 для всех m 1. Поскольку T m зависит только от T m 1, если T m = T m 1,тоT m = T m+1 = T m+2 =. Процедура будет вычислять T 1, T 2, T 3. пока для некоторого m не окажется T m = T m 1. Если w не принадлежит T m, то не принадлежит и L(G), поскольку для j>mвыполнено T j = T m. Если w T m,тоs w. Покажем, что существует такое m, что T m = T m 1. Поскольку для каждого i 1 справедливо T i T i 1, то если T i T i 1, то число элементов в T i по крайней мере на 1 больше, чем в T i 1. Пусть N T = k. Тогда число строк в (N T ) + длины меньшей или равной n равно k + k k n nk n. Только эти строки могут быть в любом T i. Значит, T m = T m 1 для некоторого m nk n. Таким образом, процедура, вычисляющая T i для всех i 1 до тех пор, пока не будут найдены два равных множества, гарантированно заканчивается, значит, это алгоритм.

21 Глава 3 Лексический анализ Основная задача лексического анализа разбить входной текст, состоящий из последовательности одиночных символов, на последовательность слов, или лексем, т.е. выделить эти слова из непрерывной последовательности символов. Все символы входной последовательности с этой точки зрения разделяются на символы, принадлежащие каким-либо лексемам, и символы, разделяющие лексемы (разделители). В некоторых случаях между лексемами может и не быть разделителей. С другой стороны, в некоторых языках лексемы могут содержать незначащие символы (например, символ пробела в Фортране). В Си разделительное значение символов-разделителей может блокироваться ( \ в конце строки внутри «. «). Обычно все лексемы делятся на классы. Примерами таких классов являются числа (целые, восьмеричные, шестнадцатиричные, действительные и т.д.), идентификаторы, строки. Отдельно выделяются ключевые слова и символы пунктуации (иногда их называют символы-ограничители). Как правило, ключевые слова это некоторое конечное подмножество идентификаторов. В некоторых языках (например, ПЛ/1) смысл лексемы может зависеть от ее контекста и невозможно провести лексический анализ в отрыве от синтаксического. С точки зрения дальнейших фаз анализа лексический анализатор выдает информацию двух сортов: для синтаксического анализатора, работающего вслед за лексическим, существенна информация о последовательности классов лексем, ограничителей и ключевых слов, а для контекстного анализа, работающего вслед за синтаксическим, важна информация о конкретных значениях отдельных лексем (идентификаторов, чисел и т.д.). Таким образом, общая схема работы лексического анализатора такова. Сначала выделяется отдельная лексема (возможно, используя символыразделители). Ключевые слова распознаются либо явным выделением непосредственно из текста, либо сначала выделяется идентификатор, а затем делается проверка на принадлежность его множеству ключевых 21

22 22 ГЛАВА 3. ЛЕКСИЧЕСКИЙ АНАЛИЗ слов. Если выделенная лексема является ограничителем, то он (точнее, некоторый его признак) выдается как результат лексического анализа. Если выделенная лексема является ключевым словом, то выдается признак соответствующего ключевого слова. Если выделенная лексема является идентификатором выдается признак идентификатора, а сам идентификатор сохраняется отдельно. Наконец, если выделенная лексема принадлежит какому-либо из других классов лексем (например, лексема представляет собой число, строку и т.д.), то выдается признак соответствующего класса, а значение лексемы сохраняется отдельно. Лексический анализатор может быть как самостоятельной фазой трансляции, так и подпрограммой, работающей по принципу дай лексему. В первом случае (рис. 3.1, а) выходом анализатора является файл лексем, во втором (рис. 3.1, б) лексема выдается при каждом обращении к анализатору (при этом, как правило, признак класса лексемы возвращается как результат функции лексический анализатор, а значение лексемы передается через глобальную переменную). С точки зрения обработки значений лексем, анализатор может либо просто выдавать значение каждой лексемы, и в этом случае построение таблиц объектов (идентификаторов, строк, чисел и т.д.) переносится на более поздние фазы, либо он может самостоятельно строить таблицы объектов. В этом случае в качестве значения лексемы выдается указатель на вход в соответствующую таблицу. LbiAgZq_gb_ KbglZgZebaZlhj Lbi e_dk_fu AgZq_gb_ LZ[ebpZ E_dkZgZebaZlhj Z [ Рис. 3.1: Работа лексического анализатора задается некоторым конечным автоматом. Однако, непосредственное описание конечного автомата неудобно с практической точки зрения. Поэтому для задания лексического анализатора, как правило, используется либо регулярное выражение, либо праволинейная грамматика. Все три формализма (конечных автоматов,

24 24 ГЛАВА 3. ЛЕКСИЧЕСКИЙ АНАЛИЗ (б) (pq) регулярное выражение, обозначающее регулярное множество PQ, (в) (p ) регулярное выражение, обозначающее регулярное множество P ; (5) ничто другое не является регулярным выражением в алфавите T. Мы будем опускать лишние скобки в регулярных выражениях, договорившись о том, что операция итерации имеет наивысший приоритет, затем идет операции конкатенации, наконец, операция объединения имеет наименьший приоритет. Кроме того, мы будем пользоваться записью p + для обозначения pp. Таким образом, запись (a ((ba)(a ))) эквивалентна a ba +. Наконец, мы будем использовать запись L(r) для регулярного множества, обозначаемого регулярным выражением r. Пример 3.1. Несколько примеров регулярных выражений и обозначаемых ими регулярных множеств: а) a(e a) b обозначает множество ; б) a(a b) обозначает множество всевозможных цепочек, состоящих из a и b, начинающихся с a; в) (a b) (a b)(a b) обозначает множество всех непустых цепочек, состоящих из a и b, т.е. множество + ; г) ((0 1)(0 1)(0 1)) обозначает множество всех цепочек, состоящих из нулей и единиц, длины которых делятся на 3. Ясно, что для каждого регулярного множества можно найти регулярное выражение, обозначающее это множество, и наоборот. Более того, для каждого регулярного множества существует бесконечно много обозначающих его регулярных выражений. Будем говорить, что регулярные выражения равны или эквивалентны (=), если они обозначают одно и то же регулярное множество. Существует ряд алгебраических законов, позволяющих осуществлять эквивалентное преобразование регулярных выражений. Лемма. Пусть p, q и r регулярные выражения. Тогда справедливы следующие соотношения: (1) p q = q p; (7) pe = ep = p; (2) = e; (8) p = p = ; (3) p (q r) =(p q) r; (9) p = p p ; (4) p(qr) =(pq)r; (10) (p ) = p ; (5) p(q r) = pq pr; (11) p p = p; (6) (p q)r = pr qr; (12) p = p. Следствие. Для любого регулярного выражения существует эквивалентное регулярное выражение, которое либо есть, либо не содержит в своей записи.

25 3.2. КОНЕЧНЫЕ АВТОМАТЫ 25 В дальнейшем будем рассматривать только регулярные выражения, не содержащие в своей записи. При практическом описании лексических структур бывает полезно сопоставлять регулярным выражениям некоторые имена, и ссылаться на них по этим именам. Для определения таких имен мы будем использовать запись вида d 1 = r 1 d 2 = r 2. d n = r n где d i различные имена, а каждое r i регулярное выражение над символами T , т.е. символами основного алфавита и ранее определенными символами (именами). Таким образом, для любого r i можно построить регулярное выражение над T, повторно заменяя имена регулярных выражений на обозначаемые ими регулярные выражения. Пример 3.2. Использование имен для регулярных выражений. а) Регулярное выражение для множества идентификаторов. Letter = a b c. x y z Digit = >

26 26 ГЛАВА 3. ЛЕКСИЧЕСКИЙ АНАЛИЗ (5) F Q множество заключительных состояний. Работа конечного автомата представляет собой некоторую последовательность шагов, или тактов. Такт определяется текущим состоянием управляющего устройства и входным символом, обозреваемым в данный момент входной головкой. Сам шаг состоит из изменения состояния и, возможно, сдвига входной головки на одну ячейку вправо (рис. 3.2). Khklhygb_ IjhqblZggZyqZklv \oh^ghcp_ihqdb D L_dmsbc \oh^ghc kbf\he G_ijhqblZggZyqZklv \oh^ghcp_ihqdb Рис. 3.2: Недетерминизм автомата заключается в том, что, во-первых, находясь в некотором состоянии и обозревая текущий символ, автомат может перейти в одно из, вообще говоря, нескольких возможных состояний, и во-вторых, автомат может делать переходы по e. Пусть M = (Q,T,D,q 0,F) НКА. Конфигурацией автомата M называется пара (q, w) Q T, где q текущее состояние управляющего устройства, а w цепочка символов на входной ленте, состоящая из символа под головкой и всех символов справа от него. Конфигурация (q 0,w) называется начальной, а конфигурация (q, e), где q F заключительной (или допускающей). Пусть M =(Q,T,D,q 0,F) НКА. Тактом автомата M называется бинарное отношение, определенное на конфигурациях M следующим образом: если p D(q, a), где a T , то(q, aw) (p, w) для всех w T. Будем обозначать символом + ( ) транзитивное (рефлексивнотранзитивное) замыкание отношения. Говорят, что автомат M допускает цепочку w, если (q 0,w) (q, e) для некоторого q F. Языком, допускаемым (распознаваемым, определяемым) автоматом M, (обозначается L(M)), называется множество входных цепочек, допускаемых автоматом M. Т.е. L(M) =.

27 3.2. КОНЕЧНЫЕ АВТОМАТЫ 27 Важным частным случаем недетерминированного конечного автомата является детерминированный конечный автомат, который на каждом такте работы имеет возможность перейти не более чем в одно состояние и не может делать переходы по e. Пусть M =(Q,T,D,q 0,F) НКА. Будем называть M детерминированным конечным автоматом (ДКА), если выполнены следующие два условия: (1) D(q, e) = для любого q Q,и (2) D(q, a) содержит не более одного элемента для любых q Q и a T. Так как функция переходов ДКА содержит не более одного элемента для любой пары аргументов, для ДКА мы будем пользоваться записью D(q, a) =p вместо D(q, a) =

. Конечный автомат может быть изображен графически в виде диаграммы, представляющей собой ориентированный граф, в котором каждому состоянию соответствует вершина, а дуга, помеченная символом a T , соединяет две вершины p и q, если p D(q, a). На диаграмме выделяются начальное и заключительные состояния (в примерах ниже, соответственно, входящей стрелкой и двойным контуром). Пример 3.3. Пусть L = L(r), где r =(a b) a(a b)(a b). а) Недетерминированный конечный автомат M, допускающий язык L: M = <<1, 2, 3, 4>, ,d,1, <4>>, где функция переходов D определяется так: D(1,a)=<1, 2>, D(3,a)=<4>, D(2,a)=<3>, D(3,b)=<4>, D(2,b)=<3>. Диаграмма автомата приведена на рис. 3.3, а. б) Детерминированный конечный автомат M, допускающий язык L: M = <<1, 2, 3, 4, 5, 6, 7, 8>, ,d,1, <3, 5, 6, 8>>, где функция переходов D определяется так: D(1,a)=2, D(5,a)=8, D(1,b)=1, D(5,b)=6, D(2,a)=4, D(6,a)=2, D(2,b)=7, D(6,b)=1, D(3,a)=3, D(7,a)=8, D(3,b)=5, D(7,b)=6, D(4,a)=3, D(8,a)=4, D(4,b)=5, D(8,b)=7. Диаграмма автомата приведена на рис. 3.3, б. Пример 3.4. Диаграмма ДКА, допускающего множество чисел в десятичной записи, приведена на рис. 3.4.

28 28 ГЛАВА 3. ЛЕКСИЧЕСКИЙ АНАЛИЗ E D D DE E DE D E E D D D D E E E D E D D E Z [ Рис. 3.3: Пример 3.5. Анализ цепочек. а) При анализе цепочки w = ababa автомат из примера 3.3, а, может сделать следующую последовательность тактов: (1, ababa) (1, baba) (1, aba) (2,ba) (3,a) (4,e). Состояние 4 является заключительным, следовательно, цепочка w допускается этим автоматом. б) При анализе цепочки w = ababab автомат из примера 3.3, б, должен сделать следующую последовательность тактов: (1, ababab) (2, babab) (7, abab) (8, bab) (7,ab) (8,b) (7,e). Так как состояние 7 не является заключительным, цепочка w не допускается этим автоматом. ( ‘LJLW ‘LJLW ‘LJLW ( ‘LJLW ‘LJLW ‘LJLW ‘LJLW Рис. 3.4:

29 3.3. АЛГОРИТМЫ ПОСТРОЕНИЯ КОНЕЧНЫХ АВТОМАТОВ Алгоритмы построения конечных автоматов Построение недетерминированного конечного автомата по регулярному выражению Рассмотрим алгоритм построения по регулярному выражению недетерминированного конечного автомата, допускающего тот же язык. Алгоритм 3.1. Построение недетерминированного конечного автомата по регулярному выражению. Вход. Регулярное выражение r в алфавите T. Выход. НКА M, такой что L(M) =L(r). Метод. Автомат для выражения строится композицией из автоматов, соответствующих подвыражениям. На каждом шаге построения строящийся автомат имеет в точности одно заключительное состояние, в начальное состояние нет переходов из других состояний и нет переходов из заключительного состояния в другие. 1. Для выражения e строится автомат L H I Рис. 3.5: 2. Для выражения a (a T ) строится автомат L D I Рис. 3.6: 3. Пусть M(s) и M(t) НКА для регулярных выражений s и t соответственно. а) Для выражения s t автомат M(s t) строится как показано на рис Здесь i новое начальное состояние и f новое заключительное состояние. Заметим, что имеет место переход по e из i в начальные состояния M(s) и M(t) и переход по e из заключительных состояний M(s) и M(t) в f. Начальное и заключительное состояния автоматов M(s) и M(t) не являются таковыми для автомата M(s t).

30 30 ГЛАВА 3. ЛЕКСИЧЕСКИЙ АНАЛИЗ H 0V H L I H 0W H Рис. 3.7: б) Для выражения st автомат M(st) строится следующим образом: L 0V 0W I Рис. 3.8: Начальное состояние M(s) становится начальным для нового автомата, а заключительное состояние M(t) становится заключительным для нового автомата. Начальное состояние M(t) и заключительное состояние M(s) сливаются, т.е. все переходы из начального состояния M(t) становятся переходами из заключительного состояния M(s). В новом автомате это объединенное состояние не является ни начальным, ни заключительным. в) Для выражения s автомат M(s ) строится следующим образом: L H H 0V H I H Рис. 3.9:

31 3.3. АЛГОРИТМЫ ПОСТРОЕНИЯ КОНЕЧНЫХ АВТОМАТОВ 31 Здесь i новое начальное состояние, а f новое заключительное состояние Построение детерминированного конечного автомата по недетерминированному Рассмотрим алгоритм построения по недетерминированному конечному автомату детерминированного конечного автомата, допускающего тот же язык. Алгоритм 3.2. Построение детерминированного конечного автомата по недетерминированному. Вход. НКА M =(Q,T,D,q 0,F). Выход. ДКА M =(Q,T,D,q 0,F ), такой что L(M) =L(M ). Метод. Каждое состояние результирующего ДКА это некоторое множество состояний исходного НКА. В алгоритме будут использоваться следующие функции: e-closure(r) (R Q) множество состояний НКА, достижимых из состояний, входящих в R, посредством только переходов по e, т.е. множество S =

q R move(r, a) (R Q) множество состояний НКА, в которые есть переход на входе a для состояний из R, т.е. множество S =

q R Вначале Q и D пусты. Выполнить шаги 1-4: (1) Определить q 0 = e-closure(). (2) Добавить q 0 в Q как непомеченное состояние. (3) Выполнить следующую процедуру: while (в Q есть непомеченное состояние R)< пометить R; for (каждого входного символа a T )< S = e-closure(move(r, a)); if (S )< if (S / Q ) добавить S в Q как непомеченное состояние; определить D (R, a) =S;

32 32 ГЛАВА 3. ЛЕКСИЧЕСКИЙ АНАЛИЗ > > > (4) Определить F = . Пример 3.6. Результат применения алгоритма 3.2 приведен на рис H H H D H H D E E H E H H D $ D % E D & D E D E ‘ E ( E Рис. 3.10: Построение детерминированного конечного автомата по регулярному выражению Приведем теперь алгоритм построения по регулярному выражению детерминированного конечного автомата, допускающего тот же язык [10]. Пусть дано регулярное выражение r в алфавите T. К регулярному выражению r добавим маркер конца: (r)#. Такое регулярное выражение будем называть пополненным. В процессе своей работы алгоритм будет использовать пополненное регулярное выражение.

33 3.3. АЛГОРИТМЫ ПОСТРОЕНИЯ КОНЕЧНЫХ АВТОМАТОВ 33 Алгоритм будет оперировать с синтаксическим деревом для пополненного регулярного выражения (r)#, каждый лист которого помечен символом a T , а каждая внутренняя вершина помечена знаком одной из операций: (конкатенация), (объединение), (итерация). Каждому листу дерева (кроме e-листьев) припишем уникальный номер, называемый позицией, и будем использовать его, с одной стороны, для ссылки на лист в дереве, и, с другой стороны, для ссылки на символ, соответствующий этому листу. Заметим, что если некоторый символ используется в регулярном выражении несколько раз, он имеет несколько позиций. Теперь, обходя дерево T снизу-вверх слева-направо, вычислим четыре функции: nullable, f irstpos, lastpos и f ollowpos. Функции nullable, firstpos и lastpos определены на узлах дерева, а followpos на множестве позиций. Значением всех функций, кроме nullable, является множество позиций. Функция f ollowpos вычисляется через три остальные функции. Функция f irstpos(n) для каждого узла n синтаксического дерева регулярного выражения дает множество позиций, которые соответствуют первым символам в подцепочках, генерируемых подвыражением с вершиной в n. Аналогично, lastpos(n) дает множество позиций, которым соответствуют последние символы в подцепочках, генерируемых подвыражениями с вершиной n. Для узла n, поддеревья которого (т.е. деревья, у которых узел n является корнем) могут породить пустое слово, определим nullable(n) =true, а для остальных узлов nullable(n)=f alse. Таблица для вычисления функций nullable, f irstpos и lastpos приведена на рис узел n nullable(n) firstpos(n) lastpos(n) лист e true лист i false (не e) nullable(u) /\ or f irstpos(u) f irstpos(v) lastpos(u) lastpos(v) uv nullable(v) nullable(u) if nullable(u) then if nullable(v) then /\ and f irstpos(u) f irstpos(v) lastpos(u) lastpos(v) u v nullable(v) else f irstpos(u) else lastpos(v) true f irstpos(v) lastpos(v) v Рис. 3.11: Пример 3.7. Синтаксическое дерево для пополненного регулярного выражения (a b) abb# с результатом вычисления функций firstpos и lastpos приведено

34 34 ГЛАВА 3. ЛЕКСИЧЕСКИЙ АНАЛИЗ ^` ^` ^` ^` ^` ^` ^` ^` ^`E ^` ^` ^` ^`E ^` ^`^` ^`D ^` ^` _ ^` ^`D ^` ^`E ^` Рис. 3.12: позиция f ollowpos 1 <1, 2, 3>2 <1, 2, 3>3 <4>4 <5>5 <6>6 Рис. 3.13: на рис Слева от каждого узла расположено значение firstpos, справа от узла значение lastpos. Заметим, что эти функции могут быть вычислены за один обход дерева. Если i позиция, то followpos(i) есть множество позиций j таких, что существует некоторая строка. cd. входящая в язык, описываемый регулярным выражением, такая, что позиция i соответствует этому вхождению c, а позиция j вхождению d. Функция f ollowpos может быть вычислена также за один обход дерева снизу-вверх по следующим двум правилам. 1. Пусть n внутренний узел с операцией (конкатенация), u и v его потомки. Тогда для каждой позиции i, входящей в lastpos(u), добавляем к множеству значений f ollowpos(i) множество f irstpos(v). 2. Пусть n внутренний узел с операцией (итерация), u его потомок. Тогда для каждой позиции i, входящей в lastpos(u), добавляем к множеству значений f ollowpos(i) множество f irstpos(u).

35 3.3. АЛГОРИТМЫ ПОСТРОЕНИЯ КОНЕЧНЫХ АВТОМАТОВ 35 Пример 3.8. Результат вычисления функции followpos для регулярного выражения из предыдущего примера приведен на рис Алгоритм 3.3. Прямое построение ДКА по регулярному выражению. Вход. Регулярное выражение r в алфавите T. Выход. ДКА M =(Q,T,D,q 0,F), такой что L(M) =L(r). Метод. Состояния ДКА соответствуют множествам позиций. Вначале Q и D пусты. Выполнить шаги 1-6: (1) Построить синтаксическое дерево для пополненного регулярного выражения (r)#. (2) Обходя синтаксическое дерево, вычислить значения функций nullable, f irstpos, lastpos и f ollowpos. (3) Определить q 0 = firstpos(root), где root корень синтаксического дерева. (4) Добавить q 0 в Q как непомеченное состояние. (5) Выполнить следующую процедуру: while (в Q есть непомеченное состояние R) < пометить R; for (каждого входного символа a T, такого, что в R имеется позиция, которой соответствует a)< пусть символ a в R соответствует позициям p 1. p n, и пусть S = followpos(p i ); 1 i n if (S )< if (S / Q) добавить S в Q как непомеченное состояние; определить D(R, a) =S; >> > (6) Определить F как множество всех состояний из Q, содержащих позиции, связанные с символом #. Пример 3.9. Результат применения алгоритма 3.3 для регулярного выражения (a b) abb приведен на рис

Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL