// 1С:Предприятие 8.3.13 ПарсерВстроенногоЯзыка = ВнешниеОбработки.Создать(ПарсерВстроенногоЯзыкаПуть, Ложь); Плагины = Новый Массив; Плагины.Добавить(ВнешниеОбработки.Создать(ПлагинПуть1, Ложь)); Плагины.Добавить(ВнешниеОбработки.Создать(ПлагинПуть2, Ложь)); ПарсерВстроенногоЯзыка.Пуск(Исходник.ПолучитьТекст(), Плагины); Отчет = Новый Массив; Для Каждого Ошибка Из Парсер.ТаблицаОшибок() Цикл Отчет.Добавить(Ошибка.Текст); Отчет.Добавить(СтрШаблон(" [стр: %1; кол: %2]", Ошибка.НомерСтрокиНачала, Ошибка.НомерКолонкиНачала)); Отчет.Добавить(Символы.ПС); КонецЦикла; Сообщить(СтрСоединить(Отчет)); // OneScript ПодключитьСценарий("..\..\src\ПарсерВстроенногоЯзыка\Ext\ObjectМодуль.bsl", "ПарсерВстроенногоЯзыка"); ПодключитьСценарий("..\plugins\ДетекторНеиспользуемыхПеременных\src\ДетекторНеиспользуемыхПеременных\Ext\ObjectМодуль.bsl", "ДетекторНеиспользуемыхПеременных"); ЧтениеТекста = Новый ЧтениеТекста("..\src\ПарсерВстроенногоЯзыка\Ext\ObjectМодуль.bsl"); Исходник = ЧтениеТекста.Прочитать(); Парсер = Новый ПарсерВстроенногоЯзыка; Плагин = Новый ДетекторНеиспользуемыхПеременных; Парсер.Пуск(Исходник, Плагин); Отчет = Новый Массив; Для Каждого Ошибка Из Парсер.ТаблицаОшибок() Цикл Отчет.Добавить(Ошибка.Текст); Отчет.Добавить(СтрШаблон(" [стр: %1; кол: %2]", Ошибка.НомерСтрокиНачала, Ошибка.НомерКолонкиНачала)); Отчет.Добавить(Символы.ПС); КонецЦикла; Сообщить(СтрСоединить(Отчет));
Перем Результат; // Будет вызвана один раз перед обходом AST. // Тут можно получить необходимые перечисления и таблицы из парсера, // и выполнить инициализацию плагина с учетом полученных параметров. Процедура Открыть(Парсер, Параметры) Экспорт Результат = Новый Массив; КонецПроцедуры // Будет вызвана после полного обхода AST. // Возвращает текстовый результат работы плагина, если он есть. // Плагины, которые регистрируют ошибки и/или замены, могут вернуть Неопределено. Функция Закрыть() Экспорт Возврат СтрСоединить(Результат); КонецФункции // Возвращает список процедур-подписок, которые будут вызываться визитером. // Состав возможных подписок можно посмотреть в исходнике парсера в функции Подписки(). // Имена большинства подписок образуются добавлением префикса Посетить/Покинуть к имени типа узла. // Справка по типам узлов находится по этому адресу: https://lead-tools.github.io/bsparser/ Функция Подписки() Экспорт Перем Подписки; Подписки = Новый Массив; Подписки.Добавить("ПосетитьОператорПрисваивания"); Подписки.Добавить("ПокинутьОператорПрисваивания"); Возврат Подписки; КонецФункции #Область РеализацияПодписок // Описание структуры узла `ОператорПрисваивания`: https://lead-tools.github.io/bsparser/#ОператорПрисваивания // Данная процедура будет вызвана при посещении узла AST перед посещением подчиненных ему узлов. // Вызов подписок с префиксом `Посетить` отражает рекурсивный спуск визитера по AST. // Сначала вызывается подписка на родительский узел, потом на этот, потом на подчиненный и так далее. Процедура ПосетитьОператорПрисваивания(ОператорПрисваивания) Экспорт // ... КонецПроцедуры // Данная процедура будет вызвана при посещении узла AST после посещения подчиненных ему узлов. // Вызов подписок с префиксом `Покинуть` отражает рекурсивный подъем визитера по AST. // Сначала вызывается подписка на подчиненный узел, потом на этот, потом на родительский и так далее. Процедура ПокинутьОператорПрисваивания(ОператорПрисваивания) Экспорт // ... КонецПроцедуры #КонецОбласти
Перем Типы; Перем Токены; Перем Исходник; Перем ТаблицаТокенов; Перем ТаблицаОшибок; Перем ТаблицаЗамен; Перем Стек; Перем Счетчики; Перем Директивы; Перем Аннотации; Перем СимволыПрепроцессора; Перем Результат; Процедура Открыть(Парсер, Параметры) Экспорт Типы = Парсер.Типы(); Токены = Парсер.Токены(); Исходник = Парсер.Исходник(); ТаблицаТокенов = Парсер.ТаблицаТокенов(); ТаблицаОшибок = Парсер.ТаблицаОшибок(); ТаблицаЗамен = Парсер.ТаблицаЗамен(); Стек = Парсер.Стек(); Счетчики = Парсер.Счетчики(); Директивы = Парсер.Директивы(); Аннотации = Парсер.Аннотации(); СимволыПрепроцессора = Парсер.СимволыПрепроцессора(); Результат = Новый Массив; КонецПроцедуры Функция Закрыть() Экспорт // ... Возврат СтрСоединить(Результат); КонецФункции Функция Подписки() Экспорт Перем Подписки; Подписки = Новый Массив; Подписки.Добавить("ПосетитьОператорПрисваивания"); //Подписки.Добавить("ПокинутьОператорПрисваивания"); Возврат Подписки; КонецФункции #Область РеализацияПодписок Процедура ПосетитьОператорПрисваивания(ОператорПрисваивания) Экспорт Ошибка("Ошибка в операторе присваивания", ОператорПрисваивания.Начало, ОператорПрисваивания.Конец); КонецПроцедуры // ПосетитьОператорПрисваивания() //Процедура ПокинутьОператорПрисваивания(ОператорПрисваивания) Экспорт // //КонецПроцедуры // ПокинутьОператорПрисваивания() #КонецОбласти Процедура Ошибка(Текст, Начало, Конец = Неопределено, ЕстьЗамена = Ложь) Ошибка = ТаблицаОшибок.Добавить(); Ошибка.Источник = "ИмяЭтогоПлагина"; Ошибка.Текст = Текст; Ошибка.ПозицияНачала = Начало.Позиция; Ошибка.НомерСтрокиНачала = Начало.НомерСтроки; Ошибка.НомерКолонкиНачала = Начало.НомерКолонки; Если Конец = Неопределено Или Конец = Начало Тогда Ошибка.ПозицияКонца = Начало.Позиция + Начало.Длина; Ошибка.НомерСтрокиКонца = Начало.НомерСтроки; Ошибка.НомерКолонкиКонца = Начало.НомерКолонки + Начало.Длина; Иначе Ошибка.ПозицияКонца = Конец.Позиция + Конец.Длина; Ошибка.НомерСтрокиКонца = Конец.НомерСтроки; Ошибка.НомерКолонкиКонца = Конец.НомерКолонки + Конец.Длина; КонецЕсли; Ошибка.ЕстьЗамена = ЕстьЗамена; КонецПроцедуры Процедура Замена(Текст, Начало, Конец = Неопределено) НоваяЗамена = ТаблицаЗамен.Добавить(); НоваяЗамена.Источник = "ИмяЭтогоПлагина"; НоваяЗамена.Текст = Текст; НоваяЗамена.Позиция = Начало.Позиция; Если Конец = Неопределено Тогда НоваяЗамена.Длина = Начало.Длина; Иначе НоваяЗамена.Длина = Конец.Позиция + Конец.Длина - Начало.Позиция; КонецЕсли; КонецПроцедуры Процедура Вставка(Текст, Позиция) НоваяЗамена = ТаблицаЗамен.Добавить(); НоваяЗамена.Источник = "ИмяЭтогоПлагина"; НоваяЗамена.Текст = Текст; НоваяЗамена.Позиция = Позиция; НоваяЗамена.Длина = 0; КонецПроцедуры
Таблица значений, которая хранит подробную информацию о всех токенах.
Каждый узел AST имеет поля Начало и Конец, которые содержат строки из этой таблицы.
С помощью обращения к таблице по индексу можно получить доступ к любому токену.
Комментарии при необходимости тоже извлекаются по данным этой таблицы.
Таблицу можно получить вызовом Парсер.ТаблицаТокенов()
Таблица значений, которая хранит ошибки собранные парсером и плагинами.
Плагины могут получить таблицу в методе Открыть() и регистрировать в ней ошибки в процессе своей работы.
Таблицу можно получить вызовом Парсер.ТаблицаОшибок()
Обязательны к заполнению только первые 4 поля. Поле Код плагины не должны заполнять.
Если плагин регистрирует ошибку и замену ее исправляющую, то желательно установить ЕстьЗамена = Истина
Таблица значений, которая хранит замены, регистрируемые плагинами.
Замена - это операция, аналогичная выделению участка текста и вставки фрагмента из буфера обмена.
Позиция и Длина указывают что выделить, а Текст - это вставляемый фрагмент.
Плагины могут получить таблицу в методе Открыть() и регистрировать в ней замены фрагментов исходника.
Фактические операции замены по таблице могут быть выполнены вызовом Парсер.ВыполнитьЗамены()
Таблицу можно получить вызовом Парсер.ТаблицаЗамен()
Корень AST. Узел хранит информацию о модуле в целом.
Узел хранит информацию об объекте области видимости.
Поле Объявление хранит объявление данного объекта (неопределено = объявление не обнаружено).
Хранит информацию об объявлении директивы.
Пример:
&НаКлиенте
Хранит информацию об объявлении аннотации.
Пример:
&Перед("ЗаполнитьТовары")
Хранит информацию об инструкции объявления переменных уровня модуля.
Пример:
&НаКлиенте // поле "Директивы" Перем П1 Экспорт, П2; // поле "Объявления"
Хранит информацию об объявлении переменной уровня модуля.
Пример:
Объявления переменных заключены в скобки {...}
&НаКлиенте Перем {П1 Экспорт}, {П2};
Хранит информацию об инструкции объявления переменных уровня метода.
Пример:
Перем П1, П2; // поле "Объявления"
Хранит информацию об объявлении локальной переменной.
Пример:
Объявления переменных заключены в скобки {...}
Перем {П1}, {П2};
Хранит информацию об объявлении авто-переменной.
Пример:
Объявления переменных заключены в скобки {...}
{Макс} = 0; Для {Индекс} = 0 По Массив.ВГраница() Цикл {Структура} = Массив[Индекс]; Для Каждого {Элемент} Из Структура Цикл Если Макс < Элемент.Значение Тогда Макс = Элемент.Значение; КонецЕсли; КонецЦикла; КонецЦикла
Хранит информацию об объявлении параметра.
Пример:
Объявления параметров заключены в скобки {...}
Процедура Тест({П1}, {Знач П2 = Неопределено})
Хранит информацию об объявлении метода.
Сигнатура метода хранится в поле Сигнатура.
Пример:
&НаКлиенте Функция Тест() Экспорт Перем П1, П2; // поле "Объявления" хранит объявления списков переменных. // каждый элемент объявления (например П2) добавляется в поле "Переменные". П1 = 2; // операторы собираются в поле Операторы П3 = П1 + 2; // Авто-переменные (П2) добавляются в поле "Переменные". КонецФункции
Хранит информацию о сигнатуре объявления процедуры.
Пример:
&НаКлиенте Процедура Тест(П1, П2) Экспорт
Хранит информацию о сигнатуре объявления функции.
Пример:
&НаКлиенте Функция Тест(П1, П2) Экспорт
Хранит информацию о глобальном объекте.
Хранит информацию о глобальном методе.
Хранит информацию о литерале примитивного типа.
Хранит информацию об обращении к полю объекта через точку.
В поле Имя содержится имя поля.
В поле Аргументы содержатся аргументы вызова (если это вызов).
Пример:
// обращения через точку заключены в скобки {...} Значение = Объект{.Поле} Значение = Объект{.Добавить(П1, П2)}
Хранит информацию об обращении к элементу объекта по индексу.
Пример:
// обращение по индексу заключено в скобки {...} Значение = Объект{[Ключ]}
Хранит информацию об обращении к идентификатору.
В поле Голова содержится объект области видимости соответствующий идентификатору.
В поле Хвост содержится последовательность обращений через точку и по индексу.
В поле Аргументы содержатся аргументы вызова (если это вызов).
Пример:
// идентификатор заключен в скобки {...} // поле "Голова" будет содержать объект переменной "Запрос"; // поле "Хвост" будет содержать три обращения; // поле "Аргументы" будет равно Неопределено, т.к. обращение к "Запрос" не является вызовом. Возврат {Запрос.Выполнить().Выгрузить()[0]};
Хранит унарное выражение.
Пример:
// унарные выражения заключены в скобки {...} // поле "Операция.Токен" равно либо Токены.ЗнакСложения, либо Токены.ЗнакВычитания // поле "Операнд" хранит операнд-выражение Значение = {-Сумма} * 2; Значение = {+Сумма}; Значение = {-(Сумма1 + Сумма2)} / 2;
Хранит бинарное выражение.
Пример:
// бинарные выражения заключены в скобки {...} // поле "Операция.Токен" равно одному из допустимых операторов: // - логических (кроме "Не") // - реляционных // - арифметических // поля "ЛевыйОперанд" и "ПравыйОперанд" содержат операнды-выражения Если {Не Отмена И Продолжить} Тогда Значение = {Сумма1 + {Сумма2 * Коэффициент}}; КонецЕсли;
Хранит выражение "Новый".
Для совместимости с OneScript поддерживается
обращение к конструктору через точку (поле Хвост)
Пример:
// выражения "Новый" заключены в скобки {...} // в этом варианте поле "Имя" хранит имя типа "Массив", // а поле "Аргументы" хранит массив из одного выражения Параметры = {Новый Массив(1)}; Параметры[0] = 10; // в этом варианте поле "Имя" равно Неопределено, // а поле "Аргументы" хранит массив из двух выражений Массив = {Новый (Тип("Массив"), Параметры)};Инвариант: если (ВыражениеНовый.Имя = Неопределено) то (0 < ВыражениеНовый.Аргументы.Количество() <= 2)
Хранит тернарное выражение "?(,,)".
Пример:
Значение = ?(Ложь, // поле "Выражение" Неопределено, // поле "Тогда" Новый Массив // поле "Иначе" ).Количество(); // поле "Хвост"
Хранит скобочное выражение.
Пример:
// скобочное выражение заключено в скобки {...} Сумма = {(Сумма1 + Сумма2)} * Количество;
Хранит выражение, к которому применено логическое отрицание "Не".
Пример:
// выражение-отрицание заключено в скобки {...} НеРавны = {Не Сумма1 = Сумма2};
Хранит строковое выражение.
Поле "Элементы" хранит упорядоченный список частей строки.
Пример:
Строка1 = "Часть1" "Часть2"; // эта строка состоит из двух частей типа Типы.Строка Строка2 = // эта строка состоит из пяти частей типа: "Начало строки // Типы.НачалоСтроки | продолжение строки // Типы.ПродолжениеСтроки | еще продолжение строки // Типы.ПродолжениеСтроки | окончание строки" // Типы.ОкончаниеСтроки "еще часть"; // Типы.Строка
Хранит оператор присваивания.
Хранит оператор "Возврат".
Поле "Выражение" равно Неопределено если это возврат из процедуры.
Хранит оператор "Прервать".
Хранит оператор "Продолжить".
Хранит оператор "ВызватьИсключение".
Поле "Выражение" равно Неопределено если это вариант оператора без выражения.
Хранит оператор "Выполнить".
Хранит вызов процедуры или функции как процедуры.
Хранит оператор "Если".
Пример:
Если Сумма > 0 Тогда // поле "Выражение" хранит условие (выражение) // поле "Тогда" хранит операторы в этом блоке ИначеЕсли Сумма = 0 Тогда // поле-массив "ИначеЕсли" хранит последовательность блоков ИначеЕсли Иначе // поле "Иначе" хранит операторы в этом блоке КонецЕслиПоля "ИначеЕсли" и "Иначе" равны Неопределено если
Хранит блок "Иначе"
Хранит блок "ИначеЕсли" оператора "Если".
Пример:
... ИначеЕсли Сумма < 0 Тогда // поле "Выражение" хранит условие (выражение) // поле "Тогда" хранит операторы в этом блоке ...
Хранит оператор цикла "Пока".
Пример:
Пока Индекс > 0 Цикл // поле "Выражение" хранит условие (выражение) // поле "Операторы" хранит операторы в этом блоке КонецЦикла
Хранит оператор цикла "Для".
Пример:
Для Индекс = 0 // поля "Идентификатор" и "Старт" хранят переменную и выражение инициализации. По Длина - 1 Цикл // поле "Финиш" хранит выражение границы // поле "Операторы" хранит операторы в этом блоке КонецЦикла
Хранит оператор цикла "Для Каждого".
Пример:
Для Каждого Элемент // поле "Идентификатор" хранит переменную. Из Список Цикл // поле "Коллекция" хранит выражение коллекции. // поле "Операторы" хранит операторы в этом блоке КонецЦикла
Хранит оператор "Попытка"
Пример:
Попытка // поле "Попытка" хранит операторы в этом блоке. Исключение // поле "Исключение" хранит операторы в этом блоке КонецПопытки
Хранит блок "Исключение"
Хранит оператор "Перейти"
Хранит оператор метки.
Хранит оператор "ДобавитьОбработчик".
Хранит оператор "УдалитьОбработчик".
Хранит информацию об инструкции препроцессора #Если,
Пример:
... #Если Сервер Тогда // поле "Выражение" хранит условие (выражение) ...
Хранит информацию об инструкции препроцессора #ИначеЕсли
Пример:
... #ИначеЕсли Клиент Тогда // поле "Выражение" хранит условие (выражение) ...
Хранит информацию об инструкции препроцессора #Иначе
Хранит информацию об инструкции препроцессора #КонецЕсли
Хранит информацию об инструкции препроцессора #Обрасть,
Пример:
... #Область Интерфейс // поле "Имя" хранит имя области ...
Хранит информацию об инструкции препроцессора #КонецОбласти,
Пример:
... #КонецОбласти ...
Хранит информацию об инструкции препроцессора #Вставка,
Пример:
... #Вставка ...
Хранит информацию об инструкции препроцессора #КонецВставки,
Пример:
... #КонецВставки ...
Хранит информацию об инструкции препроцессора #Удаление,
Пример:
... #Удаление ...
Хранит информацию об инструкции препроцессора #КонецУдаления,
Пример:
... #КонецУдаления ...
Хранит информацию об инструкции препроцессора #Использовать,
Пример:
... #Использовать osparser ...
Хранит бинарное выражение препроцессора.
Пример:
// бинарные выражения заключены в скобки {...} // поле "Операция.Токен" равно либо Токены.Или либо Токены.И: // поля "ЛевыйОперанд" и "ПравыйОперанд" содержат операнды-выражения препроцессора #Если {Сервер Или ВнешнееСоединение} Тогда ...
Хранит выражение препроцессора, к которому применено логическое отрицание "Не".
Пример:
// выражение-отрицание заключено в скобки {...} #Если {Не ВебКлиент} Тогда ...
Узел хранит информацию о символе препроцессора.
Поле Существует = Истина если такой символ существует.
Пример:
// символ заключен в скобки {...} #Если {Сервер} Тогда
Хранит скобочное выражение препроцессора.
Пример:
// скобочное выражение заключено в скобки {...} #Если {(Сервер Или ВнешнееСоединение)} Тогда