This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Кодовое имя проекта: PascalABCPartParser
Название: Восстановление синтаксического разбора после ошибок
Автор: Бушманова Наталья
EMail: bnv86@mail.ru
ICQ автора: 437-769-185
Логин на SVN: kurs4
Краткое описание проекта: Восстановление синтаксического разбора после ошибок
Комментарии:
Применяется стратегия «переполоха». Как только анализатор встречает неожиданный символ во входном
потоке, выполняются следующие действия: недопустимый символ игнорируется, и парсер переходит в одно
из состояний, сохраненных ранее. Состояния парсера представлены в виде структур, которые добавляются
в стек Stack<ParserState> ps. Если же после восстановления снова возникает синтаксическая ошибка,
парсер «откатывается» еще выше по стеку. Случаи, когда запоминается состояние анализатора:
1) вначале программы;
2) после каждой секции var, type, const, label;
3) после statement;
4) после служебного слова begin;
Алгоритм
СохранениеСостоянияПарсера()
1. Сохранить во временную структуру текущие значения полей класса Parser
2. Добавить в СтекСостояний эту структуру
3. ПроизошлоСохранение = истина
...................................
ВосстановлениеСостоянияПарсера()
1. Поместить во временную структуру Состояние с вершины СтекаСостояний
2. Значениям полей класса Parser присвоить значения полей Состояния
3. ПроизошлоСохранение = ложь
4. ПроизошлоВосстановление = истина
....................................
Parse()
1. Действия для обработки комментариев
2. Пока (истина)
Если (токен.символ != null)
Если (предыдущий символ потока begin или class или record)
СохранениеСостоянияПарсера()
ТекущийСимвол = ЧитатьСимвол()
Если (ДописанBegin)
ТекущийСимвол = ";"
ДописанBegin = ложь
Если (ДописанEndЗавершающийОснПрог)
ТекущийСимвол = "."
ДописанEndЗавершающийОснПрог = ложь
Если (ТекущийСимвол == Procedure)
Добавить в СтекТокенов
Выход
Если (ТекущийСимвол == Function)
Добавить в СтекТокенов
Выход
Если (ТекущийСимвол == Class)
Добавить в СтекТокенов
Выход
Если (ТекущийСимвол == Record)
Добавить в СтекТокенов
Выход
Если (ТекущийСимвол == Begin)
Добавить в СтекТокенов
Выход
Если (ТекущийСимвол == End)
Если (СтекТокенов не пуст и на его вершине Begin)
Удалить Begin с вершины СтекаТокенов
Если (СтекТокенов не пуст и на его вершине Procedure или Function)
Удалить Begin с вершины СтекаТокенов
Выход
Если (ТекущийСимвол == EOF)
ТекущийРазмерСтекаТокенов = СтекТокенов.Размер
Если (не было блока основной программы и СтекТокенов пуст)
ТекущийСимвол = "Begin"
ДописанBegin = истина
Добавить Begin в СтекТокенов
Выход
Если (ТекущийРазмерСтекаТокенов>0 и ПроизошлоВосстановление и ДописанBegin = ложь)
Если (на вершине СтекаТокенов Record)
ТекущийСимвол = "End"
ДописанBegin = истина
Если (СтекТокенов.Размер!=0)
Удалить символ с вершины СтекаТокенов
ТекущийРазмерСтекаТокенов--
Выход
Если (на вершине СтекаТокенов Class)
ТекущийСимвол = "End"
ДописанBegin = истина
Если (СтекТокенов.Размер!=0)
Удалить символ с вершины СтекаТокенов
ТекущийРазмерСтекаТокенов--
Выход
Если (на вершине СтекаТокенов Begin)
ТекущийСимвол = "End"
Если (СтекТокенов.Размер==1)
ДописанEndЗавершающийОснПрог = истина
Если (СтекТокенов.Размер!=0)
Удалить символ с вершины СтекаТокенов
ТекущийРазмерСтекаТокенов--
Если (СтекТокенов не пуст и на его вершине Procedure или Function)
Удалить Begin с вершины СтекаТокенов
ТекущийРазмерСтекаТокенов--
ДописанBegin = истина
Выход
Иначе
Если (ТекущийСимвол это пробел или комментарии)
Действия для обработки комментариев и пробелов
Иначе
ПарситьТокен()
....
Если (результат парсинга это синтакс. ошибка)
Если (не происходило сохранения состояния парсера после предыдущим восстановлением) то
Удалить Состояние с вершины СтекаСостояний
Вернуть Результат.Синт_Ошибка
...........................
ParseToken()
Если (ТекущееПравило!=null и не конец потока и
(ТекущееПравило == statment или ТекущееПравило == секция_var или
ТекущееПравило == секция_type или
ТекущееПравило == секция_const или
ТекущееПравило == секция_label)) то
СохранениеСостоянияПарсера()
...........................
Parse(строка)
Если (LRParser.Parse() == Сообщение.Синт_Ошибка)
Если (СтекСостояний не пуст)
ВосстановлениеСостоянияПарсера()
Выход
...........................
В папке _COPY копии файлов из проекта ParsetTools и PascalABCParser. Их менять нельзя. Когда
проекты объеденятся, они исчезнут.
Движок находится в TestGoldParserEngine.
Parser.cs - обвертка для подключения всей это бодяги к компилятору.
pascalabc_lrparser.cs - обвертка над движком прасера
_COPY\pascalabc_lrparser_rules.cs - правила
Выделяй части движка которые правиш. Старайся оформлять свои части в виде отделльных процедур.
Твои части должны работать только в определенном режиме движка. Это нужно чтобы потом обеденить движки.
Заведи себе в движке поле PartModeON, чтобы активировать твою часть можно было так:
parser.PartModeON=true;