Добро пожаловать на Pro Pawn - Портал о PAWN-скриптинге.

Реклама



**Как получить V.I.P** (Перейти)
Чтобы заказать рекламу на Pro-Pawn.Ru, обращайтесь в Skype.
Баннерная реклама 100руб/мес, Текстовая 50руб/мес.
Показано с 1 по 4 из 4
  1. #1
    Аватар для VVWVV
    Проверенный

    Статус
    Оффлайн
    Регистрация
    09.07.2015
    Сообщений
    548
    Репутация:
    250 ±

    Препроцессорные парсеры

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

    Введение

    Препроцессорные парсеры – это конструкции из препроцессорных директив define, которые необходимы для определения отрывка кода по заданному шаблону. Подобные конструкции можно рассматривать, как более продвинутые манипуляции с компилятором.

    Именно данные парсеры послужили основой для множества лучших библиотек. Например, всеми любимая библиотека foreach, которая образует новый псевдо-оператор foreach со своим синтаксисом и т.д.

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

    Рассмотрим пример:
    PHP код:
    #define SOME_PARSE: _:SOME_MACRO_TAG_0:SOME_MACRO_TAG_1:
    #define SOME_MACRO_TAG_0:SOME_MACRO_TAG_1:%1<%2>%0[%3] %1,%2,%3
    #define SOME_MACRO_TAG_1:%1[%3] %1,cellmax,%3

    main()
    {
        
    printf("%d %d %d %d"SOME_PARSE:5<8>[10]);
        
    printf("%d %d %d %d"SOME_PARSE:5[10]);

    Теперь рассмотрим каждую строчку более подробнее. Начнём.
    1. Первая строчка необходима для упрощения вызова данного парсера.
    2. Вторая строчка необходима для определения шаблона %1<%2>%0[%3] в строке. Заметим, что между символом ">" и "[" стоит нуль. Данный нуль необходим для определения пробелов между данными символами, т.е. для написания подобным образом:
      PHP код:
      SOME_PARSE:<8>  [10
    3. Третья - альтернатива. То есть, если вторая строка не подходит по шаблону то значит, что альтернативная для этого только третья.


    При использовании флага -l при компиляции, создаётся файл с расширение ".lst", который содержит результат работы препроцессора. Давайте рассмотрим результат выше приведенного кода:
    PHP код:
        printf("%d %d %d %d"_:5,8,10);
        
    printf("%d %d %d %d"_:SOME_MACRO_TAG_0:5,cellmax,10); 
    Заметим то, что остался тег SOME_MACRO_TAG_0, но мы его обезвредили "нулевым" тегом, иначе была бы ошибка из-за несовпадения тегов. Таким образом, вы можем вместо символа "_" подставлять совершенно любые теги, однако главное - чтобы функция поддерживала данный тег.


    Hash

    Теперь давайте рассмотрим алгоритм хеширования, построенный полностью на этапе пре-компиляции. Однако большой минус такой реализации - разные регистры.
    PHP код:
    #define hash_alg(%0) h@(%0,END,END)(0)
    #define h@(%0,%1)(%8) h@%0(%1)(%8)

    #define [email protected](%1)(%8) %8
    #define [email protected](%1)(%8) h@(%1)(%8 + 158)
    #define [email protected](%1)(%8) h@(%1)(%8 + 682)
    #define [email protected](%1)(%8) h@(%1)(%8 + 333) 
    Итак, давайте рассмотрим каждую строчку по отдельности:
    1. Первая строка данного кода определяет начальную точку.
    2. Вторая строка содержит макрос, отделяющий один аргумент от остальных.
    3. Четвёртая строчка необходима для вывода результата, т.к. это последняя точка этого алгоритма.
    4. Пятая строка содержит алгоритм вычисления только для символа a. В последующих же строках, алгоритм в вторых скобках может изменяться.
      Код:
      #define [email protected](%1)(%8) h@(%1)(%8 + 682)

    Примечание: все цифры - 158, 682, 333 - придуманы, вместо них может стоять какой-либо алгоритм, либо цифра.

    Теперь необходимо вызвать макро-функцию, например, в printf для вывода результата:
    PHP код:
    main()
    {
        
    printf("%d"hash_alg(a,b,c,c,b,a));

    Результатом будет число 2346, т.к. 0 + 158 + 682 + 333 + 333 + 682 + 158 = 2346


    Сложные алгоритмы

    Отличие минимальной сложности от максимальной является более уникальный и сложный алгоритм, которые конструируется только для определённой библиотеки. Такие алгоритмы немного напоминают обфускацию, что сильно уменьшает читаемость кода.

    Пример:
    PHP код:
    // Точка входа. <> необходим при последующего анализа кода.
    #define dialog%1(%2) DPARSE(%1<>%2)

    // Извлекаем содержимое из <>, если оно там присутствует.
    #define DPARSE(%1<%3>%2) forward pdR_%1(playerid,response,listitem,inputtext[]);public pdR_%1(playerid,response,listitem,inputtext[]){return [email protected](%3,%1,response)(%2)

    // Тоже самое, что и первый пример в этой статье, т.е. это отсеивание. Разделитель "$", в других библиотеках может быть "|||" или "||||" и т.п.
    #define [email protected](%3,%1,%4)(%2)                _:[email protected]:[email protected]:%1$%2$%3$%4$

    // Если содержимое в <> отсутствует, значит переопределяем по данному алгоритму:
    #define [email protected]:[email protected]:%1$%2$$%4$       _dR_%1([email protected]:%2[]$); } stock _dR_%1(%2) 

    // Иначе, если %2 содержит <>, то в пользовательском коде <...> присутствует. Кроме того, это сделано для отделения <> от аргументов.
    #define [email protected]:%1$<>%2$%3$%4$        (_:(%3)==%4) ? _dR_%1([email protected]:%2[]$) : 0; } stock _dR_%1(%2)

    // Данные строки нужны для избавления от пробела. Если бы этого не было, то мы бы получили ошибку.
    #define pdR_%0\32;%1(%2) pdR_%0%1(%2)
    #define _dR_%0\32;%1(%2) _dR_%0%1(%2)

    // Данная строка уничтожает [] в строке для избежания ошибок, т.к. при вызове функции ненужно указывать квадратные скобки.
    #define [email protected]:%2[%3]%0$) %2) 
    Данный код переопределяет псевдо-оператор dialog в компилируемый код. Давайте рассмотрим результат выполнения данного кода:

    PHP код:
    forward pdR_PlayerReg(playerid,response,listitem,inputtext[]);
    public 
    pdR_PlayerReg(playerid,response,listitem,inputtext[])
    {
        return 
    _:D@A0:(_:(true)==response)?_dR_PlayerReg(playeridinputtext):0;
    }
    stock _dR_PlayerReg(playeridinputtext[])
    {
        
    printf("Your text: %s"inputtext);

    Даже, не компилируя, можно определить работоспособность кода.


    Итог

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


    Примеры лучших работ


    Если у вас появились какие-то вопросы, или вы думаете, что я что-то забыл, напишите об этом.

    Автор: VVWVV
    Исключительно для pro-pawn.ru

    Копирование данной статьи на других ресурсах без разрешения автора запрещено!
    Последний раз редактировалось VVWVV; 11.12.2016 в 03:25.

  2. #2
    Аватар для DeimoS
    Модератор?

    Статус
    Оффлайн
    Регистрация
    27.01.2014
    Адрес
    Восточный Мордор
    Сообщений
    3,356
    Репутация:
    1338 ±
    Расписано всё хорошо, но не хватает словесных примеров того, для чего могут пригодиться препроцессорные парсеры. И, как подсказывает опыт, большая часть из скриптеров просто не поймёт твою статью =)
    Связаться со мной можно в личных сообщениях этой группы

    Широко известно, что идеи стоят 0.8333 цента каждая (исходя из рыночной цены 10 центов за дюжину).
    Великих идей полно, на них нет спроса.
    Воплощение идеи в законченную игру требует долгой работы,
    таланта, терпения и креативности, не говоря уж о затратах денег, времени и ресурсов.
    Предложить идею просто, воплотить – вот в чём проблема

    Steve Pavlina

  3. #3
    Аватар для VVWVV
    Проверенный

    Статус
    Оффлайн
    Регистрация
    09.07.2015
    Сообщений
    548
    Репутация:
    250 ±
    Цитата Сообщение от DeimoS Посмотреть сообщение
    Расписано всё хорошо, но не хватает словесных примеров того, для чего могут пригодиться препроцессорные парсеры. И, как подсказывает опыт, большая часть из скриптеров просто не поймёт твою статью =)
    Как минимум, я всего-лишь показал, что это существует, а если будут вопросы - отвечу. Словесные примеры будут. Кроме того, буду пополнять каждый раз тему примерами, а также проводить анализ.
    Последний раз редактировалось VVWVV; 10.12.2016 в 14:05.

  4. #4
    Аватар для VVWVV
    Проверенный

    Статус
    Оффлайн
    Регистрация
    09.07.2015
    Сообщений
    548
    Репутация:
    250 ±
    Переписал статью, читайте.

 

 

Информация о теме

Пользователи, просматривающие эту тему

Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •