Парсер запросов 1С. Часть 1: Введение, разбор математических выражений

Рано или поздно становится скучно решать типичные задачи, для которых придумана 1С. Голова пухнет от бухгалтерских терминов и очередных "хотелок" пользователей. Именно в такие моменты хочется гордо поднять голову, воскликнуть "Но я же программист!" и заняться чем-то интересным. В цикле статей я постараюсь доступно описать, как устроены парсеры в целом и на примере парсера языка запросов 1С. Требования к навыкам читающего: основы языка 1С, основы алгоритмизации.

Для начала, определю цели данной серии публикаций.

  1. Создание функции, выполняющей полноценный парсинг запросов 1С в некоторую древовидную структуру.
  2. Создание функции, выполняющей обратное преобразование
  3. Создание обработки «Конструктор запросов» на управляемых формах

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

Также следует определить требования к парсеру:
  1. Он должен быть однопроходным (т.к. грамматика языка запросов не предполагает необходимости двупроходной обработки, как, например, грамматика языка C++)
  2. Он должен включать в себя лексический и синтаксический анализ. В перспективе необходима разработка тонкого анализа связи с метаданными конфигурации (семантический анализ).
  3. Он должен адекватно обрабатывать исключения

В первой части статьи я опишу разбор математических выражений. Эта тема очень хорошо освещена в русской и зарубежной литературе, впервые я познакомился с ней в книге «О чем не пишут в книгах по Delphi». На хабре достатоно поискать по ключевым словам «Парсер» или «Теория компиляторов». Более того, в данное время существуют генераторы парсеров, которые на основе данных о грамматике языка составляют исходный код парсера (Вики: Сравнение генераторв парсеров (англ.)). Однако, этот метод я рассматривать не буду — настоящий 1С-ник должен полагаться только на свой код.

Итак, какие же знания требуются для написания парсера?

Формальные грамматики.

Для описания грамматики языка Алгол Джоном Бэкусом и Питером Науром была раработана формальная система описания синтаксиса. Она называется БНФ (Бэкуса-Наура форма, BNF Вики: Форма Бэкуса-Наура). Данная система позволяет описывать одни категории с использованием других, постепенно наращивая сложность, и ее вполне реально использовать для решения поставленной задачи. Забегая вперед, скажу, что сама фирма 1С описывает свой язык запросов с помощью этой грамматики. Чтобы в этом убедиться, достаточно открыть справку по языку запросов.

Следующие операторы используются в БНФ:

::=

присваивание

|

Операция ИЛИ

 Имя

Литерал

[Имя]

Необязательный литерал

(Имя)

Литерал, повторяющийся 0 или более раз

При описании грамматики БНФ сначала необходимо дать определение абстракции нижнего уровня:

Цифра :: = ‘0’ | ‘1’ | ‘2’ | ‘3’ | ‘4’ | ‘5’ | ‘6’ | ‘7’ | ‘8’ | ‘9’

С помощью этого выражения мы указываем, что литерал может принимать одно из значений ‘0’ … ‘9’

Абстракция более выского уровня — вещественное число:

Знак ::= ‘-‘ | ‘+’

Разделитель ::= ‘.’

Число ::= [Знак] Цифра (Цифра) [ Разделитель (Цифра) ]

Число может иметь знак (+, -) а может не иметь его. Далее должна идти хотя бы одна цифра (или более). Затем может идти разделитель дробной и целой части (а может не идти). Если есть разделитель, то далее может идти одна цифра (или более) (спасибо (9)) .

Простейшее математическое выражение должно удовлетворять следующим требованиям:

  1. Допустимы операции + — * /
  2. Приоритет операций: Скобка > Умножение = Деление > Сложение = Вычитание

Основную сложность представляет из себя учет приоритета операций. Для этого любое выражение раскладывается на слагаемые и множители. Далее сначала выполяются операции со скобками, затем с множителями, и в конце со слагаемыми. В терминах БНФ матемтическое выражение описывается так:

Оператор1 ::= ‘+’ | ‘-‘

Оператор2 ::= ‘*’ | ‘/’

Множитель ::= Число | ‘(‘ Выражение ‘)’

Слагаемое ::= Множитель [Оператор2 Множитель]

Выражение ::= Слагаемое [Оператор1 Слагаемое]

Требование наличия скобок делает нашу грамматкику рекурсивной (на моменте вычисления множителя).

Программная часть.

Теперь определимся с программной частью. Непосредственно синтаксис БНФ будет разбирать синтаксический анализатор. Но с точки зрения грамматики выражение 2+2 является корректным, а 2 + 2 — нет, и для решения этой проблемы (обычно выражения с переносами строки и пробелами читаются легче) будет использоваться лексический анализатор. Его целью будет пропуск незначащих символов и извлечение лексемы (в нашей грамматике это может быть Число, Операция или одна из Скобок, которую он передаст на вход синтаксического анализатора.

Лексический анализатор.

Функция СледующийЛитерал(Литерал, ТекстЗапроса, ТекПоз)

    Если ТекПоз <= СтрДлина(ТекстЗапроса) Тогда

        // Пропустить пробелы
       
НезначащиеСимволы = » » + Символы.ПС + Символы.Таб;
        Пока
Найти(НезначащиеСимволы, Сред(ТекстЗапроса, ТекПоз, 1)) > 0 Цикл
           
ТекПоз = ТекПоз + 1;
        КонецЦикла;

        // Извлечь литерал
       
ТекСимвол = Сред(ТекстЗапроса, ТекПоз, 1);

        Если Найти(«()*/+-«, ТекСимвол) > 0 Тогда

            Литерал = ТекСимвол;
           
ТекПоз = ТекПоз + 1;

        ИначеЕсли ЭтоЦифра(ТекСимвол) Тогда

            Литерал = ИзвлечьЧисло(ТекстЗапроса, ТекПоз);

        Иначе

            ВызватьИсключение «Неизвестный символ в позиции » + Формат(ТекПоз, «ЧГ=0»);

        КонецЕсли;

        Возврат Истина;

    Иначе

        Литерал = Неопределено;
        Возврат Ложь;

    КонецЕсли;

КонецФункции

Функция ИзвлечьЧисло(ТекстЗапроса, ТекПоз)

    ТекСимвол = Сред(ТекстЗапроса, ТекПоз, 1);
   
Результат = «»;

    // Целая часть
   
Пока ЭтоЦифра(ТекСимвол) И ТекПоз <= СтрДлина(ТекстЗапроса) Цикл
       
ТекПоз = ТекПоз + 1;
       
Результат = Результат + ТекСимвол;
       
ТекСимвол = Сред(ТекстЗапроса, ТекПоз, 1);
    КонецЦикла;

    // Дробная часть
   
Если ТекСимвол = «.» Тогда
       
Результат = Результат + «.»;
       
ТекПоз = ТекПоз + 1;
       
ТекСимвол = Сред(ТекстЗапроса, ТекПоз, 1);
        Пока
ЭтоЦифра(ТекСимвол) И ТекПоз <= СтрДлина(ТекстЗапроса) Цикл
           
ТекПоз = ТекПоз + 1;
           
Результат = Результат + ТекСимвол;
           
ТекСимвол = Сред(ТекстЗапроса, ТекПоз, 1);
        КонецЦикла;
    КонецЕсли;

    Возврат Число(Результат);

КонецФункции

Функция ЭтоЦифра(ТекСимвол)

    Возврат ТекСимвол >= «0» И ТекСимвол <= «9»;

КонецФункции

Синтаксический анализатор.

Теперь приведу функции синтаксического анализатора. Каждая из них соответствует элементу грамматики БНФ. Отмечу, что в примере этими функциями вычисляются реальные выражения, хотя в реальном парсере они будут всего лишь проверять корректность выражений в запросе. Также в коде отсутствует часть необходимых исключений (эти функции я выдергивал из парсера запросов, который обладает уже гораздо большим функционалом, поэтому частью исключений пришлось пожертвовать — но они вернутся в следующих статьях)

Функция Выражение(ТекЛитерал, ТекстЗапроса, ТекПоз) Экспорт

    Если ТекЛитерал = Неопределено Тогда
       
// При первом вызове необходимо сдвинуть автомат на первую позицию
       
Если Не СледующийЛитерал(ТекЛитерал, ТекстЗапроса, ТекПоз) Тогда
            ВызватьИсключение
«Пустая строка»;
        КонецЕсли;
    КонецЕсли;

    Результат = Слагаемое(ТекЛитерал, ТекстЗапроса, ТекПоз);
    Пока Не
ТекЛитерал = Неопределено И Найти(«+-«, ТекЛитерал) > 0 Цикл
       
Литерал = ТекЛитерал;
       
СледующийЛитерал(ТекЛитерал, ТекстЗапроса, ТекПоз);
        Если
Литерал = «+» Тогда
           
Результат = Результат + Слагаемое(ТекЛитерал, ТекстЗапроса, ТекПоз);
        Иначе
           
Результат = Результат Слагаемое(ТекЛитерал, ТекстЗапроса, ТекПоз);
        КонецЕсли;
    КонецЦикла;

    Возврат Результат;

КонецФункции

Функция Слагаемое(ТекЛитерал, ТекстЗапроса, ТекПоз)

    Результат = Множитель(ТекЛитерал, ТекстЗапроса, ТекПоз);
    Пока Не
ТекЛитерал = Неопределено И Найти(«*/», ТекЛитерал) > 0 Цикл
       
Литерал = ТекЛитерал;
       
СледующийЛитерал(ТекЛитерал, ТекстЗапроса, ТекПоз);
        Если
Литерал = «*» Тогда
           
Результат = Результат * Множитель(ТекЛитерал, ТекстЗапроса, ТекПоз);
        Иначе
           
Результат = Результат / Множитель(ТекЛитерал, ТекстЗапроса, ТекПоз);
        КонецЕсли;
    КонецЦикла;

    Возврат Результат;

КонецФункции

Функция Множитель(ТекЛитерал, ТекстЗапроса, ТекПоз)

    Если ТекЛитерал = «(» Тогда

        Если СледующийЛитерал(ТекЛитерал, ТекстЗапроса, ТекПоз) Тогда
           
Результат = Выражение(ТекЛитерал, ТекстЗапроса, ТекПоз);
            Если
ТекЛитерал = «)» Тогда
               
СледующийЛитерал(ТекЛитерал, ТекстЗапроса, ТекПоз);
            Иначе
                ВызватьИсключение
«Ожидается ) в позиции » + Формат(ТекПоз, «ЧГ=0»);
            КонецЕсли;
        Иначе
            ВызватьИсключение
«Ожидается выражение в позиции » + Формат(ТекПоз, «ЧГ=0»);
        КонецЕсли;

    ИначеЕсли ЭтоЦифра(Сред(Строка(ТекЛитерал), 1, 1)) Тогда
       
Результат = ТекЛитерал;
       
СледующийЛитерал(ТекЛитерал, ТекстЗапроса, ТекПоз);
    Иначе
        ВызватьИсключение
«Неизвестный литерал в позиции » + Формат(ТекПоз, «ЧГ=0»);
    КонецЕсли;

    Возврат Результат;

КонецФункции

48 Comments

  1. juntatalor

    В функциях, которые в самой публикации, съелась половина кода.

    Раскрасил «Разукрашкой», все Ок.

    Reply
  2. tsmgeorg@gmail.com

    Да, бывает, иногда весело отвлечься от повседневных будней, спасибо за статью

    Reply
  3. omut

    Увлекательно написано, автору спасибо 🙂

    Небольшое замечание: если правильно понял, то вместо

    Число ::= [Знак] Число (Число) [ Разделитель Число (Число) ]

    должно быть «Число ::= [Знак] Цифра (Цифра) [ Разделитель Цифра (Цифра) ]»

    Reply
  4. vandalsvq

    Жду продолжения. Интересная тема

    Reply
  5. andrewks
    «Число ::= [Знак] Цифра (Цифра) [ Разделитель Цифра (Цифра) ]»

    а разве .25 не число?

    целая часть необязательна, если она опущена, подразумевается 0

    правильнее так:

    Число ::= [Знак] Цифра (Цифра) [ Разделитель Цифра (Цифра) ] | [Знак] Разделитель Цифра (Цифра)

    Reply
  6. andrewks

    даёшь lex и yacc для 1С! 🙂

    Reply
  7. omut

    (5) andrewks, не число. Если вы используете такую запись в коде 1С, тогда, конечно… 🙂

    Reply
  8. juntatalor

    (3) omut, да, спасибо за внимательное чтение — поправил!

    (5) andrewks, а вы попробуйте выполнить запрос «ВЫБРАТЬ .25 КАК Поле1». С точки зрения запросов 1С .25 — НЕ число.

    Reply
  9. andrewks

    (8)

    С точки зрения запросов 1С .25 — НЕ число.

    зато «25.» число 😉

    Reply
  10. juntatalor

    (9) andrewks, да, действительно, и что интересно — реализация функции ИзвлечьЧисло() понимает такие числа. Ошибка в записи синтаксиса, сейчас поправлю.

    Reply
  11. baton_pk

    Шлёпну плюс собрату по (не)счастью 🙂 Со школьных лет увлекаюсь синтаксическими разборами выражений. Вот сейчас тоже на досуге пилю парсер языка запросов с последующим исполнением.

    Маленькое замечание по тексту:

    Вы пишете «Синтаксический анализатор.», однако в коде одновременно с разбором производите и вычисление. В случае, если мы пишем простенький калькулятор — это сгодится, но раз мы замахнулись на запросы, то всё же на выходе Вашего анализатора должно быть дерево вычислений. Обратная польская запись — наше всё.

    Если есть желание, тут можно посмотреть, что у меня получается:

    https://github.com/dmpas/e8-query-parser/blob/master/query-driver.e8s

    Буду рад услышать Ваше мнение 🙂 Заодно прикладываю обработку погонять.

    Reply
  12. Yashazz

    Йессс! Подобные публикации таки опровергают гнусное мнение, что «одинэснег — не программист». Спасибо!

    Reply
  13. juntatalor

    (11) baton_pk, вычисление прикрутил, чтобы показать, что это действительно работает 🙂

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

    Реализованный функционал:

    Пакет запросов, запрос, описание запроса (по синтаксической диаграмме 1С), вложенные запросы

    ВЫБОР … КОГДА …

    ВЫРАЗИТЬ(… КАК) [Только для примитивных типов, для таблиц пока нет]

    Все логические конструкции (В (включая вложенные запросы), ПОДОБНО, МЕЖДУ, ЕСТЬ, ССЫЛКА)

    Да и много чего еще

    Баги и нереализованное:

    Простое выражение (например, имя поля, параметр или константа ИСТИНА / ЛОЖЬ) не считаются корректным логическим выражением. Обязательно надо указывать сравнение, например ГДЕ ИСТИНА — не работает, а ГДЕ 1 = 1 — работает.

    Нет проверки на необходимость функции быть агрегатной

    Да и еще куча всего. Зато есть динамический построитель таблиц базы данных.

    Reply
  14. juntatalor

    (11) baton_pk, как вы серьезно к разработке подошли! Очень понравился такой «Отладочный» режим выполнения запросов. Изучаю Ваш труд и готовлю следующую публикацию. Хотел в ней уже начать разбираться непосредственно с запросами, но получается очень объемно, возможно, придется все же сначала полностью закончить с математическими выражениями.

    Reply
  15. baton_pk

    (14)

    я сейчас размышляю над соединениями таблиц — там есть, над чем подумать. На этом пока заткнулся. Покуриваю стандарт SQL-92 — труд здоровенный, но некоторые вещи там описаны хорошо.

    Завтра на работе посмотрю Ваш конструктор.

    Reply
  16. baton_pk

    (13)

    Посмотрел Вашу обработку — внушает 🙂 Мы даже пишем почти одинаково 🙂

    Лично я не вижу смысла производить семантический анализ текста на этапе его лексического разбора. Я бы оставил это уже на этап исполнения — когда мы знаем весь набор входящих данных.

    Вы при разборе выражения указываете, считать его логическим или нет. У Вас, кстати, при разборе конструкции ВЫБОР не совсем верно отрабатывает проверка на логичность. Как сделано у Вас:

    ВЫБОР КОГДА <тут разбираем логическое выражение> ТОГДА <тут разбираем нелогическое выражение> ….

    Однако в выражении ТОГДА тоже может быть логическое выражение, если извне мы разбираем именно логическое выражение:

    ГДЕ ВЫБОР КОГДА 1=1 ТОГДА ИСТИНА ИНАЧЕ ЛОЖЬ КОНЕЦ = ИСТИНА

    В данном случае, пытаясь разобрать инструкцию ВЫБОР, Вы не знаете, должна она быть логической или нет, пока не дойдёте до знака сравнения.

    С другой стороны, с точки зрения 1С такой запрос имеет место быть:

    ВЫБРАТЬ 1 ГДЕ (1 + 3) = ИСТИНА

    Лично я разбираю выражение независимо от его типа — проблемы с вычислением будут отрабатываться на этапе исполнения. Если мы выполняем отбор по условию ГДЕ или в конструкции КОГДА, то на этапе исполнения ожидаем получить там что-нибудь булёвое, и если не получаем — бросаем исключение.

    Reply
  17. juntatalor

    (16) baton_pk, с Вашими доводами согласен целиком и полностью.

    Вообще у меня на каком-то этапе разбора выражений произошел кризис — я понял, что не могу автоматически отличить логическое выражение от математического. Приняв это как данность, я накрутил ручную установку флага «Логическое» и успокоился. Пока речь шла о простых условиях, все было нормально. Но сейчас уже есть ВЫБОР … КОНЕЦ и параметры виртуальных таблиц. Сейчас уже всерьез задумался, что автоматическое определение типа выражения — логическое / математическое — это необходимость.

    Reply
  18. juntatalor

    (16) baton_pk, кстати, как Вам моя процедура ДобавитьИсточник()? Вроде бы достаточно неплохо обрабатывает соединения (ну, за исключением, как мы уже говорили, некоторой корявости с математикой / логикой).

    Reply
  19. baton_pk

    (18)

    В смысле разбора я примерно так и думал его делать. У меня нет чёткого понимания, как это должно отрабатываться уже непосредственно при исполнении. Это влияет на порядок построения дерева, а это влияет на разработку непосредственно разбора.

    Да, и ещё: у Вас обязательно наличие слова «КАК». Знаю я людей, которые патологически презирают это слово :):)

    Ещё неясный момент с выборкой всех полей по «*». У Вас отрабатывается только «ВЫБРАТЬ * ИЗ Т1,Т2», когда вполне может быть запрос: «ВЫБРАТЬ Т1.Поле1, Т1.Поле2, Т2.* ИЗ Т1, Т2»

    Reply
  20. German

    Парни GoldParser(x32) или Antlr. Зачем такие велосипеды? Все уже давно сделано в том числе написана грамматика для языка запросов 1С

    Reply
  21. baton_pk

    (20) German,

    я так понимаю, что у juntatalor интерес чисто академический — тут по-определению будут сплошь одни велосипеды.

    Reply
  22. comol

    Эх… детство, отрочество, молодость….

    (20) German, да. да… Такие крутяцкие программулены, изучаешь в каком формате им нужно семантику или синтаксис скармливать, пишешь правила и фигак оно всё парсит, и более того даже код на c++ генерит для парсера…

    мы в школеунивере развлекались с Flex и Bison…

    Reply
  23. juntatalor

    (19) baton_pk, Насчет * — внес в TODO лист.

    КАК обязательно только для вложенных запросов, для обычных таблиц нет.

    Reply
  24. tormozit

    Я здесь был (подписался)

    Reply
  25. baton_pk

    (23) я не только про таблицы, я ещё и про поля.

    Reply
  26. AllexSoft

    Интересно что получится в итоге….

    Reply
  27. juntatalor

    (26) AllexSoft, то, что обещано в пункте 3, конечно же! 🙂

    3. Создание обработки «Конструктор запросов» на управляемых формах

    После выходных выложу вторую часть статьи. Под конец недели работы много, никак не допишу.

    Reply
  28. awk

    (20) German, (22) comol, А мне javacc нравится..

    Reply
  29. ignor

    Подписался

    Reply
  30. so-quest

    Мои пять копеек — сравнение литералов — медленная операция. в своем сканере сдеала так — сперва весь поток преобразовывается в массив чисел (используется кодсимвола) и затем просто сравнение чисел. Но вообще-то предыдущие участники правы — детство все это — эффективнее чем автомат у тебя не получится, потребности помнить пробельный символы в твое задаче нет, выгоднее использовать типовые инструменты, чем изобретать свой лисапед. тем более для голдпарсера есть вывод кода сразу в 1С, без использования активХ.

    Вот если бы ты для PEG парсера преобразователь нарисовал — было бы лучше…

    Reply
  31. so-quest

    (6) andrewks, есть уже. нафиг только никому не нужно 🙂

    Reply
  32. juntatalor

    (30) so-quest, да уже столкнулся с тем, что сравнивать литералы действительно очень медленно. Пока что провел замеры различных алгоритмов, как ни странно, выигрывает Найти(ВесьАлфавит, ТекСимвол). Примерно равный результат дает перевод алфавита в Соответствие и сравнение литерала методом Соответствие.Получить(). Хуже Найти(ЗаглавныйАлфавит, Врег(ТекСимвол), перевод через КодСимвола с последующим сравнением числа и прямое сравнение символов.

    С КодСимвола() все сложно. Не спорю, что если все перевести в числа, и потом сравнивать — работает быстрее, но эффективно это будет только если много раз парсить один и тот же запрос (тут встает вопрос — зачем?) — потому что на каждый новый запрос нужно будет создавать новый массив чисел, а это сильные временные затраты на КодСимвола (как-то уж очень неспешно она работает).

    Вообще, убедился в очередной раз, что для критичных с точки зрения производительности процессов скриптовые языки подходят плохо. Нет высокоуровнего доступа к процессору и памяти, в результате чего код, который отрабатывает на C за микросекунды в 1С работает секунды (хотя, казалось бы — простая операция сравнения).

    Reply
  33. baton_pk

    Не смог сдержать буйный интерес и поставил себе GoldParser. Неслабый инструмент, но требующий глубокого изучения.

    Если стоит выбор, изучать теорию лексического разбора или изучать GoldParser, то конечно же лучше изучить GoldParser. Но если выбор в том, писать ли свой парсер, зная теорию лексического разбора, или изучать GoldParser с нуля, то я уж лучше напишу свой парсер сам 🙂

    Приведу цифры:

    На поставить(/посмотреть/потыркать/попробовать и т.д) GoldParser у меня ушло примерно 1.5-2 часа, чтобы понять, что это такое и с чем едят. Парсер языка 1С с преобразованием в байт-код я написал за 7 часов. Без байт-кода это как-раз бы и вышло 1.5-2 часа. Ну, если б я писал парсер хотя бы каждый месяц, я бы безусловно освоил и GoldParser, и его собратьев, но т.к. парсеры приходится писать крайне редко, а разбор математических конструкций я пишу чуть ли не с закрытыми глазами, а на выходе получаю код целиком и полностью мне известный, то буду писать парсеры руками.

    Поэтому опять же, не ищите в статье практического смысла. Он тут исключительно академический.

    Reply
  34. WalterMort

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

    Reply
  35. Pashkatancor

    ждем продолжения…

    Reply
  36. slavik27

    интересно

    Reply
  37. so-quest

    (32) Скорость и 1С это как селедка и шампанское. крайне редко вместе уживаются. Хотяб потому что операция сравнения простая только если знаешь тип.

    (33) baton_pk, руками писать понимаемый код можно только пока работаешь один. когда начинаешь работать в команде — все же требуется использование типовых (либо признаных такими) инструментов. Просто потому что там уже решены проблемы со скоростями, обработкой ошибок и наработаны практики использования. Ты же не изобретаешь каждый раз УниверсальныйОтчет или не пишешь каждый день с ноля конвертацию данных.

    Что касается голдпарсера — так это даже не смешно — нечего там изучать (тем более зная теорию ) — это же просто генератор таблиц для автоматов.

    Reply
  38. baton_pk

    (37) so-quest,

    Просто потому что там уже решены проблемы со скоростями

    Ага, помнится, на одном жёлтом неназываемом здесь форуме очень дико ругались на производительность GoldParse, ANTLR и иже с ними. Самому, к сожалению, пока не довелось сравнить скорости, потому в эту сторону рассуждать не буду.

    Ты же не изобретаешь каждый раз УниверсальныйОтчет или не пишешь каждый день с ноля конвертацию данных

    Боже упаси! 😀

    нечего там изучать (тем более зная теорию )

    Для меня «нечего там изучать» — это открыл, вбил, нажал, получил. Если за 5-10 минут у меня это не получилось, значит, надо всё-таки хоть чуть-чуть поизучать. В универсальном отчёте тоже вроде бы нечего изучать, ан нет — сам убил не один час своей жизни, объясняя людям, что это и как этим пользоваться.

    это же просто генератор таблиц для автоматов

    Ага, но итог-то требуется не в виде таблиц, а в виде автомата, работающего с этой таблицей на нужном языке.

    Я понимаю, что тут есть незнание и кривость рук, но то…. код… который мне выдала эта штуковина, ни на что не годится.

    Потому опять же, «нечего изучать» — Вы тут немножко лукавите всё-таки.

    PS

    руками писать понимаемый код можно только пока работаешь один

    Нет, если следовать стандартам. В 1С их пока-что маловато и тем не следуют. Да и практика оценки кода (Code Review) тут совершенно никак не применяется :(.

    Reply
  39. tormozit

    Возможно кто то не знает, конструктор запроса я свой уже сделал в ИР http://devtool1c.ucoz.ru/index/konstruktor_zaprosa/0-38 . Если кто то захочет писать свой, то думаю мой код ему драматически сократит затраты по времени.

    GoldParser на сервере мне не удалось использовать. Может быть кто то знает волшебный способ? Тогда бы до конструктора запроса под тонкую форму осталось часов 20-30.

    Reply
  40. so-quest

    (38) baton_pk, производительность ANTLR это конечно да… Та еще песня. По голдпарсеру — все от радиуса кривизны рук зависит. ничто не мешает переписать шаблон генерации так что бы скорость тебя удовлетворяла (на любом удобном тебе языке). Ручной парсер нужен там где граматику не сделать (лисп/схема (макросы чтения все портят)). Или сделать, но она неоправданно сложная станет (С++ или С). В случае с 1С — излишне.

    Все вышеописаное — имхо.

    И да — лучше все же flexison чем голдпарсер, ручной парсер.

    Кстати, выложи свой парсер 1С — глянуть.

    Reply
  41. so-quest

    (39) tormozit, я тебе уже рекламировал свой шаблон генератора для голдпарсера, что помешало использовать?

    Reply
  42. tormozit

    (41) Объектная модель GoldParser у тебя не воссоздана. Она у меня активно используется в коде конструктора запросов. Т.е. придется много кода переделывать необратимо, либо засорять и без того сложную логику ветвлениями «если парсер такой, то делаем так, иначе делаем так».

    Reply
  43. baton_pk

    (40) so-quest,

    Прикладываю его старую версию на C++. Сейчас всё на чистый C переписаваю. У файла куча внешних зависимостей, но если Вам только код глянуть, то в самый раз. В добавок, вывод байт-кода тоже можно было бы отбросить.

    Эта штука у меня без ошибок разобрала все общие модули УПП. Отрабатывает директивы препроцессора произвольной вложенности. Добавлена пара фишек от себя, в частности:

    https://github.com/dmpas/e8-engine-examples/blob/master/0.2.4/pre-or-and.e8s

    https://github.com/dmpas/e8-engine-examples/blob/master/0.2.4/assert.e8s

    https://github.com/dmpas/e8-engine-examples/blob/master/0.2.4/altnames.e8s

    Reply
  44. ikekoval

    Статья очень понравилась. Жду продолжения (подпись)

    Reply
  45. magolubev

    Вспомнил институтские годы, парсеры на Lex/Yacc…

    По делу — согласен с baton_pk, необходимо промежуточное представление программы в форме обратной польской записи

    Reply
  46. lesenoklenok

    Очень интересная статья, подробно описано.

    Reply
  47. baton_pk

    (0) Где обещанное продолжение??

    Reply
  48. so-quest

    Моя попытка продолжения http://www.cyberforum.ru/1c-custom/thread1307974.html#post6887051 — собираю критику к 1 главе.

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *