{"id":22283481,"url":"https://github.com/y-less/pawn_pp","last_synced_at":"2026-01-28T02:50:42.630Z","repository":{"id":142753086,"uuid":"82337907","full_name":"Y-Less/PAWN_PP","owner":"Y-Less","description":"Pre-processor macros for performing compile-time maths and concatenations.","archived":false,"fork":false,"pushed_at":"2018-04-08T23:55:23.000Z","size":60,"stargazers_count":10,"open_issues_count":0,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-06-03T04:46:33.200Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PAWN","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Y-Less.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-02-17T21:06:56.000Z","updated_at":"2024-01-21T21:33:46.000Z","dependencies_parsed_at":null,"dependency_job_id":"7d51211c-de29-447a-9bf7-8e62cef0181e","html_url":"https://github.com/Y-Less/PAWN_PP","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Y-Less/PAWN_PP","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Y-Less%2FPAWN_PP","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Y-Less%2FPAWN_PP/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Y-Less%2FPAWN_PP/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Y-Less%2FPAWN_PP/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Y-Less","download_url":"https://codeload.github.com/Y-Less/PAWN_PP/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Y-Less%2FPAWN_PP/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28834985,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-28T02:10:51.810Z","status":"ssl_error","status_checked_at":"2026-01-28T02:10:50.806Z","response_time":57,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-03T16:40:39.068Z","updated_at":"2026-01-28T02:50:42.600Z","avatar_url":"https://github.com/Y-Less.png","language":"PAWN","funding_links":[],"categories":[],"sub_categories":[],"readme":"# __PAWN PP__\n\nPAWN_PP is a library that defines pre-processor macros useful for performing compile-time maths and concatenations. \n\n\n## __Functions__\n\n\n\n#### __PP_CHAIN()__\n\nThe PAWN pre-processor's ordering is very specific, and can make some\noperations very tricky.  For example, this will not work:\n\n```pawn\nPP_ADD(PP_ADD(5,6),7)\n```\n\nThat will try to add `7` to the string `PP_ADD(5,6)` and best-case scenario\nwill give the answer `117` (`5+6` summed, followed by `7`).  Getting the\npre-processor to do the inner sum before the outer sum can't be done in that\nway since all macros are evaluated strictly left-to-right, not inner-to-\nouter.\n\n`PP_CHAIN` is a solution for this problem, for those macros explicitly\ndesigned to support it.  It is a stack machine, that uses `$` as result\nplaceholders, and `POP` to get a previous answer and put it in to that\nplaceholder.  The example above would thus become:\n\n```pawn\nPP_CHAIN( \\\n\tPP_ADD(5,6) \\ // Pushes 11 on to the stack.\n\tPP_POP()    \\ // Pops 11 and replaces the next \"$\" with it.\n\tPP_ADD($,7) \\ // Pushes 18 on to the stack.\n)\n```\n\nAt the end of the chain, the complete stack contents are dumped out.  This:\n\n```pawn\nPP_CHAIN( \\\n\tPP_ADD(5,6) \\\n\tPP_ADD(5,7) \\\n)\n```\n\nWould give:\n\n```pawn\n(12)(11)\n```\n\nSince there are two items on the stack and they are both enclosed in\nbrackets automatically.  The brackets can be stripped with `PP_UNWRAP`:\n\n```pawn\nPP_CHAIN( \\\n\tPP_ADD(5,6)  \\\n\tPP_ADD(5,7)  \\\n\tPP_UNWRAP($) \\\n)\n```\n\nWould give:\n\n```pawn\n12\n```\n\n\n\n#### __PP_UNWRAP()__\n\n`PP_UNWRAP` can ONLY be used inside `PP_CHAIN`, unlike some other functions,\nand thus it will automatically pop the top item off the stack, destroy the\nremainder of the stack, and put the popped item back on without its brackets.\n`PP_PRINT` is similar, but keeps the brackets.  In addition, both can take\nadditional parameters and will format accordingly:\n\n```pawn\nPP_CHAIN( \\\n\tPP_ADD(5,6)  \\\n\tPP_UNWRAP(answer = $;) \\\n)\n```\n\nWould give:\n\n```pawn\nanswer = 11;\n```\n\n(To output an actual `$`, use `PP_DOLLAR\u003c\u003e`).\n\n\n\n#### __PP_ADD() _[MINUS / SUB / LOG2 / POW2]___\n\n`PP_ADD`, `PP_MINUS`, `PP_SUB`, `PP_LOG2`, and `PP_POW2` are all stand-alone\nmaths operations and will work without being in `PP_CHAIN`.  Thus, they will\nnot automatically pop symbols in lieu of `$` (this is a limitation I tried to\nfix, but couldn't), so sadly they need an explicit `PP_POP_1`, `PP_POP_2`, or\n`PP_POP_3` (for which there is currently no true need):\n\n```pawn\nPP_CHAIN( \\\n\tPP_ADD(5,6)   \\\n\tPP_ADD(40,80) \\\n\tPP_POP_2()    \\\n\tPP_SUB($,$)   \\\n)\n```\n\nWould give:\n\n```pawn\n(-109)\n```\n\nResults are popped from the bottom of the stack (last in, first out), and\npushed in reverse parameter order (as in PAWN), resulting in the code above\nbeing equivalent to `(5 + 6) - (40 + 80)`.\n\nIt should also be noted that because the vast majority of the calculations\ndone in this way are done destructively in-place, there are no line-length\nlimitations to worry about (unless your equation itself is stupidly long).\n\n\n\n#### __PP_TOKENISE()__\n\n`PP_TOKENISE` is a synonym for `PP_UNWRAP`, meaning you can do:\n\n```pawn\n#define MY_MACRO_1(%0) %0 from MY_MACRO one\n#define MY_MACRO_2(%0) %0 from MY_MACRO two\n#define MY_MACRO_3(%0) %0 from MY_MACRO three\n\nPP_CHAIN( \\\n\tPP_ADD(1,2)               \\\n\tPP_TOKENISE(MY_MACRO_$)   \\\n)(hi)\n```\n\nWould give:\n\n```pawn\nhi from MY_MACRO three\n```\n\nIn that case, the entire chain would evaluate to exactly `MY_MACRO_3`, which\nwould then be parse and be seen to be preceeding another set of brackets,\nthus matching and being expanded.  Again, this is different to doing `1+2`,\nwhich would result in `MY_MACRO_1+2(hi)`, not `MY_MACRO_3(hi)`, and thus fail\nto match even the first `MY_MACRO_1`.\n\nAs stated elsewhere, this technique only works on macros explicitly designed\nfor being used in `PP_CHAIN`, mainly those that use a `_THEN` variant.  To\nwrite a standard value macro to work here would look like:\n\n```pawn\n#define MAX_PLAYERS  MAX_PLAYERS_() // Standard entry point - note `()`s.\n#define MAX_PLAYERS_ MACRO(500)     // Define the true value.\n```\n\nThat would (somewhat clunkily) enable:\n\n```pawn\nPP_CHAIN( \\\n\tPP_MACRO(MAX_PLAYERS) \\\n\tPP_POP()              \\\n\tPP_ADD(1,$)           \\\n)\n```\n\nSomeone using `MAX_PLAYERS` would get:\n\n```pawn\nMAX_PLAYERS\nMAX_PLAYERS_()\nMACRO(500)()\n_PP_MACRO(500)\n500\n```\n\nSomeone using `PP_MACRO(MAX_PLAYERS)` inside `PP_CHAIN()` would get:\n\n```pawn\nPP_MACRO(MAX_PLAYERS)\nMAX_PLAYERS_(_THEN)\nMACRO(500)(_THEN)\n_PP_MACRO_THEN(500)\n_PP_MACRO(500)\n```\n\nThe trick being that `PP_CHAIN` replaces all the functions inside it with\n`_THEN` suffixed versions.  This is the only way I could find to let macros\nuse information calculated by other macros before they were evaluated.\n\nI could not get this to work for constants as well as macros, so this will\nnot work:\n\n```pawn\nPP_CHAIN( \\\n\tPP_MACRO(100)         \\\n\tPP_POP()              \\\n\tPP_ADD(1,$)           \\\n)\n```\n\nInstead use `PP_PUSH` (or `PP_CONST` in exactly the same way):\n\n```pawn\nPP_CHAIN( \\\n\tPP_PUSH(100)          \\\n\tPP_POP()              \\\n\tPP_ADD(1,$)           \\\n)\n```\n\nThis is slightly awkward, as it does mean that a macro like this will not\nwork in all generic cases:\n\n```pawn\n#define Dialog[%1](%2) \\\n\tPP_CHAIN( \\\n\t\tPP_MACRO(%1)       \\\n\t\tPP_TOKENISE(@dlg$) \\\n\t)(%2)\n```\n\nThis will work:\n\n```pawn\n#define DIALOG_LOGIN_ID DIALOG_LOGIN_ID_()\n#define DIALOG_LOGIN_ID_ MACRO(101)\n\nDialog[DIALOG_LOGIN_ID](playerid, dialogid, response)\n{\n}\n```\n\nThis will not:\n\n```pawn\nDialog[101](playerid, dialogid, response)\n{\n}\n```\n\nSadly, you would need a separate version for the two cases, like\n`DialogNumber` and `DialogMacro`.\n\n\n\n#### __PP_ADD()__\n\nAdds two numbers (each up to +/-256) together in the pre-processor.  This is\ndifferent to using the compiler, which would just output `7+8`, or some sort\nof sum generation, which would give `7+1+1+1+1+1+1+1+1`.  The output is a\npure value of `15`, making it usable in other macros.  Strictly speaking, the\nvalue ranges are not exactly +/-256 - anything between those values\n(inclusive) are guaranteed to work; however, some other values in certain\npositions may work if the result is still within +/-512.\n\n\n\n#### __PP_SUB()__\n\nSubtracts two numbers (each up to +/-256) together in the pre-processor.\nThis is different to using the compiler, which would just output `7-8`, or\nsome sort of sum generation, which would give `7-1-1-1-1-1-1-1-1`.  The\noutput is a pure value of `-1`, making it usable in other macros.  Strictly\nspeaking, the value ranges are not exactly +/-256 - anything between those\nvalues (inclusive) are guaranteed to work; however, some other values in\ncertain positions may work if the result is still within +/-512.\n\n\n\n#### __PP_MINUS()__\n\nReturn a number with a minus sign attached.  This is used internally when a\nvalid symbol representing a negative number is required, instead of a true\nnegative number that would not be a valid macro name.  Exposed here because\nwhy not?\n\n\n\n#### __Deferred operators__  \nWhen you want, say, a bracket in the output but don't\nwant it to be matched by a macro use `PP_LEFT_BRACKET\u003c\u003e` instead.  That way\nanything preceeding that will not see or match against a bracket, but once\nthat macro is reached it will be replaced with just `(`.\n\n\n\n#### __PP_DROP()__ _[ID / ENCLOSE / TAG]_\n\n* `PP_DROP` just removes itself and its parameter.\n* `PP_ID` returns its parameter.\n* `PP_ENCLOSE` returns its parameter wrapped in brackets.\n* `PP_TAG` returns its parameter with a default tag override.\n\n\n\n\n#### __PP_AMP()__\n\n`true` when non-zero (truthy), `false` when zero (or falsy).\n\n\n\n#### __PP_NOT()__\n\n`false` when non-zero (truthy), `true` when zero (or falsy).\n\n\n\n\n#### __PP_LOG2()__\n\nFinds the log-2 base of a power of 2 number.  Only goes up to 2**73 due to\nsymbol length restrictions, but that is still vastly more than can be fit in\nto 32-bit or 64-bit cells.\n\n\n\n#### __PP_POW2()__\n\nFinds 2 raised to the given power.  Resolves to just a number.  Can't do it\nany other way, since there's no point supporting digit separators (because\nthe support range isn't large enough), and the result for negatives will be a\nfloating point number.\n\n\n\n\n#### __PP_PREVENT_EXPANSION(A_MACRO(macro, parameters))__\n\nStops the specified macro expanding, so this code below will NOT give `4`:\n\n```pawn\n#define MY_MACRO() 4\nPP_PREVENT_EXPANSION(MY_MACRO())\n```\n\nNote that this ONLY works on function-like macros, this will always expand:\n\n```pawn\nPP_PREVENT_EXPANSION(MAX_PLAYERS)\n```\n\n\n\n\n\n#### __PP_WARNING(\"Your warning message\")__\n\nGives a compile-time warning.  It will be an unused symbol warning which\nlooks vaguely like the specified warning.  Something like:\n\n```\nSymbol is never used: WARNING_Your_warning_message\n```\n\nThat should be enough for the user to go on.  Otherwise, they can look at the\ngiven file and line number (which will be correct) and will see the more\nuseful code from the example (`PP_ERROR(\"Your error message\")`).\n\n\n\n#### __PP_ERROR(\"Your error message\")__\n\nGives a compile-time error.  It will be an undefined symbol error which looks\nvaguely like the specified error.  Something like:\n\n```\nUndefined symbol: ERROR_Your_error_message\n```\n\nThat should be enough for the user to go on.  Otherwise, they can look at the\ngiven file and line number (which will be correct) and will see the more\nuseful code from the example (`PP_ERROR(\"Your error message\")`).\n\n\n\n#### __PP_STRIP_SPACES(something goes here)__\n\nGives:\n\n```pawn\nsomethinggoeshere\n```\n\nYou probably want to combine this with `PP_TAG`.\n\n\n\n#### __PP_REPLACE_SPACES(_)(something goes here)__\n\nGives:\n\n```pawn\nsomething_goes_here\n```\n\nThe first parameter is the separator to replace spaces with.  You probably\nwant to combine this with `PP_TAG`.\n\n\n\n#### __PP_PACKED()__\n\n`1` when `\"hello\"` is a packed string, `0` when it isn't.  This could be because\nthe compiler is version 4.x (in which case `''hello''` is an unpacked string,\nor because `#pragma pack 1` has been used, in which case `!\"hello\"` is a\npacked string (opposite of default).\n\n\n\n#### __PP_STRINGISE() \u0026 PP_STRINGIZE_PACKED()__\n\nGives a consistent stringize operator across multiple compiler versions.\n\nThis is not perfect.  The SA-MP PAWN branch reports its version as 3.2.3664,\nwhich is `0x0302` in the `__Pawn` macro, but the real 3.2.3664 doesn't have\nnative string concatenation abilities so needs the same hack as older\nversions; however, the two can't be distinguished (or maybe they can but I've\nnot figured out a way yet).  Thus, since the most likely use of 3.2 is for\nSA-MP I'm assuming that.\n\nIn PAWN version 4, the strings changed `\"string\"` became default packed, and\nunpacked became `''string''`, as opposed to `!\"string\"` and `\"string\"`\nbefore (unless `#pragma pack 1` is used).  I also think this is when the\nofficial compiler introduced `...` and `#` itself, since I can't find earlier\nmentions, but my set of documentation is incomplete.  For this reason, I have\nno implementation for the 3.3.xxxx branch.\n\nAdditionally, in the SA-MP version, this is legal:\n\n```pawn\nnew str[] = \"Hello \" #world;\n```\n\nBut in the 4.x branch, only macro parameters can be stringised, and must be\nexplicitly concatenated with `...`:\n\n```pawn\n#define CAT(%0,%1) %0 ... #%1\nnew str[] = CAT(\"Hello \", world);\n```\n\nThis code unites the two by making everything macro parameters and always\nhaving the `...` operator, even when it isn't required:\n\n```pawn\nnew str[] = PP_STRINGISE(\"Hello \" ... #world);\n```\n\nI'm not too sure how the explicit `#` there will fare, since that may result\nin `##` in some compilers - fine for `SA-MP` but I don't know about 4.x.\n\n\n## __Installation__\n\nSimply install to your project:\n\n```bash\nsampctl package install Y-Less/PAWN_PP\n```\n\nInclude in your code and begin using the library:\n\n```pawn\n#include \u003cpp\u003e\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fy-less%2Fpawn_pp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fy-less%2Fpawn_pp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fy-less%2Fpawn_pp/lists"}