Встроенный язык 1С: разбираемся в синтаксисе с нуля

· 9 мин

Содержание

Синтаксис 1С — это набор правил, по которым платформа читает ваш код: как объявляются переменные, как пишутся условия и циклы, где начинается и где заканчивается процедура. Понять синтаксис 1С проще, чем кажется: язык русскоязычный, нестрогий по типам и прощает новичку многое. Главное — усвоить десяток конструкций, которые встречаются в каждом модуле.

Встроенный язык 1С:Предприятие 8.3 похож на школьный алгоритмический язык. Ключевые слова пишутся по-русски (Если, Цикл, Процедура), регистр букв не важен, а большинство ошибок — это забытая ; или перепутанные Тогда и Цикл. Ниже — сами правила, с примерами кода, которые можно вставить в обработку и запустить.

Из чего состоит строка кода: лексика языка

Любой модуль 1С — это последовательность операторов. Оператор — законченное действие: присвоить значение, вызвать метод, проверить условие. Операторы разделяются точкой с запятой ;.

Сумма = 100;
Ставка = 20;
НДС = Сумма * Ставка / 120;

Базовые элементы языка:

  • 🔑 Ключевые слова — зарезервированные слова платформы: Если, Тогда, Цикл, Процедура, Возврат. Их нельзя использовать как имена переменных.
  • 🏷️ Идентификаторы — имена переменных, процедур, реквизитов. Начинаются с буквы или подчёркивания, могут содержать цифры: СуммаДокумента, _Итог1.
  • 🔢 Литералы — значения прямо в коде: число 3.14, строка "Привет", дата '20240115', логическое Истина / Ложь.
  • 💬 Комментарии — две косые черты //. Всё до конца строки платформа игнорирует.

Встроенный язык не чувствителен к регистру. Сообщить, СООБЩИТЬ и сообщить — это один и тот же метод. То же касается имён переменных: Итог и итог — одна переменная.

Строковые литералы заключают в двойные кавычки. Если кавычка нужна внутри строки, её удваивают:

Текст = "Нажмите кнопку ""Провести""";

Многострочную строку переносят, начиная каждую следующую строку с вертикальной черты |:

Текст = "Первая строка
|Вторая строка
|Третья строка";

Ещё одна особенность: ключевые слова дублируются на английском. Можно писать If ... Then ... EndIf вместо Если ... Тогда ... КонецЕсли. В типовых конфигурациях используют русский вариант — его и держитесь.

Переменные и типы данных: что во что превращается

1С — язык с динамической типизацией. Тип переменной определяется не при объявлении, а по значению, которое в неё положили. Одна и та же переменная может сначала хранить число, потом строку.

Значение = 10;        // число
Значение = "десять";  // теперь строка — ошибки нет

Явно объявлять переменную оператором Перем не обязательно — она создаётся в момент первого присваивания. Перем используют в начале модуля или процедуры, когда переменную нужно сделать видимой заранее.

Примитивные типы, с которыми вы столкнётесь в первый же день:

ТипПример значенияДля чего
Число42, 3.14, -5суммы, количества, ставки
Строка"Текст"наименования, тексты ошибок
Дата'20240115120000'даты документов, периоды
БулевоИстина, Ложьфлаги и результаты проверок
НеопределеноНеопределено«значение не задано»

Кроме примитивов есть ссылочные типы (ссылки на элементы справочников и документы) и коллекции — контейнеры для наборов данных:

  • Массив — список значений по индексу. Нумерация с нуля: Массив[0] — первый элемент.
  • Структура — набор «ключ-значение» с фиксированными именами полей.
  • Соответствие — тоже «ключ-значение», но ключом может быть любое значение.
  • ТаблицаЗначений — таблица с колонками и строками, аналог небольшой БД в памяти.

Коллекции создают оператором Новый:

Товары = Новый Массив;
Товары.Добавить("Карандаш");
Товары.Добавить("Тетрадь");
Сообщить(Товары.Количество()); // выведет 2

Число и строку нельзя просто сложить через + — платформа выдаст ошибку преобразования. Чтобы собрать текст с числом, приведите число явно: "Итого: " + Строка(Сумма) или используйте шаблон СтрШаблон("Итого: %1", Сумма).

Условия и циклы: как управлять ходом выполнения

Проверка условия — конструкция Если ... Тогда ... КонецЕсли. Ветки ИначеЕсли и Иначе необязательны.

Если Сумма > 100000 Тогда
    Скидка = 10;
ИначеЕсли Сумма > 50000 Тогда
    Скидка = 5;
Иначе
    Скидка = 0;
КонецЕсли;

Операторы сравнения: = (равно, не ==), <> (не равно), <, >, <=, >=. Логические связки пишутся словами: И, ИЛИ, НЕ.

Если Сумма > 0 И НЕ ПометкаУдаления Тогда
    // ...
КонецЕсли;

Циклов в языке три вида:

  1. Счётный цикл — Для ... По ... Цикл. Повторяет блок заданное число раз.
Для Сч = 1 По 5 Цикл
    Сообщить(Сч);
КонецЦикла;
  1. Цикл по коллекции — Для Каждого ... Из ... Цикл. Перебирает элементы массива, таблицы, выборки.
Для Каждого Элемент Из Товары Цикл
    Сообщить(Элемент);
КонецЦикла;
  1. Цикл с условием — Пока ... Цикл. Работает, пока условие истинно.
Остаток = 1000;
Пока Остаток > 0 Цикл
    Остаток = Остаток - 100;
КонецЦикла;

Внутри любого цикла работают два управляющих оператора: Прервать досрочно выходит из цикла, Продолжить пропускает оставшуюся часть итерации и переходит к следующей.

Если удаляете элементы из коллекции внутри цикла, не используйте Для Каждого — индексы сместятся. Идите счётным циклом в обратном порядке: от последнего индекса к первому.

Процедуры и функции: где живут переменные

Код группируют в процедуры и функции. Разница одна: функция возвращает значение оператором Возврат, процедура — нет.

Функция РассчитатьНДС(Сумма, Ставка)
    Возврат Сумма * Ставка / (100 + Ставка);
КонецФункции

Процедура ВывестиИтог(Значение)
    Сообщить("Итого: " + Строка(Значение));
КонецПроцедуры

Вызов выглядит естественно: функцию — в правой части присваивания, процедуру — отдельной строкой.

НДС = РассчитатьНДС(12000, 20);
ВывестиИтог(НДС);

Ключевое слово Экспорт после списка параметров делает процедуру или функцию видимой из других модулей. Без него она доступна только внутри своего модуля.

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

Параметры по умолчанию передаются по значению для примитивов и по ссылке для объектов. Чтобы запретить изменение параметра внутри процедуры, перед ним ставят Знач:

Процедура Обработать(Знач ИсходнаяСтрока)
    // ИсходнаяСтрока менять внутри можно, снаружи это не отразится
КонецПроцедуры

В управляемом приложении процедуры помечают директивами компиляции — они говорят платформе, где выполнять код: &НаКлиенте, &НаСервере, &НаСервереБезКонтекста. Директива ставится строкой выше заголовка процедуры.

Попытка и Исключение: ловим ошибки и отлаживаем код

Чтобы одна ошибка не обрушила всю обработку, опасный участок оборачивают в конструкцию Попытка ... Исключение ... КонецПопытки. Если в блоке Попытка возникает ошибка, выполнение прыгает в блок Исключение.

Попытка
    Результат = 100 / Делитель;
Исключение
    Сообщить("Ошибка: " + ОписаниеОшибки());
КонецПопытки;

Метод ОписаниеОшибки() возвращает текст последней ошибки. Собственную ошибку можно возбудить вручную оператором ВызватьИсключение:

Если Делитель = 0 Тогда
    ВызватьИсключение "Делитель не может быть нулём";
КонецЕсли;

Не оборачивайте в Попытка весь код подряд. Так вы спрячете настоящие ошибки и будете долго искать, почему «ничего не считается». Ловите только то, что реально может сбоить: деление, разбор строки, запись объекта.

Отладка. Чтобы увидеть, что происходит внутри кода, в Конфигураторе или в режиме «1С:Предприятие» ставят точку останова — клик на левом поле строки или клавиша F9. Запустив обработку в режиме отладки, вы остановитесь на этой строке и сможете навести курсор на переменную, чтобы увидеть её текущее значение. Пошаговый проход — клавиша F11 (зайти в процедуру) и F10 (выполнить строку целиком).

Для быстрой диагностики без точек останова выручает Сообщить() — вывод значения прямо в окно сообщений. Грубо, но наглядно.

Язык запросов: отдельный синтаксис внутри кода

Данные из базы читают не циклами, а запросом — это отдельный язык внутри встроенного. Запрос выполняется на стороне сервера и работает в разы быстрее, чем перебор справочника в цикле.

Текст запроса строят по схеме ВЫБРАТЬ ... ИЗ ... ГДЕ:

Запрос = Новый Запрос;
Запрос.Текст =
    "ВЫБРАТЬ
    |   Номенклатура.Наименование КАК Имя,
    |   Номенклатура.Артикул
    |ИЗ
    |   Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |   НЕ Номенклатура.ПометкаУдаления";
Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
    Сообщить(Выборка.Имя);
КонецЦикла;

Ключевые секции языка запросов:

  • ВЫБРАТЬ — какие поля получить;
  • ИЗ — из какой таблицы (справочник, документ, регистр);
  • ГДЕ — условие отбора;
  • СГРУППИРОВАТЬ ПО — группировка с агрегатами СУММА, КОЛИЧЕСТВО, МАКСИМУМ;
  • УПОРЯДОЧИТЬ ПО — сортировка результата;
  • ИТОГИ ... ПО — подсчёт итогов по иерархии.

Значения в запрос передают не склейкой строк, а параметрами — через & в тексте и метод УстановитьПараметр:

Запрос.Текст = "ВЫБРАТЬ Ссылка ИЗ Документ.РеализацияТоваровУслуг
    |ГДЕ Дата >= &НачалоПериода";
Запрос.УстановитьПараметр("НачалоПериода", '20240101');

Никогда не вставляйте значения в текст запроса конкатенацией строк. Это ломается на кавычках и датах и открывает дыру в безопасности. Только параметры через &.

Где живёт код: модули и директивы компиляции

Синтаксис одинаков везде, но код в 1С не висит в воздухе — он лежит в модулях. От того, в каком модуле находится процедура, зависит, когда и где она выполнится.

Основные типы модулей:

  • 📦 Общий модуль — функции, которые вызывают из разных мест. Здесь держат расчёты и вспомогательные методы с ключевым словом Экспорт.
  • 📄 Модуль объекта (справочника, документа) — обработчики событий записи и проведения: ПередЗаписью, ОбработкаПроведения.
  • 🖥️ Модуль формы — реакция на действия пользователя: нажатия кнопок, изменение полей.

В управляемом приложении код делится на клиентский и серверный. Клиент (компьютер пользователя) не имеет прямого доступа к базе — за данными он обращается к серверу. Поэтому перед процедурой ставят директиву компиляции:

&НаКлиенте
Процедура КнопкаРассчитатьНажатие(Команда)
    Результат = ПолучитьДанныеСервер();
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьДанныеСервер()
    // здесь доступны запросы к базе
КонецФункции

Запрос к базе и работа со справочниками возможны только на сервере. Если напишете чтение данных в клиентской процедуре, получите ошибку компиляции. Это не про синтаксис оператора, а про место, где он стоит.

Частые ошибки новичка в синтаксисе 1С

Разберём, на чём спотыкаются чаще всего — это сэкономит часы на поиск «почему не компилируется».

  • ❌ Забытая точка с запятой. Конфигуратор подчеркнёт строку и напишет, что ожидается ;. Проверьте конец предыдущего оператора.
  • ❌ Перепутаны Тогда и Цикл. После Если идёт Тогда, после Для/Пока — Цикл. Закрываются они тоже по-разному: КонецЕсли и КонецЦикла.
  • ❌ Знак == вместо =. В 1С сравнение и присваивание — это один символ =. Двойного равенства в языке нет.
  • ❌ Сложение числа и строки. "Сумма " + 100 даёт ошибку преобразования. Оберните число в Строка().
  • ❌ Обращение к несуществующему индексу массива. В массиве из 3 элементов допустимы индексы 0, 1 и 2. Обращение к Массив[3] вызовет ошибку выхода за границу.
  • ❌ Ожидание, что локальная переменная видна в другой процедуре. Переменная из одной процедуры в другой не существует — передавайте её параметром или делайте переменной модуля.

Чтобы закрепить правила, пройдите короткий тест.

Проверьте себя
Какой оператор завершает цикл `Пока`?
Как в 1С записывается «не равно»?
С какого индекса начинается нумерация элементов массива?
Что вернёт функция без оператора `Возврат`?

Частые вопросы

Нужно ли знать английский, чтобы программировать в 1С?
Нет. Ключевые слова встроенного языка русскоязычные: Если, Цикл, Процедура. Английские аналоги существуют, но в типовых конфигурациях не используются.
Чем функция отличается от процедуры?
Функция возвращает значение через оператор Возврат и вызывается в правой части присваивания. Процедура ничего не возвращает и вызывается отдельной строкой.
Обязательно ли объявлять переменные через `Перем`?
Нет. Локальная переменная создаётся при первом присваивании. Перем нужен, когда переменную надо объявить заранее — например, сделать её переменной модуля с ключевым словом Экспорт.
Почему данные из базы читают запросом, а не циклом?
Запрос выполняется на сервере и отбирает только нужные записи, а перебор справочника в цикле тянет все объекты на клиент. На больших справочниках разница в скорости — в десятки раз.
Где удобнее писать и проверять код новичку?
В Конфигураторе: там есть подсветка синтаксиса, проверка модуля (Текст → Проверить модуль) и отладчик с точками останова. Для разовых расчётов подойдёт внешняя обработка с одной процедурой.