При разработке и кастомизации печатных форм в среде 1С:Предприятие разработчики часто используют готовые механизмы БСП (Библиотеки стандартных подсистем), заимствуя фрагменты кода из типовых конфигураций (например, из 1С:Бухгалтерии). Однако механический перенос кода без понимания его структуры и синтаксиса платформы часто приводит к досадным ошибкам компиляции. В этой статье мы подробно разберем, почему возникает популярная ошибка «Ожидается выражение», как компилятор 1С реагирует на некорректный синтаксис и какие скрытые проблемы могут помешать работе печатной формы в дальнейшем.
Рассмотрим исходную ситуацию. При попытке сохранить модуль менеджера справочника система выдает следующие сообщения об ошибках:
{Справочник.ПроизводственныйКалендарь.МодульМенеджера(33,9)}: Ожидается выражение
Если<<?>> Перем ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Печать") Тогда
{Справочник.ПроизводственныйКалендарь.МодульМенеджера(41,2)}: Ожидается ключевое слово 'КонецПроцедуры' ('EndProcedure')
<<?>>КонецЕсли;
Проанализируем первую ошибку. Компилятор указывает на строку с логическим условием Если, внутри которого расположено ключевое слово Перем. Выясним причину такого поведения системы. В языке программирования 1С ключевое слово Перем предназначено исключительно для объявления переменных. Оно может использоваться только в двух местах модуля:
Использование оператора Перем внутри логических конструкций (таких как Если...Тогда, Пока...Цикл) или в правой части оператора присваивания является грубым нарушением синтаксиса. Платформа ожидает увидеть в условии логическое выражение или функцию, возвращающую булево значение (Истина/Ложь), а вместо этого встречает директиву объявления переменных. Именно поэтому система выдает ошибку «Ожидается выражение».
Разберем природу второй ошибки. Начинающих разработчиков часто сбивает с толку то, что компилятор ругается на вполне законное ключевое слово КонецЕсли и требует закрыть процедуру. Это классический пример каскадной ошибки парсера.
Когда синтаксический анализатор платформы встречает некорректную конструкцию Если Перем ... Тогда, он не может правильно распознать начало условного блока. Для парсера структура ветвления оказывается «сломанной». Анализатор аварийно прекращает разбор условного оператора, «теряет» контекст и считает, что тело процедуры завершилось некорректно. Дойдя до строки КонецЕсли;, он не находит для него парного открывающего оператора Если и предполагает, что разработчик просто забыл закрыть саму процедуру (КонецПроцедуры).
Решение здесь простое: как только мы исправим первопричину (удалим слово Перем из условия), синтаксическое дерево построится корректно, и вторая ошибка пропадет сама собой.
Даже если мы уберем синтаксическую ошибку, код может содержать скрытые логические дефекты, которые проявятся только в процессе работы (в рантайме). Проанализируем строку вызова макета:
"Справочник.ПроизводственныеКалендари.ПФ_MXL_ПроизводственныйКалендарь"
Обратите внимание на имя справочника в этой строке — используется множественное число ПроизводственныеКалендари. В то же время заголовок ошибки компилятора четко указывает, что наш код пишется в:
Справочник.ПроизводственныйКалендарь.МодульМенеджера
Здесь справочник назван в единственном числе. В типовых конфигурациях 1С (таких как ERP, ЗУП или Комплексная автоматизация) этот справочник действительно называется во множественном числе — ПроизводственныеКалендари. Однако в вашей кастомной или сильно измененной конфигурации он может быть заведен в единственном числе. Если это так, то при попытке сформировать печатную форму система выдаст ошибку выполнения: «Объект метаданных не найден» или «Макет не найден».
Путь к макету при вызове метода ВывестиТабличныйДокументВКоллекцию должен строго соответствовать реальному имени объекта в дереве метаданных конфигуратора.
Посмотрим на вызов вспомогательной функции, которая генерирует сам табличный документ:
ПечатнаяФормаПроизводственногоКалендаря(ПараметрыПечати)
Для стандартных механизмов печати БСП такая передача параметров нетипична. Обычно печатная форма привязана к конкретным объектам базы данных (документам, элементам справочников), которые выделил пользователь в списке для отправки на печать. Чтобы функция знала, для каких именно элементов нужно сформировать отчет, в неё обязательно передаются массив ссылок (МассивОбъектов) и объекты печати (ОбъектыПечати).
Если ваша функция формирует статичный календарь (например, просто пустой бланк на год, указанный в параметрах печати), то текущий вариант допустим. Но если печатная форма должна выводить данные конкретного выбранного в интерфейсе календаря, сигнатуру необходимо расширить.
Пошагово исправим все неточности, обеспечим безопасность вызовов и напишем чистый код для модуля менеджера. Мы применим динамическое обращение к общему модулю печати, чтобы избежать падения системы, если подсистема печати БСП по какой-то причине отсутствует в конфигурации.
Рассмотрим правильный вариант написания процедуры:
// Процедура осуществляет формирование печатных форм объекта
//
// Параметры:
// МассивОбъектов - Массив - Ссылки на печатаемые объекты.
// ПараметрыПечати - Структура - Дополнительные параметры настройки печати.
// КоллекцияПечатныхФорм - ТаблицаЗначений - Служебная таблица БСП для хранения результатов.
// ОбъектыПечати - СписокЗначений - Соответствие между объектами и страницами табличного документа.
// ПараметрыВывода - Структура - Параметры отображения печатных форм.
//
Процедура Печать(МассивОбъектов, ПараметрыПечати, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт
// Проверим, интегрирована ли в конфигурацию стандартная подсистема печати БСП
Если ОбщегоНазначения.ПодсистемаСуществует("СтандартныеПодсистемы.Печать") Тогда
// Получаем общий модуль динамически (это гарантирует отсутствие ошибок компиляции)
МодульУправлениеПечатью = ОбщегоНазначения.ОбщийМодуль("УправлениеПечатью");
// Формируем макет и добавляем его в коллекцию печатных форм БСП
МодульУправлениеПечатью.ВывестиТабличныйДокументВКоллекцию(
КоллекцияПечатныхФорм,
"ПроизводственныйКалендарь",
НСтр("ru = 'Производственный календарь'"),
ПечатнаяФормаПроизводственногоКалендаря(МассивОбъектов, ОбъектыПечати, ПараметрыПечати),
,
"Справочник.ПроизводственныйКалендарь.ПФ_MXL_ПроизводственныйКалендарь" // Обратите внимание на единственное число!
);
КонецЕсли;
КонецПроцедуры
В приведенном коде мы полностью устранили синтаксические ошибки, убрали некорректное использование ключевого слова Перем, исправили имя справочника в пути к макету на единственное число (согласно имени вашего объекта метаданных) и привели передачу параметров функции ПечатнаяФормаПроизводственногоКалендаря к стандартному виду БСП.