Просмотр полной версии : [Урок] Препроцессорные парсеры
В данной статье рассмотрим препроцессорные парсеры. Кроме того, в статье приведены большое количество примеров с пояснениями, каждая строка которых полностью аргументирована. Статья рассчитана на уже более-менее опытных программистов.
Введение
Препроцессорные парсеры – это конструкции из препроцессорных директив define, которые необходимы для определения отрывка кода по заданному шаблону. Подобные конструкции можно рассматривать, как более продвинутые манипуляции с компилятором.
Именно данные парсеры послужили основой для множества лучших библиотек. Например, всеми любимая библиотека foreach, которая образует новый псевдо-оператор foreach со своим синтаксисом и т.д.
Про алгоритмы, использованные в библиотеках, можно говорить очень долго, но суть всего этого одна – они анализируют код, отсеивают ненужные части, а потом переопределяют уже существующий код на этапе пре-компиляции. Это чем-то похоже на метапрограммирование.
Рассмотрим пример:
#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>%0[%3] в строке. Заметим, что между символом ">" и "[" стоит нуль. Данный нуль необходим для определения пробелов между данными символами, т.е. для написания подобным образом:
SOME_PARSE:5 <8> [10]
Третья - альтернатива. То есть, если вторая строка не подходит по шаблону то значит, что альтернативная для этого только третья.
При использовании флага -l при компиляции, создаётся файл с расширение ".lst", который содержит результат работы препроцессора. Давайте рассмотрим результат выше приведенного кода:
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
Теперь давайте рассмотрим алгоритм хеширования, построенный полностью на этапе пре-компиляции. Однако большой минус такой реализации - разные регистры.
#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)
Итак, давайте рассмотрим каждую строчку по отдельности:
Первая строка данного кода определяет начальную точку.
Вторая строка содержит макрос, отделяющий один аргумент от остальных.
Четвёртая строчка необходима для вывода результата, т.к. это последняя точка этого алгоритма.
Пятая строка содержит алгоритм вычисления только для символа a. В последующих же строках, алгоритм в вторых скобках может изменяться.
#define h@b(%1)(%8) h@(%1)(%8 + 682)
Примечание: все цифры - 158, 682, 333 - придуманы, вместо них может стоять какой-либо алгоритм, либо цифра.
Теперь необходимо вызвать макро-функцию, например, в printf для вывода результата:
main()
{
printf("%d", hash_alg(a,b,c,c,b,a));
}
Результатом будет число 2346, т.к. 0 + 158 + 682 + 333 + 333 + 682 + 158 = 2346
Сложные алгоритмы
Отличие минимальной сложности от максимальной является более уникальный и сложный алгоритм, которые конструируется только для определённой библиотеки. Такие алгоритмы немного напоминают обфускацию (https://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%84%D1%83%D1%81%D0%BA%D0%B0%D1%86%D0%B8%D1%8F_(%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%BD%D0%BE%D0%B5_%D0%BE%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D0%B5)), что сильно уменьшает читаемость кода.
Пример:
// Точка входа. <> необходим при последующего анализа кода.
#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 в компилируемый код. Давайте рассмотрим результат выполнения данного кода:
forward pdR_PlayerReg(playerid,response,listitem,inputtext[]);
public pdR_PlayerReg(playerid,response,listitem,inputtext[])
{
return _:D@A0:(_:(true)==response)?_dR_PlayerReg(playerid, inputtext):0;
}
stock _dR_PlayerReg(playerid, inputtext[])
{
printf("Your text: %s", inputtext);
}
Даже, не компилируя, можно определить работоспособность кода.
Итог
Препроцессорные парсеры позволяют сделать код более гибким, менее затратным на написание, а также более читаемым. Таким образом, можно создать собственный синтаксис для библиотек.
Примеры лучших работ
code-parse.inc (https://github.com/Y-Less/code-parse.inc) (Автор: Y_less)
YSI (https://github.com/Misiur/YSI-Includes) (Автор: Y_less)
md-sort.inc (https://github.com/oscar-broman/md-sort/blob/master/md-sort.inc) (Автор: Slice)
SmartCMD (https://github.com/YashasSamaga/SmartCMD) (Автор: YashasSamaga)
Если у вас появились какие-то вопросы, или вы думаете, что я что-то забыл, напишите об этом.
Автор: VVWVV
Исключительно для pro-pawn.ru
Копирование данной статьи на других ресурсах без разрешения автора запрещено!
Расписано всё хорошо, но не хватает словесных примеров того, для чего могут пригодиться препроцессорные парсеры. И, как подсказывает опыт, большая часть из скриптеров просто не поймёт твою статью =)
Расписано всё хорошо, но не хватает словесных примеров того, для чего могут пригодиться препроцессорные парсеры. И, как подсказывает опыт, большая часть из скриптеров просто не поймёт твою статью =)
Как минимум, я всего-лишь показал, что это существует, а если будут вопросы - отвечу. Словесные примеры будут. Кроме того, буду пополнять каждый раз тему примерами, а также проводить анализ.
Переписал статью, читайте.
Есть идеи о том, как можно использовать больше, чем 2 парсера? Поскольку тогда получается тэги накладываются друг на друга.
Есть идеи о том, как можно использовать больше, чем 2 парсера? Поскольку тогда получается тэги накладываются друг на друга.
Можно пример? Можно же сделать уникальные теги.
Можно пример? Можно же сделать уникальные теги.
Допустим
#define TEST: TEST_0:TEST_1:TEST_2:
#define TEST_2: // В этом случае будет 2 тэга: TEST_0:TEST_1:
Допустим
#define TEST: TEST_0:TEST_1:TEST_2:
#define TEST_2: // В этом случае будет 2 тэга: TEST_0:TEST_1:
Можно сделать вот так:
#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)
Как это использовать? Я для примера сделал так
test(1)
И в листинге было следующее:
(_:
Как это использовать? Я для примера сделал так
test(1)
И в листинге было следующее:
(_:
Пример.
#define TEST_0:%8$%1[%2]) %8$%1+%2)
Хорошо, понял, но что на счёт создания переменных?
Хорошо, понял, но что на счёт создания переменных?
При чём тут переменные..
При чём тут переменные..
Просто я хотел с помощью парсеров создавать разные переменные.
Просто я хотел с помощью парсеров создавать разные переменные.
Можно. Обычное объявление переменных.
Можно. Обычное объявление переменных.
Я в курсе, я про то, как можно использовать больше 2-х парсеров для создания переменных, т.к. способ выше выдаёт ошибку(что логично).
Я в курсе, я про то, как можно использовать больше 2-х парсеров для создания переменных, т.к. способ выше выдаёт ошибку(что логично).
Никак.
pawnoholic
16.06.2018, 19:35
Подскажите как эту мощь интегрировать в мод, что то приглянулся мне такой вариант именования переменных, я вставлял это, как есть, в один из заголовочных файлов, но тут либо где то допущена ошибка, либо чего то еще не хватает, потому что скомпилировать мод не удается.
By Y-Less:
#define OO_TYPE(%6,%7)%0[%1]%2. (_:@vb:@va:%6:%7@%0[%1]%2[E_%6_%0:@vw:@vx:@vy:@vz:@vs:$E_%6_%0_]
// First move the ] out as far as required.
#define @vw:%9$%0]%1[ @vv:@vu:@vt:@vr:@vq$%0%1][
#define @vx:%9$%0]%1; @vv:@vu:@vt:@vr:@vq$%0%1];
#define @vy:%9$%0]%1) @vv:@vu:@vt:@vr:@vq$%0%1])
#define @vz:%9$%0]%1, @vv:@vu:@vt:@vr:@vq$%0%1],
#define @vs:%9$%0]%1: @vv:@vu:@vt:@vr:@vq$%0%1]:
// Second, move it in again to constrain the contents. We don't need to scan
// for `[` again since it was the first one looked for above and so can't
// possibly be within the square brackets. This is good, because scanning for
// `[` from within `[]` is problematic.
#define @vv:%9$%0;%1] %9$%0];%1
#define @vu:%9$%0)%1] %9$%0])%1
#define @vt:%9$%0,%1] %9$%0],%1
#define @vr:%9$%0:%1] %9$%0]:%1
#define @vq$
#define Player. OO_TYPE(PLAYER,Player)
#define Vehicle. OO_TYPE(VEHICLE,Vehicle)
Player.Vehicle[playerid].pos;more
Player.Vehicle[playerid].pos[0];more
Player.Vehicle[playerid].pos,more
Player.Vehicle[playerid].pos[0],more
Player.Vehicle[playerid].pos[0]more
Player.Vehicle[playerid].pos:more
Player.Vehicle[playerid].pos[0]:more
Player.Vehicle[playerid][vehicleid].pos;more
Player.Vehicle[playerid][vehicleid].pos[0];more
Player.Vehicle[playerid][vehicleid].pos,more
Player.Vehicle[playerid][vehicleid].pos[0],more
Player.Vehicle[playerid][vehicleid].pos[0]more
Player.Vehicle[playerid][vehicleid].pos:more
Player.Vehicle[playerid][vehicleid].pos[0]:more
Извините, что не в ту тему, думал тут про препроцессорные парсеры :)
Подскажите как эту мощь интегрировать в мод, что то приглянулся мне такой вариант именования переменных, я вставлял это, как есть, в один из заголовочных файлов, но тут либо где то допущена ошибка, либо чего то еще не хватает, потому что скомпилировать мод не удается.
By Y-Less:
#define OO_TYPE(%6,%7)%0[%1]%2. (_:@vb:@va:%6:%7@%0[%1]%2[E_%6_%0:@vw:@vx:@vy:@vz:@vs:$E_%6_%0_]
// First move the ] out as far as required.
#define @vw:%9$%0]%1[ @vv:@vu:@vt:@vr:@vq$%0%1][
#define @vx:%9$%0]%1; @vv:@vu:@vt:@vr:@vq$%0%1];
#define @vy:%9$%0]%1) @vv:@vu:@vt:@vr:@vq$%0%1])
#define @vz:%9$%0]%1, @vv:@vu:@vt:@vr:@vq$%0%1],
#define @vs:%9$%0]%1: @vv:@vu:@vt:@vr:@vq$%0%1]:
// Second, move it in again to constrain the contents. We don't need to scan
// for `[` again since it was the first one looked for above and so can't
// possibly be within the square brackets. This is good, because scanning for
// `[` from within `[]` is problematic.
#define @vv:%9$%0;%1] %9$%0];%1
#define @vu:%9$%0)%1] %9$%0])%1
#define @vt:%9$%0,%1] %9$%0],%1
#define @vr:%9$%0:%1] %9$%0]:%1
#define @vq$
#define Player. OO_TYPE(PLAYER,Player)
#define Vehicle. OO_TYPE(VEHICLE,Vehicle)
Player.Vehicle[playerid].pos;more
Player.Vehicle[playerid].pos[0];more
Player.Vehicle[playerid].pos,more
Player.Vehicle[playerid].pos[0],more
Player.Vehicle[playerid].pos[0]more
Player.Vehicle[playerid].pos:more
Player.Vehicle[playerid].pos[0]:more
Player.Vehicle[playerid][vehicleid].pos;more
Player.Vehicle[playerid][vehicleid].pos[0];more
Player.Vehicle[playerid][vehicleid].pos,more
Player.Vehicle[playerid][vehicleid].pos[0],more
Player.Vehicle[playerid][vehicleid].pos[0]more
Player.Vehicle[playerid][vehicleid].pos:more
Player.Vehicle[playerid][vehicleid].pos[0]:more
Покажите код полностью, ибо макросы правильные. Возможно, что проблема в объявлении массива.
pawnoholic
16.06.2018, 21:55
Покажите код полностью, ибо макросы правильные. Возможно, что проблема в объявлении массива.
Если мне не изменяет память, то:
enum E_PLAYER_Vehicle
{
Float:E_PLAYER_Vehicle_x,
Float:E_PLAYER_Vehicle_y,
Float:E_PLAYER_Vehicle_z
};
new PlayerVehicle[MAX_PLAYERS_VEHICLES][E_PLAYER_Vehicle];
Собственно, от куда все это произошло: ссылка (https://github.com/Y-samp/Y-Core/commit/ebf825bea72620acc77a2114c9fc715ce6175bc4#comments)
Если мне не изменяет память, то:
enum E_PLAYER_Vehicle
{
Float:E_PLAYER_Vehicle_x,
Float:E_PLAYER_Vehicle_y,
Float:E_PLAYER_Vehicle_z
};
new PlayerVehicle[MAX_PLAYERS_VEHICLES][E_PLAYER_Vehicle];
Собственно, от куда все это произошло: ссылка (https://github.com/Y-samp/Y-Core/commit/ebf825bea72620acc77a2114c9fc715ce6175bc4#comments)
Вот как это объявлено тут (https://github.com/Y-samp/Y-Core/blob/ebf825bea72620acc77a2114c9fc715ce6175bc4/gamemodes/Y/player/vehicle/header.inc#L14-L21).
pawnoholic
16.06.2018, 23:54
Вот как это объявлено тут (https://github.com/Y-samp/Y-Core/blob/ebf825bea72620acc77a2114c9fc715ce6175bc4/gamemodes/Y/player/vehicle/header.inc#L14-L21).
Я знаю, я видел это, но там другой вариант (https://github.com/Y-samp/Y-Core/blob/aca42da9a604dccc394b7dc7fe331b4198a7946e/gamemodes/Y/core/header.inc#L10-L12), более к классическому стилю.
Daniel_Cortez
17.06.2018, 18:07
Извините, что не в ту тему, думал тут про препроцессорные парсеры :)
Ничего страшного, переместил обсуждение в нужную тему.
pawnoholic
20.06.2018, 00:49
Пришло время снова попробовать.
Код:
#define Player. OO_TYPE(PLAYER,Player)
enum E_PLAYER_Vehicle
{
Float:E_PLAYER_Vehicle_x,
Float:E_PLAYER_Vehicle_y,
Float:E_PLAYER_Vehicle_z,
Float:E_PLAYER_Vehicle_a
};
new Player@Vehicle[MAX_PLAYERS][E_PLAYER_Vehicle];
main() {
Player.Vehicle[0].x = 10.0;
}
Результат:
(error) must be lvalue (non-constant)
(error) invalid expression, assumed zero
(warning) expression has no effect
Я думаю проблема скорее в отсутствии макросов для @vb: и @va:
Я их нашел, но не думаю что подходят к этому варианту, либо Y-Less забыл про них, либо они не нужны и я что то не так делаю.
#define OO_TYPE(%6,%7)%0[%1] (_:@vb:@va:%6:%7@%0[%1]
#define @va:%6:%7@%0[%1][@%2] %7%0[%1])[E_%6_%0_%2]
#define @vb:@va:%6:%7@%0[%1][%2][@%3] %7%0[%1])[%2][E_%6_%0_%3]
Скинь весь код, что у тебя получился (и макросы, и то, как ты пытаешься их использовать)
pawnoholic
20.06.2018, 13:46
// by Y-Less
#define OO_TYPE(%6,%7)%0[%1]%2. (_:@vb:@va:%6:%7@%0[%1]%2[E_%6_%0:@vw:@vx:@vy:@vz:@vs:$E_%6_%0_]
#define @va:%6:%7@%0[%1][@%2] %7%0[%1])[E_%6_%0_%2]
#define @vb:@va:%6:%7@%0[%1][%2][@%3] %7%0[%1])[%2][E_%6_%0_%3]
// First move the ] out as far as required.
#define @vw:%9$%0]%1[ @vv:@vu:@vt:@vr:@vq$%0%1][
#define @vx:%9$%0]%1; @vv:@vu:@vt:@vr:@vq$%0%1];
#define @vy:%9$%0]%1) @vv:@vu:@vt:@vr:@vq$%0%1])
#define @vz:%9$%0]%1, @vv:@vu:@vt:@vr:@vq$%0%1],
#define @vs:%9$%0]%1: @vv:@vu:@vt:@vr:@vq$%0%1]:
// Second, move it in again to constrain the contents. We don't need to scan
// for `[` again since it was the first one looked for above and so can't
// possibly be within the square brackets. This is good, because scanning for
// `[` from within `[]` is problematic.
#define @vv:%9$%0;%1] %9$%0];%1
#define @vu:%9$%0)%1] %9$%0])%1
#define @vt:%9$%0,%1] %9$%0],%1
#define @vr:%9$%0:%1] %9$%0]:%1
#define @vq$
#define Player. OO_TYPE(PLAYER,Player)
enum E_PLAYER_Vehicle
{
Float:E_PLAYER_Vehicle_x,
Float:E_PLAYER_Vehicle_y,
Float:E_PLAYER_Vehicle_z,
Float:E_PLAYER_Vehicle_a
};
new PlayerVehicle[MAX_PLAYERS][E_PLAYER_Vehicle];
public OnPlayerConnect(playerid)
{
Player.Vehicle[playerid].x = 0.0;
Player.Vehicle[playerid].y = 0.0;
Player.Vehicle[playerid].z = 0.0;
Player.Vehicle[playerid].a = 0.0;
return 1;
}
1) Массив должен быть назван так: Player@Vehicle.
2) Данный парсер не рассчитан на какие-либо операции, поскольку нет таковых условий, поэтому знак равно, да и в общем-то любые знаки записываются в квадратные скобки.
Вот результат работы препроцессора:
enum E_PLAYER_Vehicle
{
Float:E_PLAYER_Vehicle_x,
Float:E_PLAYER_Vehicle_y,
Float:E_PLAYER_Vehicle_z,
Float:E_PLAYER_Vehicle_a
};
new Player@Vehicle[MAX_PLAYERS][E_PLAYER_Vehicle];
public OnPlayerConnect(playerid)
{
(_:@vb:@va:PLAYER:Player@Vehicle[playerid][E_PLAYER_Vehicle:@vw:@vv:@vu:@vt:@vr:E_PLAYER_Vehicle_x = 0.0];
(_:@vb:@va:PLAYER:Player@Vehicle[playerid][E_PLAYER_Vehicle:@vw:@vv:@vu:@vt:@vr:E_PLAYER_Vehicle_y = 0.0];
(_:@vb:@va:PLAYER:Player@Vehicle[playerid][E_PLAYER_Vehicle:@vw:@vv:@vu:@vt:@vr:E_PLAYER_Vehicle_z = 0.0];
(_:@vb:@va:PLAYER:Player@Vehicle[playerid][E_PLAYER_Vehicle:@vw:@vv:@vu:@vt:@vr:E_PLAYER_Vehicle_a = 0.0];
return 1;
}
pawnoholic
15.07.2018, 22:09
Уже очень много времени не могу понять по какому принципу пишутся препроцессорные парсеры, подскажите как можно реализовать вот такой вызов этого макроса:
SendClientMessage(playerid, COLOR(RED,500), "Добро пожаловать!"); // Сейчас
SendClientMessage(playerid, COLOR(RED, 500), "Добро пожаловать!"); // Не возможно поставить пробел между аргументами
SendClientMessage(playerid, COLOR(RED), "Добро пожаловать!"); // Вызов функции без второго аргумента, который по умолчанию заменяется на COLOR@RED@500
Код:
#define COLOR@RED@100<%1,%2> (%1FFCDD2%2)
#define COLOR@RED@200<%1,%2> (%1EF9A9A%2)
#define COLOR@RED@300<%1,%2> (%1E57373%2)
#define COLOR@RED@400<%1,%2> (%1EF5350%2)
#define COLOR@RED@500<%1,%2> (%1F44336%2)
#define COLOR@RED@600<%1,%2> (%1E53935%2)
#define COLOR@RED@700<%1,%2> (%1D32F2F%2)
#define COLOR@RED@800<%1,%2> (%1C62828%2)
#define COLOR@RED@900<%1,%2> (%1B71C1C%2)
#define COLOR(%0,%1) (COLOR@%0@%1<0x,AA>)
Уже очень много времени не могу понять по какому принципу пишутся препроцессорные парсеры, подскажите как можно реализовать вот такой вызов этого макроса:
SendClientMessage(playerid, COLOR(RED,500), "Добро пожаловать!"); // Сейчас
SendClientMessage(playerid, COLOR(RED, 500), "Добро пожаловать!"); // Не возможно поставить пробел между аргументами
SendClientMessage(playerid, COLOR(RED), "Добро пожаловать!"); // Вызов функции без второго аргумента, который по умолчанию заменяется на COLOR@RED@500
Код:
#define COLOR@RED@100<%1,%2> (%1FFCDD2%2)
#define COLOR@RED@200<%1,%2> (%1EF9A9A%2)
#define COLOR@RED@300<%1,%2> (%1E57373%2)
#define COLOR@RED@400<%1,%2> (%1EF5350%2)
#define COLOR@RED@500<%1,%2> (%1F44336%2)
#define COLOR@RED@600<%1,%2> (%1E53935%2)
#define COLOR@RED@700<%1,%2> (%1D32F2F%2)
#define COLOR@RED@800<%1,%2> (%1C62828%2)
#define COLOR@RED@900<%1,%2> (%1B71C1C%2)
#define COLOR(%0,%1) (COLOR@%0@%1<0x,AA>)
Делаем две проверки на символ ','
#define COLOR@RED@100<%1,%2> (%1FFCDD2%2)
#define COLOR@RED@200<%1,%2> (%1EF9A9A%2)
#define COLOR@RED@300<%1,%2> (%1E57373%2)
#define COLOR@RED@400<%1,%2> (%1EF5350%2)
#define COLOR@RED@500<%1,%2> (%1F44336%2)
#define COLOR@RED@600<%1,%2> (%1E53935%2)
#define COLOR@RED@700<%1,%2> (%1D32F2F%2)
#define COLOR@RED@800<%1,%2> (%1C62828%2)
#define COLOR@RED@900<%1,%2> (%1B71C1C%2)
#define COLOR(%1) (_:clr@aM:clr@aN:$%1)
#define clr@aM:%8$%0,%1) clr@rS:COLOR@%0@%1<0x,AA>)
#define clr@aN:%8$%0) clr@rS:COLOR@%0@100<0x,AA>) // 100 - default value.
#define clr@rS:%1\32;%0) clr@rS:%1%0)
COLOR(RED, 800)
pawnoholic
15.07.2018, 23:11
SendClientMessage(playerid, COLOR(RED), "Добро пожаловать!");
undefined symbol "@COLOR@RED"
invalid expression, assumed zero
array must be indexed (variable "-unknown-")
too many error messages on one line
http://ihost.pro-pawn.ru/image.php?di=SMF6
pawnoholic
16.07.2018, 00:07
new color = COLOR(RED);
SendClientMessage(playerid, color, "Добро пожаловать!");
Да, таким методом компиляция проходит нормально.
SendClientMessage(playerid, COLOR(RED), "Добро пожаловать!");
А если вызывать вот так, то компиляция проходит с ошибкой
-l:
SendClientMessage(playerid, (_:clr@rS:@COLOR@RED)@"Добро пожаловать!"<0x,AA>);
new color = COLOR(RED);
SendClientMessage(playerid, color, "Добро пожаловать!");
Да, таким методом компиляция проходит нормально.
SendClientMessage(playerid, COLOR(RED), "Добро пожаловать!");
А если вызывать вот так, то компиляция проходит с ошибкой
-l:
SendClientMessage(playerid, (_:clr@rS:@COLOR@RED)@"Добро пожаловать!"<0x,AA>);
Опс.. Да...
Попробуй так:
#define COLOR@RED@100<%1,%2> (%1FFCDD2%2)
#define COLOR@RED@200<%1,%2> (%1EF9A9A%2)
#define COLOR@RED@300<%1,%2> (%1E57373%2)
#define COLOR@RED@400<%1,%2> (%1EF5350%2)
#define COLOR@RED@500<%1,%2> (%1F44336%2)
#define COLOR@RED@600<%1,%2> (%1E53935%2)
#define COLOR@RED@700<%1,%2> (%1D32F2F%2)
#define COLOR@RED@800<%1,%2> (%1C62828%2)
#define COLOR@RED@900<%1,%2> (%1B71C1C%2)
#define COLOR(%1) (_:clr@aM:clr@aN:$%1,)
#define clr@aM:%8$%0,%1,) clr@rS:COLOR@%0@%1<0x,AA>)
#define clr@aN:%8$%0,) clr@rS:COLOR@%0@100<0x,AA>) // 100 - default value.
#define clr@rS:%1\32;%0,) clr@rS:%1%0,)
COLOR(RED, 800)
pawnoholic
16.07.2018, 00:54
#define COLOR(%1) (_:clr@aM:clr@aN:$%1,)
#define clr@aM:%8$%0,%1,) clr@rS:COLOR@%0@%1<0x,AA>)
#define clr@aN:%8$%0,) clr@rS:COLOR@%0@100<0x,AA>) // 100 - default value.
#define clr@rS:%1\32;%0,) clr@rS:%1%0,)
Спасибо, это работает.
pawnoholic
16.07.2018, 02:48
Решил немного модифицировать и добавить третий аргумент, но теперь перед вторым и третьим параметром не убирается пробел, пробовал самостоятельно разрешить этот пробел, но так и не понял как это сделать:
#define COLOR(%1) (_:COLOR@A:COLOR@B:COLOR@C:$%1,)
#define COLOR@A:%8$%0,%1,%2,) COLOR@S:@COLOR@%0@%1<0x,%2>)
#define COLOR@B:%8$%0,%1,) COLOR@S:@COLOR@%0@%1<0x,AA>)
#define COLOR@C:%8$%0,) COLOR@S:@COLOR@%0@500<0x,AA>)
#define COLOR@S:%1\32;%0,) COLOR@S:%1%0,)
Результат:
(_:COLOR@S:@COLOR@RED@ 500<0x, AA>)
Необходимо:
(_:COLOR@S:@COLOR@RED@500<0x,AA>) -> (_:COLOR@S:(0xF44336AA))
Решил немного модифицировать и добавить третий аргумент, но теперь перед вторым и третьим параметром не убирается пробел, пробовал самостоятельно разрешить этот пробел, но так и не понял как это сделать:
#define COLOR(%1) (_:COLOR@A:COLOR@B:COLOR@C:$%1,)
#define COLOR@A:%8$%0,%1,%2,) COLOR@S:@COLOR@%0@%1<0x,%2>)
#define COLOR@B:%8$%0,%1,) COLOR@S:@COLOR@%0@%1<0x,AA>)
#define COLOR@C:%8$%0,) COLOR@S:@COLOR@%0@500<0x,AA>)
#define COLOR@S:%1\32;%0,) COLOR@S:%1%0,)
Результат:
(_:COLOR@S:@COLOR@RED@ 500<0x, AA>)
Необходимо:
(_:COLOR@S:@COLOR@RED@500<0x,AA>) -> (_:COLOR@S:(0xF44336AA))
%8$ забыли в COLOR@S.
pawnoholic
16.07.2018, 10:52
%8$ забыли в COLOR@S.
Как то без изменений, пробовал вот так
#define COLOR@S:%8$%1\32;%0,) COLOR@S:%1%0,)
И вот так
#define COLOR@S:%1\32;%8$%0,) COLOR@S:%1%0,)
Как то без изменений, пробовал вот так
#define COLOR@S:%8$%1\32;%0,) COLOR@S:%1%0,)
И вот так
#define COLOR@S:%1\32;%8$%0,) COLOR@S:%1%0,)
#define COLOR(%1) (_:COLOR@A:COLOR@B:COLOR@C:$%1,)
#define COLOR@A:%8$%0,%1,%2,) COLOR@S:@COLOR@%0@%1<0x,%2>)
#define COLOR@B:%8$%0,%1,) COLOR@S:@COLOR@%0@%1<0x,AA>)
#define COLOR@C:%8$%0,) COLOR@S:@COLOR@%0@500<0x,AA>)
#define COLOR@S:%1\32;%0,%6) COLOR@S:%1%0,%6)
pawnoholic
16.07.2018, 16:58
Спасибо, только еще пробел остался в таком варианте использования.
new color = (_:COLOR@S:(0xF44336 AA));
А можно еще как то модифицировать, так чтобы можно было и такой вариант вызвать или для такого варианта лучше новое правило сделать?
#define @COLOR@BLACK<%1,%2> (%1000000%2)
#define @COLOR@WHITE<%1,%2> (%1FFFFFF%2)
Допустим, есть макрос такого вида
#define SomeFunc1(%0,%1)
"%0" и "%1" - целочисленные переменные. Возможно ли убрать все пробелы между запятой и "%1", не добавляя, при этом, никаких символов или тегов?
В целом, задача заключается в том, чтоб переместить "%1" в начало
#define SomeFunc1(%0,%1) %1 = SomeFunc2(%0)
И если прописать в коде, например, так:
SomeFunc1(var1, var2);
То компилятор ругнётся на кривую табуляцию, так как "var2" перенесётся в начало вместе с пробелом. Собственно, от этого предупреждения и нужно избавиться.
Допустим, есть макрос такого вида
#define SomeFunc1(%0,%1)
"%0" и "%1" - целочисленные переменные. Возможно ли убрать все пробелы между запятой и "%1", не добавляя, при этом, никаких символов или тегов?
В целом, задача заключается в том, чтоб переместить "%1" в начало
#define SomeFunc1(%0,%1) %1 = SomeFunc2(%0)
И если прописать в коде, например, так:
SomeFunc1(var1, var2);
То компилятор ругнётся на кривую табуляцию, так как "var2" перенесётся в начало вместе с пробелом. Собственно, от этого предупреждения и нужно избавиться.
Почему бы не обернуть это в скобки (do - while)?
#define foo(%0,%1) (%1=Bar(%0))
//#define foo(%0,%1) do{%1=Bar(%0)}while(0)
Почему бы не обернуть это в скобки (do - while)?
#define foo(%0,%1) (%1=Bar(%0))
//#define foo(%0,%1) do{%1=Bar(%0)}while(0)
Точно, скобки... Совсем не подумал про них. Так и думал, что правильная реализация окажется совсем простой и очевидной. А я тут пытался чуть ли не в 10 строк алгоритмы писать ради избавления от этих пробелов. Спасибо.
Если что, просто решил сделать для себя парсер, который бы упрощал перевод с MySQL R-39 на MySQL R-40 и наоборот. А то с некоторыми заказчиками периодически бывают проблемы в плане определения нужной версии MySQL и либо приходилось один и тот же код дублировать, либо переписывать под нужную версию.
MassonNN
17.10.2020, 16:57
Хороший урок. Есть один вопрос. Я хочу найти в коде (довольно объемном коде с огромным количеством библиотек и т.д.) удаление конкретного объекта, удаляется он соответственно:
RemoveBuildingForPlayer(playerid, 17513
по этому примеру, я хочу с помощью макроса изменить данный код на какую - нибудь лабуду и искусственно вызвать ошибки для нахождения этой строчки во всех файлах одновременно. Но есть проблема: в данном макросе есть пробел, который я не знаю как учитывать. Просто подставить %0 не очень работает, так как дальше идут цифры, а если пробел оставить, то под дефайн попадут ВСЕ RemoveBuildingForPlayer(playerid,
а не только те, которые мне нужны.
Хороший урок. Есть один вопрос. Я хочу найти в коде (довольно объемном коде с огромным количеством библиотек и т.д.) удаление конкретного объекта, удаляется он соответственно:
RemoveBuildingForPlayer(playerid, 17513
по этому примеру, я хочу с помощью макроса изменить данный код на какую - нибудь лабуду и искусственно вызвать ошибки для нахождения этой строчки во всех файлах одновременно. Но есть проблема: в данном макросе есть пробел, который я не знаю как учитывать. Просто подставить %0 не очень работает, так как дальше идут цифры, а если пробел оставить, то под дефайн попадут ВСЕ RemoveBuildingForPlayer(playerid,
а не только те, которые мне нужны.
Качаешь Sublime Text 3 (можешь попробовать другой редактор, но там регулярки могут работать иначе), перетаскиваешь папку с модом в текущий проект (https://i.imgur.com/AvmpP43.png), жмёшь на папку правой кнопкой и выбираешь "Find & Replace".
Далее в открывшемся снизу меню жмёшь на кнопку " .* " и в поле "Find" добавляешь
RemoveBuildingForPlayer\s*\((\s*[a-zA-Z0-9_]+)\s*,\s*17513
Собственно, дальше можешь либо нажать на "Find" и получить все совпадения, либо можешь даже какие-то махинации с этим сделать, дописав в "Replace" текст, на который его нужно заменить.
Вот тут (https://sublimetext.ru/documentation/find-and-replace) можешь подробнее почитать про этот функционал. Собственно, если сейчас в "Replace" указать "\1", то на месте этих двух символов появится тот текст, что в RemoveBuildingForPlayer будет указан в качестве ID игрока ("playerid" и т.п.)
Powered by vBulletin® Version 4.2.0 Copyright © 2024 vBulletin Solutions, Inc. All rights reserved. Перевод: zCarot