Разработка инструментальных средств создания текстовых предметно-ориентированных языков: компонент проверки синтаксиса
Характеристика метода создания текстовых предметно-ориентированных языков. Расчет трудоемкости разработки компонента проверки синтаксиса. Проектирование архитектуры языкового инструментария и программная реализация компонента проверки синтаксиса.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | дипломная работа |
Язык | русский |
Дата добавления | 01.08.2017 |
Размер файла | 2,9 M |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
К квалификации персонала системы предъявляются следующие требования:
1. Пользователь должен знать данную предметную область.
2. Иметь минимальные навыки работы с вычислительной техникой, навыки работы с аналитическими приложениями.
Режимы работы конечного пользователя обуславливается его рабочим графиком.
И.1.4. Перечень эксплуатационной документации
Перечень документов, с которыми следует ознакомиться перед эксплуатацией:
1. Руководство пользователя.
2. Руководство администратора (см. прил. К).
И.2. Назначения и условия применения
И2.1. Виды деятельности, функции
Языковой инструментарий предназначен для упрощения процесса создания текстовых DSL, в частности за счет следующих показателей, реализуемых в результате применения инструментария:
1. Предоставление визуального представления конструкций языка и программы с помощью выделения их цветом.
2. Оптимизация процесса проверки корректности программы относительно созданного языка.
3. Сокращение количества возможных лексических и синтаксических ошибок за счет предоставления пользователю списка ожидаемых терминальных символов для каждой конструкции языка в момент формирования программы.
4. Предоставление пользователю возможности оперировать проектами как разработанными непосредственно в данной системе, так и из внешних источников посредством репозитория и браузера проектов.
Перечень функций, реализованных в системе, приведен в разделе И1.2 текущего документа.
И.2.2. Программные и аппаратные требования к системе
Система должна использоваться на ПК со следующими операционными системами: Windows XP, Windows 7, Windows 8, Windows 10.
В состав технических средств должен входить:
1. IBM-совместимый персональный компьютер (ПЭВМ), включающий в себя:
1.1. Процессор Pentium - 4 с тактовой частотой 1.2 ГГц, не менее.
1.2. Оперативную память объемом, 512 Mб, не менее.
1.3. Жесткий диск объемом 40 Гб, и выше.
1.4. Оптический манипулятор типа «мышь».
2. Локальная сеть. Пропускная способность ЛС до 1Гб/сек.
И.3. Подготовка к работе
И.3.1. Запуск системы
Для работы с языковым инструментарием сначала необходимо открыть папку, в которую была установлена система, и запустить файл EBNF.exe.
И.3.2. Проверка работоспособности системы
Система работоспособна, если при выполнении действий, описанных в пункте И.3.1. настоящего документа, открылось главное окно редактора кода без выдачи сообщения об ошибках на экран пользователя.
И.4. Описание операций
После успешного входа в систему будет открыто главное окно, состоящее из редактора кода и браузера проектов, расположенного в правой части окна (рис. И.1).
Рисунок И.1. Главное окно системы
Объекты репозитория загружаются в браузер проектов автоматически и образуют иерархию, первый уровень которой представляет решения, следующий - языки и последний - программы. Управление репозиторием включает в себя возможность выполнения определенных функций для каждого из уровней с помощью вызова контекстного меню.
Контекстное меню для браузера проектов (вызывается с помощью нажатия правой кнопкой мыши по пустой области браузера):
1. Создать решение - создает новое решение с заданным именем.
2. Загрузить решение извне - позволяет создать новое решение с заданным именем и загрузить в него все созданные языки из выбранной папки.
3. Загрузить решение извне полностью - позволяет создать новое решение с заданным именем и загрузить в него все созданные языки и программы из выбранной папки.
Контекстное меню для решений (вызывается с помощью нажатия правой кнопкой мыши по выбранному решению):
1. Редактировать - открывает на редактирование все созданные языки в данном решении.
2. Редактировать все - открывает на редактирование все созданные языки и программы в данном решении.
3. Загрузить в репозиторий извне - загружает в данное решение выбранный язык.
4. Загрузить в репозиторий извне все - загружает в данное решение выбранный язык со всеми спроектированными программами.
5. Переименовать - изменяет имя решения на заданное.
6. Удалить - удаляет решение из браузера проектов.
7. Создать модель - создает новый язык.
Контекстное меню для языков (вызывается с помощью нажатия правой кнопкой мыши по выбранному языку).
1. Редактировать - открывает на редактирование данный язык.
2. Редактировать все - открывает на редактирование данный язык и все созданные на его основе программы.
3. Загрузить в репозиторий извне - загружает в данный язык выбранную программу.
4. Переименовать - изменяет имя языка на заданное.
5. Удалить - удаляет язык из браузера проектов.
6. Создать модель - создает новую программу.
Контекстное меню для программ (вызывается с помощью нажатия правой кнопкой мыши по выбранной программе).
1. Редактировать - открывает на редактирование данную программу.
2. Переименовать - изменяет имя программы на заданное.
3. Удалить - удаляет программу из браузера проектов.
Кроме того, в нижней части браузера проектов располагаются кнопки «Запомнить», «Выход», позволяющие актуализировать репозиторий до состояния браузера проектов и выйти из системы соответственно.
После открытия языка или программы с помощью соответствующего пункта контекстного меню появляется редактор кода, состоящий из рабочей области и области вывода ошибок с индикаторами корректности, а также кнопки «Выйти без сохранения», «Сохранить и выйти», «Сохранить». Переход между открытыми языками и программами осуществляется посредством клика левой кнопкой мыши по нужной вкладке, расположенной в верхней части редактора.
Язык и программа считаются корректно спроектированными, если в области ошибок не появилось ни одного уведомления, а также индикаторы корректности горят зеленым цветом (рис. И.2):
Рисунок И.2. Пример корректного языка
При создании языка и программы строка в которой обнаружена ошибка и индикатор корректности подсвечиваются красным цветом (см. рис. И.3)
Рисунок И.3. Пример некорректной программы
Для сокращения числа возможных синтаксических ошибок в системе предусмотрен вывод списка ожидаемых символов, появляющийся во время редактирования программы. Для выбора нужного варианта следует навести курсор мыши на символ и кликнуть левой кнопкой мыши (рис. И.4).
Рисунок И.4. Список ожидаемых символов
И.5. Аварийные ситуации
При сбое в работе системы, аппаратуры достаточно выполнить перезапуск исполняемого файла системы или перезагрузку ОС.
Приложение К. Руководство системного программиста
Языковой инструментарий: компоненты описания и проверки синтаксиса Руководство системного программиста
Номер документа
На 3 листах
Действует с «___»________2017 г.
Пермь 2017
К.1. Общие сведения о системе
Данный языковой инструментарий предназначена для упрощения процесса разработки текстовых DSL за счет наличия редактора кода с подсветкой синтаксиса, браузера проектов, валидатора для автоматизации процесса анализа программы на наличие лексических и синтаксических ошибок относительно спроектированного языка.
Основные функции системы:
1. Создание решения, языка и программы.
2. Подсветка синтаксиса языка и программы на основе формально заданных правил.
3. Проверка языка на наличие лексических, синтаксических и семантических ошибок.
4. Проверка программы на наличие синтаксических ошибок относительно спроектированного языка.
5. Отображение списка ожидаемых терминальных символов для конструкции языка в момент редактирования программы.
6. Сохранение, загразка, удаление и переименование решений, языков и программ в репозитории.
К.2. Структура программы
Архитектура системы состоит из нескольких компонентов (см. рис. К.1):
1. Редактор кода - выполняет лексический анализ текста языка и программы, после чего передает полученную информацию компоненту проверки синтаксиса. Кроме того, в функции данного модуля входит подсвета синтаксиса языка по заданной разметке, отображение списка найденных ошибок.
2. Валидатор - выполнят построение дерева синтаксического разбора для языка по данным, полученным от лексического анализатора, с целью проверки корректности синтаксиса программы. В качестве результата передает редактору кода получившуюся разметку текста, список найденных в ходе анализа ошибок в языке, набор ожидаемых символов для заданной конструкции программы.
3. Репозиторий - набор XML файлов на жестком диске с определенным расширением, зависящим от уровня сохраняемого объекта: решение, язык, программа.
4. Браузер проектов - позволяет управлять репозиторием: редактировать, сохранять, удалять, добавлять, переименовывать решения, языки и программы.
Размещено на http://www.allbest.ru/
Рисунок К.1. Архитектура системы
Связь между лексическим и синтаксическим анализаторами можно представить на примере диаграмм последовательности для бизнес-процессов редактирования языка и программы (рис. К.2, см. рис. К.3).
Рисунок К.2. Диаграмма последовательности «Редактирование языка»
Рисунок К.3. Диаграмма последовательности «Редактирование программы»
Диаграмма классов, отражающая структуру разработанной системы представлена в приложении (см. прил. В).
К.3. Настройка системы
Требования, предъявляемые к параметрам технических средств:
1. IBM-совместимый персональный компьютер (ПЭВМ), включающий в себя:
1.1. Процессор Pentium - 4 с тактовой частотой 1.2 ГГц, не менее.
1.2. Оперативную память объемом, 512 Mб, не менее.
1.3. Жесткий диск объемом 40 Гб, и выше.
1.4. Оптический манипулятор типа «мышь».
2. Локальная сеть. Пропускная способность ЛС до 1Гб/сек.
Требования к информационной и программной совместимости:
1. Среда разработки MS Visual Studio, так как она предназначена для разработки и исполнения приложений различных типов, в том числе приложение Windows Forms.
2. Операционные системы, которые поддерживают среду разработки:
2.1. WindowsXP.
2.2. Windows 7.
2.3. Windows 8.
2.4. Windows 10.
Приложение Л. Тестирование методом сценариев
Таблица Л.1. Результаты тестирования
Порядок действий |
Реакция системы |
Результат (пройден/не пройден) |
|
Состояние системы: |
Открыта и готова к использованию |
||
Функция «Создание решения» |
|||
1. Нажать правой кнопкой мыши по пустой области в браузере проектов. 2. Выбрать пункт контекстного меню «Создать решение». 3. Ввести название решения: a. Решение с данным названием уже существует. b. Название уникально. 4. Закрыть диалоговое окно ввода названия: a. Нажать «ОК». b. Нажать на «крестик» в правом верхнем углу. 5. Закрыть диалоговое окно с предупреждением о наличии решения с таким же названием: a. Нажать «ОК». b. Нажать на «крестик» в правом верхнем углу |
(1, 2, 3-a, 4-a, 5-a) - Существующее решение перезаписалось (1,2,3(a/b),4-b) - Состояние системы не изменилось, узел не создался. (1, 2, 3-a, 4-a, 5-b) - Состояние системы не изменилось, узел не создался. (1, 2, 3-b, 4-a) - Создался новый узел с решением |
Пройден |
|
Функция «Создание языка» |
|||
1. Нажать правой кнопкой мыши по решению. a. В решении нет языков. b. В решении есть созданные языки. 2. Выбрать пункт контекстного меню «Создать язык». 3. Ввести название языка. a. Язык с данным названием уже существует. b. Название языка уникально в пределах решения. 4. Закрыть диалоговое окно ввода названия: a. Нажать «ОК» b. Нажать на «крестик» в правом верхнем углу. 5. Закрыть диалоговое окно с предупреждением о наличии языка с таким же названием: a. Нажать кнопку «Заменить». b. Нажать на «крестик» в правом верхнем углу |
(1-b, 2, 3-a, 4-a, 5-a) - Существующий язык перезаписался. (1(a/b),2,3(a/b),4-b) - Состояние системы не изменилось, узел для языка не создался. (1-b, 2, 3-a, 4-a, 5-b) - Состояние системы не изменилось, узел не создался. (1(a/b), 2, 3-b, 4-a) - Создался новый узел с языком в выбранном решении |
Пройден |
|
Функция «Создание программы» |
|||
1. Нажать правой кнопкой мыши по языку. a. В языке нет программ. b. В языке есть созданные программы. 2. Выбрать пункт контекстного меню «Создать программу». 3. Ввести название программы. a. Программа с данным названием уже существует. b. Название программы уникально в пределах решения. 4. Закрыть диалоговое окно ввода названия: a. Нажать «ОК» b. Нажать на «крестик» в правом верхнем углу. 5. Закрыть диалоговое окно с предупреждением о наличии программы с таким же названием: a. Нажать кнопку «Заменить». b. Нажать на «крестик» в правом верхнем углу |
(1-b, 2, 3-a, 4-a, 5-a) - Существующая программа перезаписалась. (1(a/b),2,3(a/b),4-b) - Состояние системы не изменилось, узел для программы не создался. (1-b, 2, 3-a, 4-a, 5-b) - Состояние системы не изменилось, узел не создался. (1(a/b), 2, 3-b, 4-a) - Создался новый узел с программой в выбранном языке |
Пройден |
|
Функция «Редактирование языка, программы» |
|||
1. Нажать правой кнопкой мыши по языку/программе. 2. Выбрать пункт контекстного меню «Редактировать». a. Выбранный язык/программа уже открыт. b. Вкладка для языка/программы еще не создана |
(1, 2-a) - Вкладка, содержащая нужный язык/программу, стала активной. (1,2-b) - Создалась новая вкладка, выбранный язык/программа открыт для редактирования |
Пройден |
|
Функция «Редактирование всех языков и программ решения» |
|||
1. Нажать правой кнопкой мыши по решению. 2. Выбрать пункт контекстного меню «Редактировать все». a. Какой-либо из объектов решения уже открыт. b. Ни один объект решения еще не открыт |
(1, 2-a) - Для открытых объектов новые вкладки не создались. Активной вкладкой стал последний открытый объект. (1,2-b) - Создались новые вкладки для всех объектов решения |
Пройден |
|
Функция «Редактирование всех программ языка» |
|||
1. Нажать правой кнопкой мыши по языку. 2. Выбрать пункт контекстного меню «Редактировать все». a. Какая-либо из программ уже открыта. b. Ни одна из программ языка еще не открыт |
(1, 2-a) - Для открытых программ новые вкладки не создались. Активной вкладкой стала последняя открытая программа. (1,2-b) - Создались новые вкладки для всех программ языка |
Пройден |
|
Функция «Загрузка из репозитория» |
|||
1. Нажать правой кнопкой мыши по нужному объекту: a. Решение. b. Язык. 2. Выбрать пункт контекстного меню «Загрузить в репозиторий». 3. В диалоговом окне выбрать нужный объект: a. Данный объект уже существует в рамках решения. b. Данный объект уже существует в рамках языка. c. Объект уникален и не содержит ошибок. d. Объект содержит ошибки. 4. В диалоговом окне уведомления о наличии объекта в системе нажать кнопку: a. Заменить. b. Отмена. 5. В диалоговом окне уведомления о наличии ошибок нажать кнопку: a. Открыть модель. b. Отмена |
(1-a, 2, 3-a, 4-a) - Выбранный язык заменил язык, имеющийся в браузере проектов. (1-a, 2, 3-a, 4-b) - Состояние системы не изменилось. (1-a, 2, 3-c) - Создался новый узел, содержащий выбранный язык в браузере проектов. (1-a, 2, 3-d, 5-a) - Создался новый узел, содержащий выбранный язык в браузере проектов. (1-a, 2, 3-d, 5-b) - Состояние системы не изменилось. (1-b, 2, 3-b, 4-a) - Выбранная программа заменила программу, имеющуюся в браузере проектов. (1-b, 2, 3-b, 4-b) - Состояние системы не изменилось. (1-b, 2, 3-с) - Выбранная программа создалась в браузере проектов. (1-b, 2, 3-d, 5-a) - Выбранная программа создалась в браузере проектов. (1-b, 2, 3-d, 5-b) - Состояние системы не изменилось |
Пройден |
|
Функция «Переименование решения, языка, программы» |
|||
1. Нажать правой кнопкой мыши по нужному объекту: a. Решение. b. Язык. c. Программа. 2. Выбрать пункт контекстного меню «Переименовать». 3. В диалоговом окне ввести название: a. Объект с таким именем уже существует. b. Имя уникальное. 4. В диалоговом окне изменения имени нажать кнопку: a. ОК. b. Отмена |
(1(a/b/c), 2, 3-a) - Объект не переименован. (1(a/b/c), 2, 3-b, 4-a) - Объект переименован. (1(a/b/c), 2, 3-b, 4-b) - Объект не переименован |
Пройден |
|
Функция «Сохранение и выход» |
|||
1. Открыть для редактирования объект: a. Язык. b. Программа. 2. Нажать кнопку «Выйти без сохранения»: a. Объект не был изменен. b. Объект редактировался. 3. Нажать кнопку «Сохранить и выйти»: a. Объект не был изменен. b. Объект редактировался. 4. Нажать на кнопку «Сохранить»: a. Объект не был изменен. b. Объект редактировался |
(1(a/b), 2(a/b)) - Изменения в объекте не сохранились, вкладка закрылась. (1(a/b), 3(a/b)) - Изменения в объекте сохранились, вкладка закрылась. (1(a/b), 4(a/b)) - Изменения в объекте сохранились, вкладка не закрылась |
Пройден |
Приложение М. Программный код
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
namespace EBNF
{
/// Представление терминальных и нетерминальных символов
internal abstract class CSymbol
{
}
/// Представление терминала
internal class CTerminal : CSymbol
{
internal string Symbol;
internal CTerminal(string Symbol)
{
this.Symbol = Symbol;
}
}
/// Представление нетерминала
internal abstract class CNonterminal : CSymbol
{
}
/// Типы предопределённых нетерминалов
internal enum EPredefined
{
/// Пропуск
eSpace,
/// Цифра
eDigit,
/// Буква
eLetter,
/// Идентификатор
eIdentifier
}
/// Предопределённый нетерминал
internal class CPredefined : CNonterminal
{
internal EPredefined type;
internal bool CanEmpty;
/// Создание предопределённого нетерминала заданного типа
internal CPredefined(EPredefined type, bool CanEmpty)
{
this.type = type;
this.CanEmpty = CanEmpty;
}
}
/// Определяемый пользователем нетерминал
internal class CDefined : CNonterminal
{
/// Данный нетерминал не является стартовым
internal bool NonStart;
/// Индекс элемента в списке TextStructure класса CSequence, к которому отностися нетерминал.
internal int it;
/// Индекс элемента, следующего за правилом, определяющим нетерминал, либо индекс конца правила первого появления, если нетерминал ещё не определён
internal int ier;
internal List<CSymbol> Sequence;
/// Меню для данного нетерминала
internal List<string>[] menus;
/// Список связей. Используется для определения циклических определений нетерминалов.
internal List<CDefined> links;
/// Добавляет в список связей нетерминал, если его ещё нет в этом списке
internal void AddLink(CDefined d)
{
for (int i = 0; i < links.Count; i++)
if (links[i] == d)
return;
links.Add(d);
}
/// Удаляет из списка связей нетерминалы с пустыми списками связей
internal bool RemoveLinks()
{
bool ret = false;
for (int i = links.Count - 1; i >= 0; i--)
if (links[i].links.Count == 0)
{
links.RemoveAt(i);
ret = true;
}
return ret;
}
/// Добавить пункт в меню
internal static void Add2Menu(List<string> menu, string item)
{
for (int i = 0; i < menu.Count; i++)
if (menu[i] == item)
return;
menu.Add(item);
}
/// Объединяет 2 меню
internal static void Add2Menu(List<string> menu, List<string> items)
{
if (items == null)
return;
int i;
for (int k = 0; k < items.Count; k++)
{
for (i = 0; i < menu.Count; i++)
if (menu[i] == items[k])
break;
if (i >= menu.Count)
menu.Add(items[k]);
}
}
/// Создаёт меню для данного нетерминала
internal void MakeMenu()
{
menus = new List<string>[Sequence.Count];
List<int> iGroop = new List<int>(); //Начала вложенных групп
iGroop.Add(0);
menus[0] = new List<string>();
bool ToCombine = true;
List<bool> combines = new List<bool>();
for (int i = 0; i < Sequence.Count; i++)
{
CSymbol symb = Sequence[i];
List<string> menu; //Текущее меню
if (symb is CTerminal)
{
if (ToCombine)
{//Объединить с меню начала группы
Add2Menu(menus[iGroop[iGroop.Count - 1]], (symb as CTerminal).Symbol);
menus[i] = menus[iGroop[iGroop.Count - 1]];
}
else
{//Создать индивидуальное для терминала меню
menus[i] = new List<string>();
menus[i].Add((symb as CTerminal).Symbol);
}
ToCombine = false;
}
else if (symb is CDefined)
{
CDefined d = symb as CDefined;
if (d.menus == null)
d.MakeMenu();
if (ToCombine)
{
menu = menus[i] = menus[iGroop[iGroop.Count - 1]];
ToCombine = false;
}
else menu = menus[i] = new List<string>();
if (d.menus[0] != null)
for (int j = 0; j < d.menus[0].Count; j++)
menu.Add(d.menus[0][j]);
}
else if (symb is CMetaSymbol)
switch ((symb as CMetaSymbol).type)
{
case EMetaType.eEndOption:
case EMetaType.eEndRepeator:
if (combines.Count > 0 && combines[combines.Count - 1])
Add2Menu(menus[iGroop[iGroop.Count - 2]], menus[iGroop[iGroop.Count - 1]]);
iGroop.RemoveAt(iGroop.Count - 1);
ToCombine = combines[combines.Count - 1];
combines.RemoveAt(combines.Count - 1);
break;
case EMetaType.eStartOption:
case EMetaType.eStartRepeator:
menus[i] = new List<string>();
iGroop.Add(i);
combines.Add(ToCombine);
ToCombine = true;
break;
default: //Разделитель
ToCombine = true;
break;
}
else if (!(symb as CPredefined).CanEmpty)
ToCombine = false; //Предопределённый идентификатор, который не может быть пустым
}
List<string> CurrentMenu = null;
List<List<string>> GroupMenus = new List<List<string>>(); //Меню на выходе вложенных групп
GroupMenus.Add(null); //Для основной последовательности
for (int i = Sequence.Count - 1; i >= 0; i--)
{
CSymbol symb = Sequence[i];
if (symb is CPredefined)
{
if ((symb as CPredefined).CanEmpty)
menus[i] = CurrentMenu; //Для предопределённого нетерминала, который может быть пустым
else
CurrentMenu = menus[i];
}
else if (symb is CDefined || symb is CTerminal)
CurrentMenu = menus[i]; //Текущее меню - меню данного символа
else switch ((symb as CMetaSymbol).type)
{
case EMetaType.eEndOption: //Добавляется в начало группы текущее меню
case EMetaType.eEndRepeator:
Add2Menu(menus[(symb as CMetaSymbol).iGoto], CurrentMenu);
GroupMenus.Add(CurrentMenu);
break;
case EMetaType.eSeparator:
CurrentMenu = GroupMenus[GroupMenus.Count - 1];
break;
case EMetaType.eStartOption: //Текущее меню - меню конца группы
case EMetaType.eStartRepeator:
GroupMenus.RemoveAt(GroupMenus.Count - 1);
CurrentMenu = menus[i];
break;
}
}
//Обнулить меню с нулевым количеством пунктов
for (int i = 0; i < menus.GetLength(0); i++)
if (menus[i] != null && menus[i].Count == 0)
menus[i] = null;
}
/// Создаётся определяемый пользователем нетерминал
internal CDefined(int it)
{
this.it = it;
NonStart = false;
Sequence = new List<CSymbol>(32);
menus = null;
}
}
/// Типы метасимволов, присутствующих в описании нетерминала
internal enum EMetaType
{
/// Начало группы опций
eStartOption,
/// Конец группы опций
eEndOption,
/// Начало группы повторений
eStartRepeator,
/// Конец группы повторения
eEndRepeator,
eSeparator
}
/// Класс, представляющий метасимвол в описании нетерминала
internal class CMetaSymbol : CSymbol
{
internal EMetaType type;
/// Индекс символа в определении, на который происходит переход при выполнении условия перехода:
/// в конце группы - индекс метасимвола начала группы,
/// в разделителе и в начале группы - индекс конца группы.
internal int iGoto;
/// Создание объекта представляющего метасимвол в описании нетерминала
internal CMetaSymbol(EMetaType type)
{
this.type = type;
}
/// Создание объекта представляющего метасимвол в описании нетерминала
internal CMetaSymbol(EMetaType type, int iGoto)
{
this.type = type;
this.iGoto = iGoto;
}
}
/// Элементы разметки текста описания языка
internal enum ETextPiece
{
incorrect,
terminal,
extention,
nonterminal,
metasymbol
}
/// Элемент разметки текста метамодель
internal class CTextStructure
{
/// Индекс символа в тексте, с которого начинается элемент
internal int ind;
internal ETextPiece type;
internal CTextStructure(int ind, ETextPiece type)
{
this.ind = ind;
this.type = type;
}
}
/// Последовательность символов, которая представляет язык
public class CSentence
{
/// Стартовый символ
internal string StartSymbol;
/// Упорядоченный список нетерминалов
private Dictionary<string, CNonterminal> Nonterminals;
/// Структура текста языка с целью раскраски
internal List<CTextStructure> TextStructure;
/// Список ошибок
internal List<string> SemanticErrors;
/// Обнаружена синтаксическая ошибка для текущего определения
private bool error;
internal bool LanguageFault;
/// Начало правила в тексте. На случай, если правило ошибочно.
private int iTS;
static char[] cServiceSymbols = { ';', '<', '\\', ':', '[', ']', '{', '}', '|' };
private int MissSpaces(int i, string s)
{
int ret = i;
while (ret < s.Length && (s[ret] == ' ' || s[ret] == '\r' || s[ret] == '\n' || s[ret] == '\t'))
ret++;
return ret;
}
/// Поиск начала или конца метасимвола
private int SearchBoundMetasymbol(int i, string s, char c)
{
int ret = i;
if (i >= s.Length)
return -1;
while (ret >= 0 && s[ret] != c)
{
ret = s.IndexOf(c, ret);
if (ret > 0 && s[ret - 1] == '\\')
{
ret++;
if (ret == s.Length)
return -1; }
}
return ret;
}
/// Считывает текст на участке обрабатываемого текста.
private string GetText(int i, int k, string s, ETextPiece type)
{
char[] cs = new char[k - i];
int l = 0;
for (int j = i; j < k; j++)
{
if (s[j] == '\\')
{
TextStructure.Add(new CTextStructure(j, ETextPiece.metasymbol));
TextStructure.Add(new CTextStructure(j + 1, ETextPiece.extention));
if (j < k - 2 && s[j + 2] != '\\')
TextStructure.Add(new CTextStructure(j + 2, type));
j++;
}
if (j < k)
cs[l++] = s[j];
}
return new string(cs, 0, l).Trim();
}
/// Добавление в конец TextStructure ошибки, если последней записью TextStructure уже не была
private void AddError()
{
//Удалить всю разметку до начала правила
while (TextStructure.Count > 0 && iTS <= TextStructure[TextStructure.Count - 1].ind)
TextStructure.RemoveAt(TextStructure.Count - 1);
TextStructure.Add(new CTextStructure(iTS, ETextPiece.incorrect));
LanguageFault = true;
}
private string GetText(ref int i, string s)
{
int k = i;
int i0 = i;
if (s[i] != '\\')
TextStructure.Add(new CTextStructure(i, ETextPiece.terminal));
while (true)
{
k = s.IndexOfAny(cServiceSymbols, k);
if (k < 0)
{
i = s.Length;
return GetText(i0, i, s, ETextPiece.terminal);
}
if (s[k] == '\\')
{
if (k == s.Length - 1)
{
i = s.Length;
return GetText(i0, i, s, ETextPiece.terminal);
}
k += 2;
}
else if (s[k] == ':')
{
if (k < s.Length - 3 && s[k + 1] == ':' && s[k + 2] == '=')
{//Обнаружен символ определения "::="
TextStructure.Add(new CTextStructure(k, ETextPiece.incorrect));
k += 3;
error = true;
TextStructure.Add(new CTextStructure(k, ETextPiece.terminal));
}
else k++;
}
else
{
i = k;
return GetText(i0, k, s, ETextPiece.terminal);
}
}
}
/// Описание группы
private class CGroupDescription
{
internal bool Repeator;
/// Индекс начала группы в последовательности
internal int ind;
/// Индексы принадлежащих группе разделителей (|) в последовательности
internal List<int> iSeparators;
/// Создание описания группы
internal CGroupDescription(bool Repeator, int ind)
{
this.Repeator = Repeator;
this.ind = ind;
iSeparators = new List<int>();
}
}
/// Создаёт меню для каждого нетерминала
internal void MakeMenu()
{
if ((Nonterminals[StartSymbol] as CDefined).menus != null)
return;
(Nonterminals[StartSymbol] as CDefined).MakeMenu();
foreach (CNonterminal nt in Nonterminals.Values)
if (nt is CDefined)
{
CDefined d = nt as CDefined;
if (d.menus == null)
d.MakeMenu();
}
}
private void MarkIncorrectRule(int iS, int iF)
{
for (int j = 0; j < TextStructure.Count; j++)
if (TextStructure[j].ind >= iS)
{
ETextPiece type = TextStructure[j].type;
while (j < TextStructure.Count && TextStructure[j].ind < iF)
{
type = TextStructure[j].type;
TextStructure.RemoveAt(j);
}
TextStructure.Insert(j, new CTextStructure(iS, ETextPiece.incorrect));
if (++j >= TextStructure.Count || TextStructure[j].ind > iF)
TextStructure.Insert(j, new CTextStructure(iF, type));
return;
}
TextStructure.Add(new CTextStructure(iS, ETextPiece.incorrect));
}
/// Анализ метамодели
internal CSentence(string s)
{
int k; //Индекс следующего найденного символа в тексте
CGroupDescription Group;
CNonterminal Nonterminal;
List<CSymbol> Definishing; //Определение нетерминала
SemanticErrors = new List<string>();
TextStructure = new List<CTextStructure>();
TextStructure.Add(new CTextStructure(0, ETextPiece.nonterminal));
List<CGroupDescription> Groups = new List<CGroupDescription>();
Nonterminals = new Dictionary<string, CNonterminal>();
Nonterminals.Add("пропуск", new CPredefined(EPredefined.eSpace, true)); Nonterminals.Add("цифра", new CPredefined(EPredefined.eDigit, false));
Nonterminals.Add("буква", new CPredefined(EPredefined.eLetter, false));
Nonterminals.Add("идентификатор", new CPredefined(EPredefined.eIdentifier, false));
LanguageFault = false;
for (int iS = MissSpaces(0, s); iS < s.Length; iS = MissSpaces(iS, s))
{
iTS = iS; //Начало правила. На случай, если правило ошибочно.
Groups.Add(new CGroupDescription(false, 0)); //Самая внешняя группа (не выделенная скобками) рассматривается как группа опций
k = SearchBoundMetasymbol(iS, s, '<');
if (k > iS || k < 0)
{
AddError();
iS = k;
if (k < 0)
break;
}
iTS = k;
//Поиск конца описываемого нетерминала
TextStructure.Add(new CTextStructure(k, ETextPiece.metasymbol));
iS = k + 1;
k = SearchBoundMetasymbol(iS, s, '>');
if (k < 0)
{//Нет конца нетерминала
AddError();
iS = s.Length;
break;
}
error = false;
List<string> NewNonterminals = new List<string>(); //Список новых нетерминалов в правиле. Если есть синтаксическая ошибка, то они удаляются.
TextStructure.Add(new CTextStructure(iS, ETextPiece.nonterminal));
string DetermedName = GetText(iS, k, s, ETextPiece.nonterminal);
TextStructure.Add(new CTextStructure(k, ETextPiece.metasymbol));
CDefined Determing = null; //Определяемый нетерминал
int itDetermed = TextStructure.Count; //Индекс структуры текста начала определяемого нетерминала
if (!Nonterminals.TryGetValue(DetermedName, out Nonterminal))
{
Nonterminal = new CDefined(iTS);
Nonterminals.Add(DetermedName, Nonterminal);
NewNonterminals.Add(DetermedName);
}
if ((Nonterminal is CDefined) && (Nonterminal as CDefined).Sequence.Count == 0)
{//Нетерминал пока неопределён (последовательность пуста)
Determing = Nonterminal as CDefined;
Determing.it = iTS;
Definishing = Determing.Sequence;
}
else
{
Definishing = new List<CSymbol>(16);
if (!(Nonterminal is CPredefined))
SemanticErrors.Add("Нетерминал <" + DetermedName + "> определён повторно.");
}
iS = MissSpaces(k + 1, s);
for (k = SearchBoundMetasymbol(iS, s, ':'); k >= 0 && k < s.Length - 3 && (s[k + 1] != ':' || s[k + 2] != '=');
k = SearchBoundMetasymbol(k + 1, s, ':')) ;
if (iS < s.Length && k == iS)
{//Метасимвол определения найден
k += 3;
iS = MissSpaces(k, s);
}
else
{//Метасимвол отсутствует или ошибка
error = true;
iS = MissSpaces(k < 0 || k >= s.Length - 3 ? s.Length : k + 3, s);
}
//Чтение определения нетерминала
while (iS < s.Length && s[iS] != ';')
{
switch (s[iS])
{
case '<':
TextStructure.Add(new CTextStructure(iS, ETextPiece.metasymbol));
iS++;
TextStructure.Add(new CTextStructure(iS, ETextPiece.nonterminal));
k = SearchBoundMetasymbol(iS, s, '>');
string name = k < 0 ? null : GetText(iS, k, s, ETextPiece.nonterminal);
if (name == null)
{
error = true;
iS = s.Length;
}
else
{
TextStructure.Add(new CTextStructure(k, ETextPiece.metasymbol));
iS = k + 1;
if (!Nonterminals.TryGetValue(name, out Nonterminal))
{
Nonterminal = new CDefined(iTS);
Nonterminals.Add(name, Nonterminal);
NewNonterminals.Add(name);
}
Definishing.Add(Nonterminal);
}
break;
case '\\':
Definishing.Add(new CTerminal(GetText(ref iS, s)));
error |= iS < s.Length && s[iS] == '\\';
break;
case '|':
TextStructure.Add(new CTextStructure(iS, ETextPiece.metasymbol));
if (Definishing.Count == 0 || (Definishing[Definishing.Count - 1] is CMetaSymbol
&& ((Definishing[Definishing.Count - 1] as CMetaSymbol).type == EMetaType.eSeparator || (Definishing[Definishing.Count - 1] as CMetaSymbol).type == EMetaType.eStartOption
|| (Definishing[Definishing.Count - 1] as CMetaSymbol).type == EMetaType.eStartRepeator)))
error = true;
else
{
Groups[Groups.Count - 1].iSeparators.Add(Definishing.Count);
Definishing.Add(new CMetaSymbol(EMetaType.eSeparator));
}
iS++;
break;
case '[':
TextStructure.Add(new CTextStructure(iS, ETextPiece.metasymbol));
Groups.Add(new CGroupDescription(false, Definishing.Count));
Definishing.Add(new CMetaSymbol(EMetaType.eStartOption));
iS++;
break;
case ']':
TextStructure.Add(new CTextStructure(iS, ETextPiece.metasymbol));
if (Groups.Count > 1 && !Groups[Groups.Count - 1].Repeator)
{
Group = Groups[Groups.Count - 1];
for (int i = 0; i < Group.iSeparators.Count; i++)
(Definishing[Group.iSeparators[i]] as CMetaSymbol).iGoto = Definishing.Count;
(Definishing[Group.ind] as CMetaSymbol).iGoto = Definishing.Count;
Definishing.Add(new CMetaSymbol(EMetaType.eEndOption, Group.ind));
Groups.RemoveAt(Groups.Count - 1);
}
else
error = true;
iS++;
break;
case '{':
TextStructure.Add(new CTextStructure(iS, ETextPiece.metasymbol));
Groups.Add(new CGroupDescription(true, Definishing.Count));
Definishing.Add(new CMetaSymbol(EMetaType.eStartRepeator));
iS++;
break;
case '}':
TextStructure.Add(new CTextStructure(iS, ETextPiece.metasymbol));
if (Groups.Count > 1 && Groups[Groups.Count - 1].Repeator)
{
Group = Groups[Groups.Count - 1];
for (int i = 0; i < Group.iSeparators.Count; i++)
(Definishing[Group.iSeparators[i]] as CMetaSymbol).iGoto = Group.ind;
(Definishing[Group.ind] as CMetaSymbol).iGoto = Definishing.Count;
Definishing.Add(new CMetaSymbol(EMetaType.eEndRepeator, Group.ind));
Groups.RemoveAt(Groups.Count - 1);
}
else
error = true;
iS++;
break;
case '>':
error = true; iS++;
break;
default:
TextStructure.Add(new CTextStructure(iS, ETextPiece.terminal));
Definishing.Add(new CTerminal(GetText(ref iS, s)));
error |= iS < s.Length && s[iS] == '\\';
break;
}
iS = MissSpaces(iS, s);
}
if (iS == s.Length || Groups.Count > 1)
error = true; if (iS < s.Length)
{
TextStructure.Add(new CTextStructure(iS, ETextPiece.metasymbol));
iS++;
}
if (Determing != null)
Determing.ier = iS;
Group = Groups[0];
for (int i = 0; i < Group.iSeparators.Count; i++)
(Definishing[Group.iSeparators[i]] as CMetaSymbol).iGoto = Definishing.Count; //Переход на конец группы опций
Groups.Clear();
if (error)
AddError();
if (Determing != null && Definishing == Determing.Sequence)
Determing.Sequence.Clear(); //Последовательность удаляется, если она была вновь создана
for (int i = 0; i < NewNonterminals.Count; i++)
Nonterminals.Remove(NewNonterminals[i]);
while (TextStructure.Count > 0 && TextStructure[TextStructure.Count - 1].ind >= iTS)
TextStructure.RemoveAt(TextStructure.Count - 1);
TextStructure.Add(new CTextStructure(iTS, ETextPiece.incorrect));
}
else
{
if (Nonterminals.TryGetValue(DetermedName, out Nonterminal))
{
if (Nonterminal is CPredefined)
CDefined def = new CDefined(itDetermed);
def.Sequence = Definishing;
Nonterminals[DetermedName] = def;
}
}
for (int i = 0; i < NewNonterminals.Count; i++)
{
CDefined D = Nonterminals[NewNonterminals[i]] as CDefined;
D.ier = iS;
}
}
}
while (TextStructure.Count > 0 && TextStructure[TextStructure.Count - 1].ind >= s.Length && s.Length > 0)
TextStructure.RemoveAt(TextStructure.Count - 1);
for (int i = TextStructure.Count - 2; i >= 0; i--)
{
if (TextStructure[i].type == TextStructure[i + 1].type)
TextStructure.RemoveAt(i + 1);
if (i < TextStructure.Count - 1 && TextStructure[i].ind == TextStructure[i + 1].ind)
TextStructure.RemoveAt(i); //Если приходится несколько разметок на 1 символ, то оставляется последняя
}
//Построение дерева
foreach (string name in Nonterminals.Keys)
{
Nonterminals.TryGetValue(name, out Nonterminal);
if (Nonterminal is CDefined)
{
CDefined D = Nonterminal as CDefined;
if (D.Sequence.Count == 0)
{
SemanticErrors.Add("Нетерминал <" + name + "> неопределён.");
MarkIncorrectRule(D.it, D.ier);
}
else
for (int i = 0; i < D.Sequence.Count; i++)
{
CSymbol symbol = D.Sequence[i];
if (symbol is CDefined)
(symbol as CDefined).NonStart = true;
}
}
}
List<string> StartNonterminals = new List<string>(); //Список стартовых нетерминалов
bool b;
foreach (string name in Nonterminals.Keys)
{
Nonterminals.TryGetValue(name, out Nonterminal);
if (Nonterminal is CDefined)
{
CDefined d = Nonterminal as CDefined;
if (!d.NonStart)
StartNonterminals.Add(name);
d.links = new List<CDefined>();
List<CSymbol> sequence = d.Sequence;
b = true;
int il = 0;
for (int i = 0; i < sequence.Count; i++)
if (b)
{
if (sequence[i] is CDefined)
d.AddLink(sequence[i] as CDefined); //Непредопределённый идентификатор
else if ((sequence[i] is CPredefined && !(sequence[i] as CPredefined).CanEmpty) || sequence[i] is CTerminal)
{
b = false; d.links.RemoveRange(il, d.links.Count - il
else if (sequence[i] is CMetaSymbol)
{
CMetaSymbol mt = sequence[i] as CMetaSymbol;
if (mt.type == EMetaType.eSeparator)
il = d.links.Count;
else
i = mt.iGoto;
}
}
else if (sequence[i] is CMetaSymbol)
{//Пропускаем всё до разделителя нижнего уровня
CMetaSymbol mt = sequence[i] as CMetaSymbol;
if (mt.type == EMetaType.eSeparator)
b = true;
else
i = mt.iGoto;
}
}
}
do
{//Удаление из списка связей непредопределённых нетерминалов без связей
b = false;
foreach (CNonterminal nt in Nonterminals.Values)
if (nt is CDefined)
b |= (nt as CDefined).RemoveLinks();
} while (b);
foreach (string name in Nonterminals.Keys)
{
Nonterminals.TryGetValue(name, out Nonterminal);
if (Nonterminal is CDefined && (Nonterminal as CDefined).links.Count > 0)
{
SemanticErrors.Add("Нетерминал '" + name + "' циклически определяется через себя.");
CDefined d = (Nonterminal as CDefined);
MarkIncorrectRule(d.it, d.ier);
}
}
if (StartNonterminals.Count == 0)
SemanticErrors.Add("Последовательность не содержит ни одного стартового символа");
else if (StartNonterminals.Count > 1)
{
string err = "Последовательность содержит следующие стартовые символы: <" + StartNonterminals[0];
for (int i = 1; i < StartNonterminals.Count; i++)
err += ">, <" + StartNonterminals[i];
err += ">";
for (int i = 0; i < StartNonterminals.Count; i++)
{
Nonterminals.TryGetValue(StartNonterminals[i], out Nonterminal);
MarkIncorrectRule(((CDefined)Nonterminal).it, ((CDefined)Nonterminal).ier);
}
SemanticErrors.Add(err);
}
else StartSymbol = StartNonterminals[0];
LanguageFault |= SemanticErrors.Count > 0;
}
//---------------------------------------Модель----------------------------------------//
internal bool CompileError;
internal List<CTextStructure> CompiledText;
private List<CTextStructure> WText;
private int iSW;
private class CCompileState
{
/// <summary>
internal CDefined Defined;
internal int ind;
internal List<int> GroupText;
/// Создаёт состояние для нетерминала
internal CCompileState(CDefined Defined, int iS)
{
this.Defined = Defined;
this.ind = 0;
GroupText = new List<int>();
GroupText.Add(iS);
}
/// Копирование группы
internal CCompileState(CCompileState src)
{
Defined = src.Defined;
ind = src.ind;
GroupText = new List<int>();
for (int i = 0; i < src.GroupText.Count; i++)
GroupText.Add(src.GroupText[i]);
}
}
/// Поиск
private bool WhenNoItem(List<CCompileState> states, ref CDefined Defined, ref List<CSymbol> Sequence, ref CCompileState CurrentState, ref int iS)
{
if (iS > iSW)
{
WText.Clear();
for (int i = 0; i < CompiledText.Count; i++)
WText.Add(CompiledText[i]);
iSW = iS;
}
while (states.Count > 0)
{
for (CurrentState.ind++; CurrentState.ind < Sequence.Count; CurrentState.ind++)
if (Sequence[CurrentState.ind] is CMetaSymbol)
{
CMetaSymbol MetaSymbol = Sequence[CurrentState.ind] as CMetaSymbol;
switch (MetaSymbol.type)
{
case EMetaType.eStartRepeator:
case EMetaType.eStartOption: CurrentState.ind = (Sequence[CurrentState.ind] as CMetaSymbol).iGoto;
break;
case EMetaType.eSeparator:
CurrentState.ind++;
iS = CurrentState.GroupText[CurrentState.GroupText.Count - 1];
int i = CompiledText.Count;
while (i > 0 && CompiledText[i - 1].ind >= iS)
i--;
CompiledText.RemoveRange(i, CompiledText.Count - i);
return false;
default:
CurrentState.ind++;
iS = CurrentState.GroupText[CurrentState.GroupText.Count - 1];
CurrentState.GroupText.RemoveAt(CurrentState.GroupText.Count - 1);
return false;
}
}
else if (states.Count == 1 && CurrentState.GroupText.Count == 1 && !((Sequence[CurrentState.ind] is CPredefined)
&& (Sequence[CurrentState.ind] as CPredefined).CanEmpty))
{
if (iSW > iS)
{
iS = iSW;
CompiledText = WText;
}
return true;
}
states.RemoveAt(states.Count - 1);
if (states.Count == 0)
return true;
CurrentState = states[states.Count - 1];
Defined = CurrentState.Defined;
Sequence = Defined.Sequence;
}
return false;
}
/// Обозначить строку с ошибкой
private void SetProgramError(string s, int iS)
{
CompileError = true;
if (iSW > iS)
{
iS = iSW;
CompiledText = WText;
}
int iSL = iS; //Начало строки с ошибкой
while (iSL > 0 && s[iSL - 1] != '\r' && s[iSL - 1] != '\n')
iSL--;
while (CompiledText.Count > 0 && CompiledText[CompiledText.Count - 1].ind >= iSL)
CompiledText.RemoveAt(CompiledText.Count - 1);
CompiledText.Add(new CTextStructure(iSL, ETextPiece.incorrect));
int iSF = iS; //Конец строки с ошибкой
while (iSF < s.Length && ((s[iSF] != '\r' && s[iSF] != '\n') || iSF == iSL))
iSF++;
CompiledText.Add(new CTextStructure(iSF, ETextPiece.terminal)); //Вернуться к чёрному цвету
}
/// Добавить маркер в разметку текста
private void AddMarker(int iS, ETextPiece type)
{
if (CompiledText.Count > 0 && CompiledText[CompiledText.Count - 1].ind == iS)
{
CompiledText[CompiledText.Count - 1].type = type;
if (CompiledText.Count > 1 && CompiledText[CompiledText.Count - 2].type == type)
CompiledText.RemoveAt(CompiledText.Count - 1);
}
else if (CompiledText.Count == 0 || CompiledText[CompiledText.Count - 1].type == type)
return;
CompiledText.Add(new CTextStructure(iS, type));
}
/// Анализ модели
internal List<string> Compile(string s, int iCaret)
{
CompiledText = new List<CTextStructure>();
CompiledText.Add(new CTextStructure(0, ETextPiece.terminal));
if (LanguageFault)
{
CompileError = true;
return null;
}
MakeMenu(); //Меню для нетерминалов
WText = new List<CTextStructure>();
iSW = -1;
List<string> ret = null;
CompileError = false;
int iS = 0;
List<CCompileState> states = new List<CCompileState>(256); //Список вложенных состояний компиляции
CDefined CurrentNonterminal = Nonterminals[StartSymbol] as CDefined; //Текущий нетерминал
List<CSymbol> Sequence = CurrentNonterminal.Sequence; //Текущая последовательность
CCompileState CurrentState = new CCompileState(CurrentNonterminal, 0);
states.Add(CurrentState);
while (iS < s.Length)
{
while (states.Count != 0)
{
if (CurrentState.ind < Sequence.Count)
{
if (iS == iCaret && CurrentNonterminal.menus[CurrentState.ind] != null)
ret = CurrentNonterminal.menus[CurrentState.ind];
CSymbol CurrentSymbol = Sequence[CurrentState.ind];
if (CurrentSymbol is CTerminal)
{//Проверка наличия терминала в тексте
string st = (CurrentSymbol as CTerminal).Symbol;
bool CaretHere = iS == iCaret; //Каретка установлена на данном символе
int iT = 0;
int iSc = iS;
while (iT < st.Length && iSc < s.Length && st[iT] == s[iSc])
{
iT++;
iSc++;
}
if (iT >= st.Length)
{//Терминал присутствует в тексте
AddMarker(iS, ETextPiece.extention); //Выделение терминала синим цветом
CurrentState.ind++;
iS = iSc;
}
else
{
if (WhenNoItem(states, ref CurrentNonterminal, ref Sequence, ref CurrentState, ref iS))
{
SetProgramError(s, iS);
return ret;
}
}
}
else if (CurrentSymbol is CDefined)
{
CurrentNonterminal = CurrentSymbol as CDefined;
CurrentState = new CCompileState(CurrentNonterminal, iS);
states.Add(CurrentState);
if (states.Count > 512)
{
SetProgramError(s, iS);
return ret;
}
Sequence = CurrentNonterminal.Sequence;
}
else if (CurrentSymbol is CPredefined)
{
switch ((CurrentSymbol as CPredefined).type)
{
case EPredefined.eSpace: while (iS < s.Length && (uint)s[iS] <= 0x20)
{
if (iS == iCaret && CurrentState.ind < Sequence.Count && CurrentNonterminal.menus[CurrentState.ind] != null)
ret = CurrentNonterminal.menus[CurrentState.ind];
iS++;
}
CurrentState.ind++;
break;
case EPredefined.eDigit:
if (iS < s.Length && char.IsDigit(s[iS]))
{
AddMarker(iS, ETextPiece.terminal);
iS++;
CurrentState.ind++;
}
else if (WhenNoItem(states, ref CurrentNonterminal, ref Sequence, ref CurrentState, ref iS))
{
SetProgramError(s, iS);
return ret;
}
break;
case EPredefined.eLetter:
if (iS < s.Length && char.IsLetter(s[iS]))
{
AddMarker(iS, ETextPiece.terminal); iS++;
CurrentState.ind++;
}
else if (WhenNoItem(states, ref CurrentNonterminal, ref Sequence, ref CurrentState, ref iS))
{
SetProgramError(s, iS);
return ret;
}
break;
default:
if (iS < s.Length && char.IsLetter(s[iS]))
{
AddMarker(iS, ETextPiece.terminal);
iS++;
while (iS < s.Length && (((ushort)s[iS] > 0x20 && (ushort)s[iS] < 0x7F)
|| ((ushort)s[iS] >= 0x410 && (ushort)s[iS] < 0x450 || s[iS] == 'Ё' || s[iS] == 'ё')))
iS++;
CurrentState.ind++;
}
else if (WhenNoItem(states, ref CurrentNonterminal, ref Sequence, ref CurrentState, ref iS))
{
SetProgramError(s, iS);
return ret;
}
break;
}
}
else switch ((CurrentSymbol as CMetaSymbol).type)
{//Метасимвол
case EMetaType.eEndOption:
CurrentState.ind++;
CurrentState.GroupText.RemoveAt(CurrentState.GroupText.Count - 1);
break;
case EMetaType.eStartOption:
++CurrentState.ind;
CurrentState.GroupText.Add(iS);
break;
case EMetaType.eStartRepeator:
++CurrentState.ind;
CurrentState.GroupText.Add(iS);
break;
case EMetaType.eEndRepeator:
if (iS > CurrentState.GroupText[CurrentState.GroupText.Count - 1])
{
CurrentState.GroupText[CurrentState.GroupText.Count - 1] = iS;
CurrentState.ind = (CurrentSymbol as CMetaSymbol).iGoto;
}
else
{
CurrentState.ind++;
CurrentState.GroupText.RemoveAt(CurrentState.GroupText.Count - 1);
}
break;
default:
if (iS > CurrentState.GroupText[CurrentState.GroupText.Count - 1])
{//Найден элемент в группе. Зафиксируем продвижение.
CurrentState.GroupText[CurrentState.GroupText.Count - 1] = iS;
CurrentState.ind = (CurrentSymbol as CMetaSymbol).iGoto;
}
else CurrentState.ind++;
break;
}
}
else if (states.Count > 0)
{
states.RemoveAt(states.Count - 1);
if (states.Count > 0)
{
CurrentState = states[states.Count - 1];
CurrentState.ind++;
CurrentNonterminal = CurrentState.Defined;
Sequence = CurrentNonterminal.Sequence;
}
}
}
if (iS < s.Length)
{//Обнаружена ошибка
SetProgramError(s, iS);
return ret;
}
}
if (s.Length == 0 && ret == null)
ret = CurrentNonterminal.menus[0];
if (!CompileError && states.Count > 0)
SetProgramError(s, iS);
return ret;
}
static void Main()
{
string text = File.ReadAllText("json.language", Encoding.Default);
CSentence sentence = new CSentence(text);
string CompiledText = File.ReadAllText("options.json", Encoding.Default);
sentence.Compile(CompiledText, 0);
CompiledText = File.ReadAllText("errors.json", Encoding.Default);
sentence.Compile(CompiledText, 0);
text = File.ReadAllText("pascal_minus.language", Encoding.Default);
sentence = new CSentence(text);
CompiledText = File.ReadAllText("test.pascal_minus", Encoding.Default);
sentence.Compile(CompiledText, 0);
text = File.ReadAllText("Errors1.language", Encoding.Default);
sentence = new CSentence(text);
text = File.ReadAllText("Errors2.language", Encoding.Default);
sentence = new CSentence(text);
text = File.ReadAllText("Errors3.language", Encoding.Default);
sentence = new CSentence(text);
...Подобные документы
Разработка текстового редактора с подсветкой синтаксиса языков программирования. Загрузка из XML-файла настроек для подсветки синтаксиса и конструкций языка. Формат файлов конфигурации и проверки. Разбор текста и применение к нему стилей, тестовый пример.
курсовая работа [141,6 K], добавлен 13.03.2013Формат файла конфигурации, содержащего данные для подсветки синтаксиса. Его проверка при помощи XML Schema. Реализация функций для чтения данных подсветки и по загрузке таблицы стилей, ключевых слов и типов. Разбор текста и применение к нему стилей.
курсовая работа [122,3 K], добавлен 30.05.2015Разработка программного приложения, производящего проверку синтаксиса простой программы: выбор метода создания синтаксического анализатора, описание требований к программному обеспечению, написание алгоритмов решения и тестирование конечного продукта.
курсовая работа [579,7 K], добавлен 03.07.2011Краткая характеристика предметно-ориентированных языков, различия между "внутренними" и "внешними" DSL. Особенности работы транслятора (компилятора). Листинг программы для разработки простейшего калькулятора с использованием программной среды Java.
лабораторная работа [57,8 K], добавлен 31.03.2017Применение правил грамматики. Синтаксический анализатор, нис- и восходящий разбор, полный перебор правил подстановки. Классификация грамматик по Хомскому. Определение языков с помощью автоматов. Форма Бекуса-Наура описания синтаксиса формальных языков.
лекция [270,1 K], добавлен 19.10.2014Разработка алгоритма как конструктивный компонент программирования, не зависящий от особенностей синтаксиса языков программирования и специфики функционирования конкретных ЭВМ. Алгоритм - операциональный подход к программированию. Экономичность алгоритма.
учебное пособие [346,8 K], добавлен 09.02.2009Обзор разнообразных методов теории линейных систем: методов корреляционного и регрессионного анализа, косинор-анализа. Особенности применения факторного анализа. Программная реализация метода главных компонент. Разработка нелинейных регрессионных моделей.
дипломная работа [390,2 K], добавлен 03.09.2016История разработки языка программирования Си. Программа на Си как одна или несколько единиц компиляции (файлов), стадии работы компилятора. Идентификаторы и ключевые слова, типы констант. Форма Бекуса-Наура описания синтаксиса формальных языков.
презентация [257,7 K], добавлен 05.01.2014Характеристики и свойства языков программирования. Исследование эволюции объектно-ориентированных языков программирования. Построение эволюционной карты механизмов ООП. Разработка концептуальной модели функционирования пользовательского интерфейса.
курсовая работа [2,6 M], добавлен 17.11.2014Классификация текстовых редакторов и процессоров. Способы хранения текста в файле. Форматирование документа и его редактирование. Среда текстового редактора. Автоматическая проверка орфографии и синтаксиса текста, автотекст, автозамена, гипертекст.
курсовая работа [35,0 K], добавлен 25.04.2013Ознакомление с ситуацией распространения на рынке языков программирования. Определение плюсов и минусов Pascal, C++, VBA. Сравнение и анализ синтаксиса программ на основе одной задачи. Выявление лучшего языка для освоения первоначальных навыков.
курсовая работа [1022,0 K], добавлен 13.10.2014Классификация и возможности текстовых редакторов. Среда текстового редактора Microsoft Word 2003. Процесс редактирования текста, его копирование и перемещение. Проверка орфографии и синтаксиса, автотекст и автозамена. Пример гипертекстового документа.
курсовая работа [2,4 M], добавлен 25.04.2013Классификация и возможности текстовых редакторов, их основные элементы: рабочее поле, курсор, строка состояния и меню, полосы прокрутки, панель инструментов. Форматирование текста, проверка орфографии и синтаксиса. Создание гипертекстового документа.
курсовая работа [3,6 M], добавлен 27.04.2013Обзор средств разработки и технологий: особенности языка программирования Visual Basic и подсистемы WIN32 API. Методы, приемы решения задачи автоматического размещения текстовых надписей на рисунке. Механизм создания полигонального объекта. Код программы.
курсовая работа [231,0 K], добавлен 28.08.2012Основные методы описания синтаксиса языков программирования: формальные грамматики, формы Бэкуса-Наура и диаграммы Вирта. Разработка алгоритма решения задачи. Лексический и синтаксический анализатор, семантический анализ. Структурная организация данных.
курсовая работа [680,1 K], добавлен 12.06.2011Описание синтаксиса и семантики входного языка. Описание типов лексем, определение их синтаксиса. Построение диаграммы лексического анализатора, а также его таблицы, тестирование. Построение КС-грамматики входного языка. Описание промежуточного языка.
курсовая работа [83,0 K], добавлен 23.01.2014Функциональные характеристики программы форматирования текстовых файлов, требования к ее интерфейсу и данным. Схема взаимодействия компонентов системы, выбор среды исполнения и программная реализация алгоритмов. Тестирование и оценка качества программы.
курсовая работа [61,1 K], добавлен 25.07.2012Разработка интерфейса программы, обеспечивающего доступ ко всем возможностям среды структурно-визуального программирования. Реализация инструментальных средств, позволяющих связывать компоненты в единое приложение. Создание иерархии классов представления.
дипломная работа [2,3 M], добавлен 11.04.2012Разработка алгоритмов и программных средств поддержки взаимодействия компетентностно-ориентированных моделей в обучающих ИЭС (АТ-ТЕХНОЛОГИЯ). Анализ функциональных возможностей базовой версии компонента выявления текущего уровня компетенций обучаемого.
отчет по практике [1,6 M], добавлен 28.04.2015Характеристика средств обработки текстовой информации, способы редактирования и форматирования документов. Порядок создания списков и таблиц, проверка орфографии и синтаксиса текста. Выбор формата файла. Работа в табличном процессоре Microsoft Excel.
курсовая работа [411,1 K], добавлен 27.04.2013