Почему возникает ошибка «Ожидается символ '('» после использования конструктора печати и как её исправить?

Программист 1С v8.3 (Обычные формы)
← На главную

При разработке в среде 1С:Предприятие программисты часто прибегают к помощи автоматизированных инструментов, таких как «Конструктор печати». Это мощный инструмент, который позволяет быстро создать макет, описать запрос к базе данных и сформировать программный код в модуле менеджера или объекта. Однако автоматика не всегда безупречна. Распространенной проблемой является ситуация, когда после завершения работы конструктора система выдает синтаксическую ошибку: Ожидается символ '('. Рассмотрим детально, почему это происходит, как исправить ошибку и какие нюансы работы с объектом Запрос стоит учитывать.

Причина ошибки: Правила именования идентификаторов

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

Процедура МШ8-1(ТабДок, Ссылка) Экспорт

С точки зрения компилятора 1С, имя процедуры МШ8-1 является некорректным. Разберем почему. Встроенный язык 1С накладывает строгие ограничения на идентификаторы (имена переменных, процедур, функций, метаданных):

  1. Идентификатор должен начинаться с буквы или символа подчеркивания _.
  2. Идентификатор может содержать только буквы, цифры и символы подчеркивания.
  3. Использование дефиса (тире) «-» внутри идентификатора запрещено.

Когда синтаксический анализатор 1С встречает строку Процедура МШ8-1, он воспринимает МШ8 как имя процедуры, а символ - как бинарный оператор вычитания. После имени процедуры анализатор ожидает открывающую скобку для списка параметров (. Поскольку вместо скобки он видит знак «минус», система выдает сообщение об ошибке: Ожидается символ '('.

Выясним причину, по которой «Конструктор печати» допустил такую ошибку. Часто разработчики называют макеты, используя дефисы (например, согласно шифрам государственных форм — «МШ8-1», «Т-11»). Конструктор, генерируя код, подставляет имя макета в название процедуры «как есть», не очищая его от спецсимволов. Это особенность платформы, которую необходимо контролировать вручную.

Как исправить имя процедуры

Для устранения ошибки нам необходимо переименовать процедуру во всех местах её вызова. Рассмотрим правильный вариант написания кода:


// Вместо МШ8-1 используем подчеркивание
Процедура МШ8_1(ТабДок, Ссылка) Экспорт 
    // Внутренняя логика процедуры
КонецПроцедуры

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

Разбор методов установки параметров запроса

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

Метод УстановитьПараметр(Имя, Значение) — это классический способ, существующий в платформе практически с момента её основания. Он выполняет одну задачу: передает значение в текст запроса по указанному имени.

Свойство Параметры представляет собой объект типа Соответствие. Этот механизм появился позже (в версии 8.2.14) для удобства разработчиков. Использование Запрос.Параметры.Вставить("Ссылка", Ссылка) технически эквивалентно методу УстановитьПараметр.

Выясним преимущества использования коллекции Параметры:

Таким образом, хотя оба метода равнозначны для выполнения запроса, использование Запрос.Параметры считается более современным и гибким подходом. Однако стоит помнить, что «Конструктор печати» в старых конфигурациях или определенных режимах совместимости может по-прежнему генерировать УстановитьПараметр(), что не является ошибкой.

Фантомные ошибки компиляции

Интересным моментом в сообщении автора является ошибка в строке Выборка = Запрос.Выполнить(>).Выбрать;. На первый взгляд кажется, что проблема в синтаксисе выполнения запроса. Однако на самом деле это «фантомная» ошибка или ошибка каскадного типа.

Проанализируем ситуацию: когда компилятор встречает критическую ошибку в объявлении процедуры (как в случае с дефисом), он теряет контекст. Весь последующий блок кода до ключевого слова КонецПроцедуры может распознаваться некорректно. Как только вы исправите заголовок Процедура МШ8_1, ошибки внутри тела процедуры, связанные с методом Выполнить(), скорее всего, исчезнут сами собой.

Рекомендации по профилактике подобных ситуаций

Чтобы избежать подобных проблем при работе с конструкторами 1С, рекомендуем придерживаться следующих правил:

  1. Именование макетов: Старайтесь изначально называть макеты без использования дефисов. Вместо «МШ8-1» пишите «МШ8_1» или «МШ81». Это гарантирует, что любой автогенерируемый код будет синтаксически верным.
  2. Синтаксический контроль: После работы любого конструктора всегда нажимайте Ctrl + F7. Это позволяет выявить ошибки до запуска отладки и точно определить строку, на которую «ругается» платформа.
  3. Внимательность к позиции курсора: Обращайте внимание на номер строки и позицию символа в тексте ошибки. В примере автора платформа четко указала на 14-й символ в строке объявления процедуры — именно там располагался злополучный дефис.

Рассмотрим финальный вариант корректного кода, который должен получиться после исправления:


Процедура МШ8_1(ТабДок, Ссылка) Экспорт 
    //{{_КОНСТРУКТОР_ПЕЧАТИ(МШ8_1)
    Макет = Документы.СписаниеМалоценныхАктивовИзЭксплуатации.ПолучитьМакет("МШ8_1");
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	СписаниеМалоценныхАктивовИзЭксплуатации.Дата,
        |	СписаниеМалоценныхАктивовИзЭксплуатации.Номер,
        |	СписаниеМалоценныхАктивовИзЭксплуатации.МалоценныеАктивы.(
        |		Номенклатура,
        |		ФизЛицо
        |	)
        |ИЗ
        |	Документ.СписаниеМалоценныхАктивовИзЭксплуатации КАК СписаниеМалоценныхАктивовИзЭксплуатации
        |ГДЕ
        |	СписаниеМалоценныхАктивовИзЭксплуатации.Ссылка В (&Ссылка)";

    Запрос.УстановитьПараметр("Ссылка", Ссылка);
    Выборка = Запрос.Выполнить().Выбрать;

    ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
    Шапка = Макет.ПолучитьОбласть("Шапка");
    ОбластьМалоценныеАктивыШапка = Макет.ПолучитьОбласть("МалоценныеАктивыШапка");
    ОбластьМалоценныеАктивы = Макет.ПолучитьОбласть("МалоценныеАктивы");

    ТабДок.Очистить();
    ВставлятьРазделительСтраниц = Ложь;
    
    Пока Выборка.Следующий() Цикл
        Если ВставлятьРазделительСтраниц Тогда
            ТабДок.ВывестиГоризонтальныйРазделительСтраниц();
        КонецЕсли;
        
        ТабДок.Вывести(ОбластьЗаголовок);
        Шапка.Параметры.Заполнить(Выборка);
        ТабДок.Вывести(Шапка, Выборка.Уровень());
        ТабДок.Вывести(ОбластьМалоценныеАктивыШапка);
        
        ВыборкаМалоценныеАктивы = Выборка.МалоценныеАктивы.Выбрать();
        Пока ВыборкаМалоценныеАктивы.Следующий() Цикл
            ОбластьМалоценныеАктивы.Параметры.Заполнить(ВыборкаМалоценныеАктивы);
            ТабДок.Вывести(ОбластьМалоценныеАктивы, ВыборкаМалоценныеАктивы.Уровень());
        КонецЦикла;
        
        ВставлятьРазделительСтраниц = Истина;
    КонецЦикла;
    //}}
КонецПроцедуры

Подводя итог, можно сказать, что ошибка «Ожидается символ '('» в 99% случаев связана с тем, что компилятор наткнулся на неожиданный символ там, где по правилам языка должна быть скобка. В контексте конструктора печати это почти всегда вызвано дефисом в названии процедуры. Будьте внимательны к именованию объектов метаданных, и это избавит вас от множества мелких, но досадных ошибок.

← На главную