Добро пожаловать на Pro Pawn - Портал о PAWN-скриптинге.
Страница 1 из 5 1 2 3 ... ПоследняяПоследняя
Показано с 1 по 10 из 43
  1. #1
    Аватар для VVWVV
    ?

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

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

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

    Введение

    Препроцессорные парсеры – это конструкции из препроцессорных директив 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 h@END(%1)(%8) %8
    #define h@a(%1)(%8) h@(%1)(%8 + 158)
    #define h@b(%1)(%8) h@(%1)(%8 + 682)
    #define h@c(%1)(%8) h@(%1)(%8 + 333) 
    Итак, давайте рассмотрим каждую строчку по отдельности:
    1. Первая строка данного кода определяет начальную точку.
    2. Вторая строка содержит макрос, отделяющий один аргумент от остальных.
    3. Четвёртая строчка необходима для вывода результата, т.к. это последняя точка этого алгоритма.
    4. Пятая строка содержит алгоритм вычисления только для символа a. В последующих же строках, алгоритм в вторых скобках может изменяться.
      Код:
      #define h@b(%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 g@R(%3,%1,response)(%2)

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

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

    // Иначе, если %2 содержит <>, то в пользовательском коде <...> присутствует. Кроме того, это сделано для отделения <> от аргументов.
    #define D@A1:%1$<>%2$%3$%4$        (_:(%3)==%4) ? _dR_%1(D@AN:%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 D@AN:%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. 5 пользователя(ей) сказали cпасибо:
    #Djuga (17.07.2018) Geebrox (16.02.2018) Nexius_Tailer (01.02.2018) pawnoholic (16.07.2018) ziggi (31.01.2018)
  3. #2
    Аватар для DeimoS
    Модератор?

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

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

    Steve Pavlina

  4. #3
    Аватар для VVWVV
    ?

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

  5. #4
    Аватар для VVWVV
    ?

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

  6. #5
    Аватар для Anve
    Пользователь

    Статус
    Оффлайн
    Регистрация
    04.01.2018
    Сообщений
    15
    Репутация:
    0 ±
    Есть идеи о том, как можно использовать больше, чем 2 парсера? Поскольку тогда получается тэги накладываются друг на друга.

  7. #6
    Аватар для VVWVV
    ?

    Статус
    Оффлайн
    Регистрация
    09.07.2015
    Сообщений
    731
    Репутация:
    353 ±
    Цитата Сообщение от Anve Посмотреть сообщение
    Есть идеи о том, как можно использовать больше, чем 2 парсера? Поскольку тогда получается тэги накладываются друг на друга.
    Можно пример? Можно же сделать уникальные теги.

  8. #7
    Аватар для Anve
    Пользователь

    Статус
    Оффлайн
    Регистрация
    04.01.2018
    Сообщений
    15
    Репутация:
    0 ±
    Цитата Сообщение от VVWVV Посмотреть сообщение
    Можно пример? Можно же сделать уникальные теги.
    Допустим
    PHP код:
    #define TEST: TEST_0:TEST_1:TEST_2:
    #define TEST_2: // В этом случае будет 2 тэга: TEST_0:TEST_1: 

  9. #8
    Аватар для VVWVV
    ?

    Статус
    Оффлайн
    Регистрация
    09.07.2015
    Сообщений
    731
    Репутация:
    353 ±
    Цитата Сообщение от Anve Посмотреть сообщение
    Допустим
    PHP код:
    #define TEST: TEST_0:TEST_1:TEST_2:
    #define TEST_2: // В этом случае будет 2 тэга: TEST_0:TEST_1: 
    Можно сделать вот так:
    PHP код:
    #define test(%1) (_:TEST_0:TEST_1:TEST_2:$%1)
    #define TEST_0:%8$%1)
    #define TEST_1:%8$%1)
    #define TEST_2:%8$%1) 

  10. #9
    Аватар для Anve
    Пользователь

    Статус
    Оффлайн
    Регистрация
    04.01.2018
    Сообщений
    15
    Репутация:
    0 ±
    Как это использовать? Я для примера сделал так
    PHP код:
    test(1
    И в листинге было следующее:
    PHP код:
    (_

  11. #10
    Аватар для VVWVV
    ?

    Статус
    Оффлайн
    Регистрация
    09.07.2015
    Сообщений
    731
    Репутация:
    353 ±
    Цитата Сообщение от Anve Посмотреть сообщение
    Как это использовать? Я для примера сделал так
    PHP код:
    test(1
    И в листинге было следующее:
    PHP код:
    (_
    Пример.
    PHP код:
    #define TEST_0:%8$%1[%2]) %8$%1+%2) 

 

 
Страница 1 из 5 1 2 3 ... ПоследняяПоследняя

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

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

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

Ваши права

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