exec.inc 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825
  1. #include "parser"
  2. static stock
  3. ISI_gHeap[128],
  4. ISI_gHeapPtr = -1;
  5. static stock const
  6. _EXEC_TAG_MISMATCH[] = "PARSER WARNING: Tag mismatch.",
  7. _EXEC_INCOMPATIBLE[] = "PARSER ERROR: Incompatible operands.",
  8. _EXEC_NOT_LVALUE[] = "PARSER ERROR: Not an lvalue.";
  9. #if defined INTROSPECT_PLAYER_DATA
  10. #define EXEC_TAG_MISMATCH _Parser_Msg(_EXEC_TAG_MISMATCH)
  11. #define EXEC_INCOMPATIBLE _Parser_Msg(_EXEC_INCOMPATIBLE)
  12. #define EXEC_NOT_LVALUE _Parser_Msg(_EXEC_NOT_LVALUE)
  13. #else
  14. #define EXEC_TAG_MISMATCH print(_EXEC_TAG_MISMATCH)
  15. #define EXEC_INCOMPATIBLE print(_EXEC_INCOMPATIBLE)
  16. #define EXEC_NOT_LVALUE print(_EXEC_NOT_LVALUE)
  17. #endif
  18. stock RunExpression(line[], size = sizeof (line), as = -1)
  19. {
  20. new
  21. ret[E_TOKEN] = EMPTY_PARSER_TOKEN;
  22. ISI_gHeapPtr = -1;
  23. Parser_SetPlayer(as);
  24. if (Parser_SetInput(line, size))
  25. {
  26. new
  27. parse = Parser_BuildTree();
  28. Exec_Evaluate(ret, ISI_gParseTree, parse);
  29. }
  30. Parser_SetPlayer(-1);
  31. return ret;
  32. }
  33. static stock MI(const token[E_TOKEN])
  34. {
  35. // Get a token as an integer.
  36. switch (token[E_TOKEN_TYPE])
  37. {
  38. case e_TOKEN_TYPE_VAR:
  39. return ReadAmxMemory(token[E_TOKEN_SYM_PTR]);
  40. case e_TOKEN_TYPE_INT:
  41. return token[E_TOKEN_INT_VAL];
  42. case e_TOKEN_TYPE_BOOL:
  43. return token[E_TOKEN_BOOL_VAL] ? 1 : 0;
  44. case e_TOKEN_TYPE_FLOAT:
  45. return
  46. EXEC_TAG_MISMATCH,
  47. floatround(token[E_TOKEN_FLOAT_VAL]);
  48. case e_TOKEN_TYPE_FVAR:
  49. return
  50. EXEC_TAG_MISMATCH,
  51. floatround(Float:ReadAmxMemory(token[E_TOKEN_SYM_PTR]));
  52. }
  53. return cellmin; // Almost NAN.
  54. }
  55. static stock Float:MF(const token[E_TOKEN])
  56. {
  57. // Get a token as a float.
  58. switch (token[E_TOKEN_TYPE])
  59. {
  60. case e_TOKEN_TYPE_VAR:
  61. return
  62. EXEC_TAG_MISMATCH,
  63. float(ReadAmxMemory(token[E_TOKEN_SYM_PTR]));
  64. case e_TOKEN_TYPE_INT:
  65. return
  66. EXEC_TAG_MISMATCH,
  67. float(token[E_TOKEN_INT_VAL]);
  68. case e_TOKEN_TYPE_BOOL:
  69. return token[E_TOKEN_BOOL_VAL] ? 1.0 : 0.0;
  70. case e_TOKEN_TYPE_FLOAT:
  71. return token[E_TOKEN_FLOAT_VAL];
  72. case e_TOKEN_TYPE_FVAR:
  73. return Float:ReadAmxMemory(token[E_TOKEN_SYM_PTR]);
  74. }
  75. return Float:0x7FFFFFFF; // NAN.
  76. }
  77. static stock e_TOKEN_TYPE:Exec_ResolveTags(const l[E_TOKEN], const r[E_TOKEN], &lr, &rr)
  78. {
  79. new
  80. bool:rfloat = false;
  81. switch (l[E_TOKEN_TYPE])
  82. {
  83. case e_TOKEN_TYPE_VAR, e_TOKEN_TYPE_BOOL, e_TOKEN_TYPE_INT: {}
  84. case e_TOKEN_TYPE_FVAR, e_TOKEN_TYPE_FLOAT: rfloat = true;
  85. default: return e_TOKEN_TYPE_NONE;
  86. }
  87. switch (r[E_TOKEN_TYPE])
  88. {
  89. case e_TOKEN_TYPE_VAR, e_TOKEN_TYPE_BOOL, e_TOKEN_TYPE_INT: {}
  90. case e_TOKEN_TYPE_FVAR, e_TOKEN_TYPE_FLOAT: rfloat = true;
  91. default: return e_TOKEN_TYPE_NONE;
  92. }
  93. if (rfloat)
  94. {
  95. // Some floats.
  96. return
  97. lr = _:MF(l),
  98. rr = _:MF(r),
  99. e_TOKEN_TYPE_FLOAT;
  100. }
  101. else
  102. {
  103. return
  104. lr = MI(l),
  105. rr = MI(r),
  106. e_TOKEN_TYPE_INT;
  107. }
  108. }
  109. static stock e_TOKEN_TYPE:Exec_ResolveBool(const l[E_TOKEN], const r[E_TOKEN], &lr, &rr)
  110. {
  111. switch (l[E_TOKEN_TYPE])
  112. {
  113. case e_TOKEN_TYPE_VAR:
  114. lr = ReadAmxMemory(l[E_TOKEN_SYM_PTR]) ? true : false;
  115. case e_TOKEN_TYPE_INT :
  116. lr = l[E_TOKEN_INT_VAL] ? true : false;
  117. case e_TOKEN_TYPE_BOOL :
  118. lr = l[E_TOKEN_BOOL_VAL];
  119. case e_TOKEN_TYPE_FLOAT:
  120. lr = l[E_TOKEN_FLOAT_VAL] ? true : false;
  121. case e_TOKEN_TYPE_FVAR :
  122. lr = Float:ReadAmxMemory(l[E_TOKEN_SYM_PTR]) ? true : false;
  123. default:
  124. return e_TOKEN_TYPE_NONE;
  125. }
  126. switch (r[E_TOKEN_TYPE])
  127. {
  128. case e_TOKEN_TYPE_VAR:
  129. rr = ReadAmxMemory(r[E_TOKEN_SYM_PTR]) ? true : false;
  130. case e_TOKEN_TYPE_INT :
  131. rr = r[E_TOKEN_INT_VAL] ? true : false;
  132. case e_TOKEN_TYPE_BOOL :
  133. rr = r[E_TOKEN_BOOL_VAL];
  134. case e_TOKEN_TYPE_FLOAT:
  135. rr = r[E_TOKEN_FLOAT_VAL] ? true : false;
  136. case e_TOKEN_TYPE_FVAR :
  137. rr = Float:ReadAmxMemory(r[E_TOKEN_SYM_PTR]) ? true : false;
  138. default:
  139. return e_TOKEN_TYPE_NONE;
  140. }
  141. return e_TOKEN_TYPE_BOOL;
  142. }
  143. static stock e_TOKEN_TYPE:Exec_ResolveInt(const l[E_TOKEN], const r[E_TOKEN], &lr, &rr)
  144. {
  145. new
  146. e_TOKEN_TYPE:ret = e_TOKEN_TYPE_INT;
  147. switch (l[E_TOKEN_TYPE])
  148. {
  149. case e_TOKEN_TYPE_VAR:
  150. lr = ReadAmxMemory(l[E_TOKEN_SYM_PTR]);
  151. case e_TOKEN_TYPE_INT :
  152. lr = l[E_TOKEN_INT_VAL];
  153. case e_TOKEN_TYPE_BOOL :
  154. lr = _:l[E_TOKEN_BOOL_VAL];
  155. case e_TOKEN_TYPE_FLOAT:
  156. ret = e_TOKEN_TYPE_FLOAT,
  157. lr = _:l[E_TOKEN_FLOAT_VAL];
  158. case e_TOKEN_TYPE_FVAR :
  159. ret = e_TOKEN_TYPE_FLOAT,
  160. lr = _:Float:ReadAmxMemory(l[E_TOKEN_SYM_PTR]);
  161. default:
  162. return e_TOKEN_TYPE_NONE;
  163. }
  164. switch (r[E_TOKEN_TYPE])
  165. {
  166. case e_TOKEN_TYPE_VAR :
  167. {
  168. if (ret == e_TOKEN_TYPE_FLOAT) EXEC_TAG_MISMATCH;
  169. rr = ReadAmxMemory(r[E_TOKEN_SYM_PTR]);
  170. }
  171. case e_TOKEN_TYPE_INT :
  172. {
  173. if (ret == e_TOKEN_TYPE_FLOAT) EXEC_TAG_MISMATCH;
  174. rr = r[E_TOKEN_INT_VAL];
  175. }
  176. case e_TOKEN_TYPE_BOOL :
  177. {
  178. if (ret == e_TOKEN_TYPE_FLOAT) EXEC_TAG_MISMATCH;
  179. rr = _:r[E_TOKEN_BOOL_VAL];
  180. }
  181. case e_TOKEN_TYPE_FLOAT:
  182. {
  183. if (ret == e_TOKEN_TYPE_INT) EXEC_TAG_MISMATCH;
  184. rr = _:r[E_TOKEN_FLOAT_VAL];
  185. }
  186. case e_TOKEN_TYPE_FVAR :
  187. {
  188. if (ret == e_TOKEN_TYPE_INT) EXEC_TAG_MISMATCH;
  189. rr = _:Float:ReadAmxMemory(r[E_TOKEN_SYM_PTR]);
  190. }
  191. default:
  192. return e_TOKEN_TYPE_NONE;
  193. }
  194. return ret;
  195. }
  196. static stock Exec_ToHeap(value)
  197. {
  198. static
  199. sNullDest;
  200. if (++ISI_gHeapPtr == sizeof (ISI_gHeap))
  201. {
  202. Parser_Error("Heap overflow.");
  203. return ref(sNullDest);
  204. }
  205. else
  206. {
  207. ISI_gHeap[ISI_gHeapPtr] = value;
  208. return ref(ISI_gHeap[ISI_gHeapPtr]);
  209. }
  210. }
  211. #define EXEC_OP(%0\32;%9\32;%1,%7) switch(Exec_ResolveTags(%0,%1,lr,rr)) { \
  212. case e_TOKEN_TYPE_FLOAT:ret[E_TOKEN_TYPE]=e_TOKEN_TYPE_FLOAT,ret[E_TOKEN_FLOAT_VAL]=%7((Float:lr),(Float:rr)); \
  213. case e_TOKEN_TYPE_INT:ret[E_TOKEN_TYPE]=e_TOKEN_TYPE_INT,ret[E_TOKEN_INT_VAL]=lr%9rr; \
  214. default:EXEC_INCOMPATIBLE;}
  215. #define EXEC_CMP(%0\32;%9\32;%1,%7) switch(Exec_ResolveTags(%0,%1,lr,rr)) { \
  216. case e_TOKEN_TYPE_FLOAT:ret[E_TOKEN_TYPE]=e_TOKEN_TYPE_BOOL,ret[E_TOKEN_BOOL_VAL]=%7((Float:lr),(Float:rr)); \
  217. case e_TOKEN_TYPE_INT:ret[E_TOKEN_TYPE]=e_TOKEN_TYPE_BOOL,ret[E_TOKEN_BOOL_VAL]=lr%9rr; \
  218. default:EXEC_INCOMPATIBLE;}
  219. #define EXEC_BOOL(%0\32;%9\32;%1) if(Exec_ResolveBool(%0,%1,lr,rr)==e_TOKEN_TYPE_BOOL) \
  220. ret[E_TOKEN_TYPE]=e_TOKEN_TYPE_BOOL,ret[E_TOKEN_BOOL_VAL]=(bool:lr)%9(bool:rr); \
  221. else EXEC_INCOMPATIBLE;
  222. #define EXEC_INT(%0\32;%9\32;%1) { new e_TOKEN_TYPE:ttt = Exec_ResolveInt(%0,%1,lr,rr); \
  223. if(ttt==e_TOKEN_TYPE_NONE) EXEC_INCOMPATIBLE; \
  224. else ret[E_TOKEN_TYPE]=ttt,ret[E_TOKEN_INT_VAL]=lr%9rr; }
  225. static stock Exec_ExecToken(const t[E_TOKEN], const l[E_TOKEN], const r[E_TOKEN])
  226. {
  227. static lr, rr;
  228. static const
  229. scAssign[E_TOKEN] = MAKE_PARSER_TOKEN(e_TOKEN_TYPE_OP, e_TOKEN_OP_ASSIGN, -1, -1);
  230. new
  231. ret[E_TOKEN] = EMPTY_PARSER_TOKEN;
  232. switch (t[E_TOKEN_TYPE] & TOKEN_TYPE_MASK)
  233. {
  234. case e_TOKEN_TYPE_OP : switch (t[E_TOKEN_OP])
  235. {
  236. case e_TOKEN_OP_COMMA, e_TOKEN_OP_SEMICOLON:
  237. {
  238. ret = r;
  239. }
  240. case e_TOKEN_OP_ASSIGN: switch (l[E_TOKEN_TYPE] & TOKEN_TYPE_MASK)
  241. {
  242. case e_TOKEN_TYPE_VAR:
  243. {
  244. rr = MI(r),
  245. WriteAmxMemory(l[E_TOKEN_SYM_PTR], rr),
  246. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_INT,
  247. ret[E_TOKEN_INT_VAL] = rr;
  248. }
  249. case e_TOKEN_TYPE_FVAR:
  250. {
  251. rr = _:MF(r),
  252. WriteAmxMemory(l[E_TOKEN_SYM_PTR], rr),
  253. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_FLOAT,
  254. ret[E_TOKEN_FLOAT_VAL] = Float:rr;
  255. }
  256. case e_TOKEN_TYPE_ARRAY:
  257. {
  258. // Allow string assignment.
  259. if (r[E_TOKEN_TYPE] == e_TOKEN_TYPE_STRING)
  260. {
  261. new
  262. idx = ISI_gsStringTable[(ret[E_TOKEN_STRING_IDX] = r[E_TOKEN_STRING_IDX])];
  263. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_STRING,
  264. WriteAmxMemoryArray(l[E_TOKEN_SYM_PTR], ISI_gInputLine[idx], strlen(ISI_gInputLine[idx]));
  265. }
  266. else Parser_Error("Can only assign strings to arrays.");
  267. }
  268. default: EXEC_NOT_LVALUE;
  269. }
  270. // Float versions are reversed.
  271. case e_TOKEN_OP_EQUALS : // '=='
  272. EXEC_CMP(l == r, 0 == floatcmp)
  273. case e_TOKEN_OP_LTE : // '<='
  274. EXEC_CMP(l <= r, 0 >= floatcmp)
  275. case e_TOKEN_OP_GTE : // '>='
  276. EXEC_CMP(l >= r, 0 <= floatcmp)
  277. case e_TOKEN_OP_LESS : // '<'
  278. EXEC_CMP(l < r, 0 > floatcmp)
  279. case e_TOKEN_OP_GREATER: // '>'
  280. EXEC_CMP(l > r, 0 < floatcmp)
  281. case e_TOKEN_OP_NEQ : // '!='
  282. EXEC_CMP(l != r, 0 != floatcmp)
  283. #define _EXEC_DO_ASSIGN(%0) case e_TOKEN_OP_%0_ASS: { \
  284. static const scMathOp[E_TOKEN] = MAKE_PARSER_TOKEN(e_TOKEN_TYPE_OP, e_TOKEN_OP_%0, -1, -1); \
  285. return ret = Exec_ExecToken(scMathOp, l, r), Exec_ExecToken(scAssign, l, ret); }
  286. // For these, run the code twice.
  287. _EXEC_DO_ASSIGN(INV)
  288. _EXEC_DO_ASSIGN(ADD)
  289. _EXEC_DO_ASSIGN(SUB)
  290. _EXEC_DO_ASSIGN(MUL)
  291. _EXEC_DO_ASSIGN(DIV)
  292. _EXEC_DO_ASSIGN(MOD)
  293. _EXEC_DO_ASSIGN(XOR)
  294. _EXEC_DO_ASSIGN(LAND)
  295. _EXEC_DO_ASSIGN(LOR)
  296. _EXEC_DO_ASSIGN(RSHIFT)
  297. _EXEC_DO_ASSIGN(SHIFT)
  298. _EXEC_DO_ASSIGN(LSHIFT)
  299. #undef _EXEC_DO_ASSIGN
  300. case e_TOKEN_OP_INV : switch (r[E_TOKEN_TYPE])
  301. {
  302. case e_TOKEN_TYPE_VAR:
  303. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_INT,
  304. ret[E_TOKEN_INT_VAL] = ~ReadAmxMemory(r[E_TOKEN_SYM_PTR]);
  305. case e_TOKEN_TYPE_INT :
  306. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_INT,
  307. ret[E_TOKEN_INT_VAL] = ~r[E_TOKEN_INT_VAL];
  308. case e_TOKEN_TYPE_BOOL :
  309. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_INT,
  310. ret[E_TOKEN_INT_VAL] = ~_:r[E_TOKEN_BOOL_VAL];
  311. case e_TOKEN_TYPE_FLOAT:
  312. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_FLOAT,
  313. ret[E_TOKEN_FLOAT_VAL] = ~r[E_TOKEN_FLOAT_VAL];
  314. case e_TOKEN_TYPE_FVAR :
  315. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_FLOAT,
  316. ret[E_TOKEN_FLOAT_VAL] = ~Float:ReadAmxMemory(r[E_TOKEN_SYM_PTR]);
  317. default:
  318. return Parser_Error("Unary inversion not applied to value."), ret;
  319. }
  320. case e_TOKEN_OP_NOT : switch (r[E_TOKEN_TYPE])
  321. {
  322. case e_TOKEN_TYPE_VAR:
  323. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_BOOL,
  324. ret[E_TOKEN_BOOL_VAL] = !ReadAmxMemory(r[E_TOKEN_SYM_PTR]);
  325. case e_TOKEN_TYPE_INT :
  326. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_BOOL,
  327. ret[E_TOKEN_BOOL_VAL] = !r[E_TOKEN_INT_VAL];
  328. case e_TOKEN_TYPE_BOOL :
  329. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_BOOL,
  330. ret[E_TOKEN_BOOL_VAL] = !r[E_TOKEN_BOOL_VAL];
  331. case e_TOKEN_TYPE_FLOAT:
  332. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_BOOL,
  333. ret[E_TOKEN_BOOL_VAL] = !r[E_TOKEN_FLOAT_VAL];
  334. case e_TOKEN_TYPE_FVAR :
  335. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_BOOL,
  336. ret[E_TOKEN_BOOL_VAL] = !Float:ReadAmxMemory(r[E_TOKEN_SYM_PTR]);
  337. default: return Parser_Error("Unary negation not applied to value."), ret;
  338. }
  339. case e_TOKEN_OP_NEG : switch (r[E_TOKEN_TYPE]) // PREFIX '-'
  340. {
  341. case e_TOKEN_TYPE_VAR:
  342. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_INT,
  343. ret[E_TOKEN_INT_VAL] = -ReadAmxMemory(r[E_TOKEN_SYM_PTR]);
  344. case e_TOKEN_TYPE_INT :
  345. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_INT,
  346. ret[E_TOKEN_INT_VAL] = -r[E_TOKEN_INT_VAL];
  347. case e_TOKEN_TYPE_BOOL :
  348. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_INT,
  349. ret[E_TOKEN_INT_VAL] = -_:r[E_TOKEN_BOOL_VAL];
  350. case e_TOKEN_TYPE_FLOAT:
  351. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_FLOAT,
  352. ret[E_TOKEN_FLOAT_VAL] = r[E_TOKEN_FLOAT_VAL] ^ Float:cellmin;
  353. case e_TOKEN_TYPE_FVAR :
  354. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_FLOAT,
  355. ret[E_TOKEN_FLOAT_VAL] = Float:ReadAmxMemory(r[E_TOKEN_SYM_PTR]) ^ Float:cellmin;
  356. default:
  357. return Parser_Error("Unary minus not applied to value."), ret;
  358. }
  359. case e_TOKEN_OP_SUB : // INFIX '-'
  360. EXEC_OP(l - r, floatsub)
  361. case e_TOKEN_OP_ADD : // '+'
  362. EXEC_OP(l + r, floatadd)
  363. case e_TOKEN_OP_MUL : // '*'
  364. EXEC_OP(l * r, floatmul)
  365. case e_TOKEN_OP_DIV : // '/'
  366. EXEC_OP(l / r, floatdiv)
  367. case e_TOKEN_OP_MOD : // '%'
  368. {
  369. if (Exec_ResolveTags(l, r, lr, rr) == e_TOKEN_TYPE_INT)
  370. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_INT,
  371. ret[E_TOKEN_INT_VAL] = lr % rr;
  372. else EXEC_INCOMPATIBLE;
  373. }
  374. case e_TOKEN_OP_XOR : // '^'
  375. EXEC_INT(l ^ r)
  376. case e_TOKEN_OP_LAND : // INFIX '&'
  377. EXEC_INT(l & r)
  378. case e_TOKEN_OP_REF : switch (r[E_TOKEN_TYPE]) // PREFIX '&'
  379. {
  380. case e_TOKEN_TYPE_INT, e_TOKEN_TYPE_BOOL, e_TOKEN_TYPE_FLOAT:
  381. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_INT,
  382. ret[E_TOKEN_INT_VAL] = Exec_ToHeap(r[E_TOKEN_INT_VAL]);
  383. case e_TOKEN_TYPE_FVAR, e_TOKEN_TYPE_VAR:
  384. // Store the pointer as a number.
  385. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_INT,
  386. ret[E_TOKEN_INT_VAL] = r[E_TOKEN_SYM_PTR];
  387. default:
  388. return Parser_Error("References must be made to values."), ret;
  389. }
  390. case e_TOKEN_OP_LOR : // '|'
  391. EXEC_INT(l | r)
  392. case e_TOKEN_OP_RSHIFT : // '>>'
  393. EXEC_INT(l >> r)
  394. case e_TOKEN_OP_SHIFT : // '>>>'
  395. EXEC_INT(l >>> r)
  396. case e_TOKEN_OP_LSHIFT : // '<<'
  397. EXEC_INT(l << r)
  398. case e_TOKEN_OP_AND : // '&&'
  399. EXEC_BOOL(l && r)
  400. case e_TOKEN_OP_OR : // '||'
  401. EXEC_BOOL(l || r)
  402. case e_TOKEN_OP_POST_INC: switch (l[E_TOKEN_TYPE])
  403. {
  404. case e_TOKEN_TYPE_VAR: // Suffix integer op.
  405. lr = ReadAmxMemory(l[E_TOKEN_SYM_PTR]),
  406. WriteAmxMemory(l[E_TOKEN_SYM_PTR], lr + 1),
  407. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_INT,
  408. ret[E_TOKEN_INT_VAL] = lr;
  409. case e_TOKEN_TYPE_FVAR: // Suffix float op.
  410. lr = _:Float:ReadAmxMemory(l[E_TOKEN_SYM_PTR]),
  411. WriteAmxMemory(l[E_TOKEN_SYM_PTR], _:floatadd(Float:lr, 1.0)),
  412. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_FLOAT,
  413. ret[E_TOKEN_FLOAT_VAL] = Float:lr;
  414. default: EXEC_NOT_LVALUE;
  415. }
  416. case e_TOKEN_OP_PRE_INC: switch (r[E_TOKEN_TYPE])
  417. {
  418. case e_TOKEN_TYPE_VAR: // Prefix integer op.
  419. rr = ReadAmxMemory(r[E_TOKEN_SYM_PTR]) + 1,
  420. WriteAmxMemory(r[E_TOKEN_SYM_PTR], rr),
  421. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_INT,
  422. ret[E_TOKEN_INT_VAL] = rr;
  423. case e_TOKEN_TYPE_FVAR: // Prefix float op.
  424. rr = _:floatadd(Float:ReadAmxMemory(r[E_TOKEN_SYM_PTR]), 1.0),
  425. WriteAmxMemory(r[E_TOKEN_SYM_PTR], rr),
  426. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_FLOAT,
  427. ret[E_TOKEN_FLOAT_VAL] = Float:rr;
  428. default: EXEC_NOT_LVALUE;
  429. }
  430. case e_TOKEN_OP_POST_DEC: switch (l[E_TOKEN_TYPE])
  431. {
  432. case e_TOKEN_TYPE_VAR: // Suffix integer op.
  433. lr = ReadAmxMemory(l[E_TOKEN_SYM_PTR]),
  434. WriteAmxMemory(l[E_TOKEN_SYM_PTR], lr - 1),
  435. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_INT,
  436. ret[E_TOKEN_INT_VAL] = lr;
  437. case e_TOKEN_TYPE_FVAR: // Suffix float op.
  438. lr = _:Float:ReadAmxMemory(l[E_TOKEN_SYM_PTR]),
  439. WriteAmxMemory(l[E_TOKEN_SYM_PTR], _:floatsub(Float:lr, 1.0)),
  440. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_FLOAT,
  441. ret[E_TOKEN_FLOAT_VAL] = Float:lr;
  442. default: EXEC_NOT_LVALUE;
  443. }
  444. case e_TOKEN_OP_PRE_DEC: switch (r[E_TOKEN_TYPE])
  445. {
  446. case e_TOKEN_TYPE_VAR: // Prefix integer op.
  447. rr = ReadAmxMemory(r[E_TOKEN_SYM_PTR]) - 1,
  448. WriteAmxMemory(r[E_TOKEN_SYM_PTR], rr),
  449. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_INT,
  450. ret[E_TOKEN_INT_VAL] = rr;
  451. case e_TOKEN_TYPE_FVAR: // Prefix float op.
  452. rr = _:floatsub(Float:ReadAmxMemory(r[E_TOKEN_SYM_PTR]), 1.0),
  453. WriteAmxMemory(r[E_TOKEN_SYM_PTR], rr),
  454. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_FLOAT,
  455. ret[E_TOKEN_FLOAT_VAL] = Float:rr;
  456. default: EXEC_NOT_LVALUE;
  457. }
  458. case e_TOKEN_OP_CONCAT:
  459. {
  460. if (l[E_TOKEN_TYPE] != e_TOKEN_TYPE_STRING || r[E_TOKEN_TYPE] != e_TOKEN_TYPE_STRING)
  461. return Parser_Error("Can only concat strings."), ret;
  462. new
  463. str[512];
  464. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_STRING,
  465. lr = l[E_TOKEN_STRING_IDX],
  466. rr = r[E_TOKEN_STRING_IDX],
  467. strcat(str, ISI_gInputLine[ISI_gsStringTable[lr]]),
  468. strcat(str, ISI_gInputLine[ISI_gsStringTable[rr]]),
  469. Parser_RemoveString(lr),
  470. Parser_RemoveString(rr),
  471. ret[E_TOKEN_STRING_IDX] = Parser_InsertString(str);
  472. }
  473. case e_TOKEN_OP_HASH:
  474. {
  475. new
  476. str[512];
  477. switch (r[E_TOKEN_TYPE])
  478. {
  479. case e_TOKEN_TYPE_VAR:
  480. {
  481. valstr(str, ReadAmxMemory(r[E_TOKEN_SYM_PTR]));
  482. }
  483. case e_TOKEN_TYPE_INT:
  484. {
  485. valstr(str, r[E_TOKEN_INT_VAL]);
  486. }
  487. case e_TOKEN_TYPE_BOOL:
  488. {
  489. str = r[E_TOKEN_BOOL_VAL] ? ("true") : ("false");
  490. }
  491. case e_TOKEN_TYPE_FLOAT:
  492. {
  493. format(str, sizeof (str), "%.2f", r[E_TOKEN_FLOAT_VAL]);
  494. }
  495. case e_TOKEN_TYPE_FVAR:
  496. {
  497. format(str, sizeof (str), "%.2f", Float:ReadAmxMemory(r[E_TOKEN_SYM_PTR]));
  498. }
  499. case e_TOKEN_TYPE_STRING: return r;
  500. default: return Parser_Error("Cannot convert token to string."), ret;
  501. }
  502. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_STRING,
  503. ret[E_TOKEN_STRING_IDX] = Parser_InsertString(str);
  504. }
  505. //default: TODO: Whatever OP this is...
  506. }
  507. case e_TOKEN_TYPE_INDEX :
  508. {
  509. rr = MI(r);
  510. if (rr == cellmin) return Parser_Error("Invalid index."), ret;
  511. rr = l[E_TOKEN_SYM_PTR] + rr * 4,
  512. lr = _:(l[E_TOKEN_TYPE] >>> TOKEN_TYPE_SHIFT) - 1;
  513. switch (l[E_TOKEN_TYPE] & TOKEN_TYPE_MASK)
  514. {
  515. case e_TOKEN_TYPE_ARRAY:
  516. if (lr <= 0)
  517. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_VAR,
  518. ret[E_TOKEN_SYM_PTR] = rr;
  519. else
  520. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_ARRAY | (e_TOKEN_TYPE:lr << TOKEN_TYPE_SHIFT),
  521. ret[E_TOKEN_SYM_PTR] = ReadAmxMemory(rr);
  522. case e_TOKEN_TYPE_FARRAY:
  523. if (lr <= 0)
  524. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_FVAR,
  525. ret[E_TOKEN_SYM_PTR] = rr;
  526. else
  527. ret[E_TOKEN_TYPE] = e_TOKEN_TYPE_FARRAY | (e_TOKEN_TYPE:lr << TOKEN_TYPE_SHIFT),
  528. ret[E_TOKEN_SYM_PTR] = ReadAmxMemory(rr);
  529. default: return Parser_Error("Invalid subscript or not an array."), ret;
  530. }
  531. }
  532. default: ret = t;
  533. }
  534. return ret;
  535. // new
  536. // l[E_EXEC_RESULT]:
  537. // r[E_EXEC_RESULT];
  538. }
  539. static stock Exec_PushOne(tree[][E_TOKEN], entry)
  540. {
  541. new
  542. token[E_TOKEN],
  543. bool:pushed;
  544. Exec_Evaluate(token, tree, entry);
  545. switch (token[E_TOKEN_TYPE] & TOKEN_TYPE_MASK)
  546. {
  547. case e_TOKEN_TYPE_VAR, e_TOKEN_TYPE_FVAR:
  548. {
  549. pushed = Push(ReadAmxMemory(token[E_TOKEN_SYM_PTR]));
  550. }
  551. case e_TOKEN_TYPE_INT,
  552. e_TOKEN_TYPE_BOOL,
  553. e_TOKEN_TYPE_FLOAT,
  554. e_TOKEN_TYPE_ARRAY,
  555. e_TOKEN_TYPE_FARRAY:
  556. {
  557. pushed = Push(token[E_TOKEN_INT_VAL]);
  558. }
  559. case e_TOKEN_TYPE_STRING:
  560. {
  561. pushed = PushString(ISI_gInputLine[ISI_gsStringTable[token[E_TOKEN_STRING_IDX]]]);
  562. }
  563. }
  564. if (!pushed) Parser_Error("Could not push parameters.");
  565. }
  566. static stock Exec_PushParams(tree[][E_TOKEN], entry)
  567. {
  568. if (tree[entry][E_TOKEN_TYPE] == e_TOKEN_TYPE_NONE) return 0; // End.
  569. else if (tree[entry][E_TOKEN_TYPE] != e_TOKEN_TYPE_OP || tree[entry][E_TOKEN_OP] != e_TOKEN_OP_COMMA)
  570. {
  571. Exec_PushOne(tree, entry);
  572. return
  573. 1;
  574. }
  575. new
  576. ret = Exec_PushParams(tree, tree[entry][E_TOKEN_LEFT]) + 1;
  577. Exec_PushOne(tree, tree[entry][E_TOKEN_RIGHT]);
  578. return ret;
  579. }
  580. static stock Exec_Evaluate(token[E_TOKEN], tree[][E_TOKEN], entry)
  581. {
  582. new
  583. l[E_TOKEN],
  584. r[E_TOKEN];
  585. token = tree[0];
  586. if (entry == -1) return;
  587. token = tree[entry];
  588. if (token[E_TOKEN_LEFT] == -1 && token[E_TOKEN_RIGHT] == -1) return;
  589. Exec_Evaluate(l, tree, token[E_TOKEN_LEFT]);
  590. switch (token[E_TOKEN_TYPE])
  591. {
  592. case e_TOKEN_TYPE_OP: if (token[E_TOKEN_OP] == e_TOKEN_OP_QUESTION)
  593. {
  594. // Ternary operator - requires special handling.
  595. new
  596. bool:tf;
  597. r = tree[token[E_TOKEN_RIGHT]];
  598. if (r[E_TOKEN_TYPE] != e_TOKEN_TYPE_OP || r[E_TOKEN_OP] != e_TOKEN_OP_COLON)
  599. {
  600. Parser_Error("Missing ':' after '?'.");
  601. return;
  602. }
  603. switch (l[E_TOKEN_TYPE])
  604. {
  605. case e_TOKEN_TYPE_VAR:
  606. tf = bool:ReadAmxMemory(l[E_TOKEN_SYM_PTR]);
  607. case e_TOKEN_TYPE_INT:
  608. tf = bool:l[E_TOKEN_INT_VAL];
  609. case e_TOKEN_TYPE_BOOL:
  610. tf = l[E_TOKEN_BOOL_VAL];
  611. case e_TOKEN_TYPE_FLOAT:
  612. tf = bool:token[E_TOKEN_FLOAT_VAL];
  613. case e_TOKEN_TYPE_FVAR:
  614. tf = bool:Float:ReadAmxMemory(token[E_TOKEN_SYM_PTR]);
  615. default:
  616. {
  617. Parser_Error("Could not evaluate condition.");
  618. return;
  619. }
  620. }
  621. // Only execute either the "true" or "false" branch (for side effects).
  622. if (tf) Exec_Evaluate(token, tree, r[E_TOKEN_LEFT]);
  623. else Exec_Evaluate(token, tree, r[E_TOKEN_RIGHT]);
  624. return;
  625. }
  626. case e_TOKEN_TYPE_APPLY:
  627. {
  628. // Function call.
  629. new
  630. count = Exec_PushParams(tree, token[E_TOKEN_RIGHT]);
  631. switch (l[E_TOKEN_TYPE])
  632. {
  633. case e_TOKEN_TYPE_NATIVE:
  634. {
  635. token[E_TOKEN_TYPE] = e_TOKEN_TYPE_INT,
  636. token[E_TOKEN_INT_VAL] = SysreqCN(l[E_TOKEN_NATIVE_IDX], count);
  637. }
  638. case e_TOKEN_TYPE_FUNC:
  639. {
  640. token[E_TOKEN_TYPE] = e_TOKEN_TYPE_INT,
  641. token[E_TOKEN_INT_VAL] = CallN(l[E_TOKEN_FUNC_PTR], count);
  642. }
  643. case e_TOKEN_TYPE_FFUNC:
  644. {
  645. token[E_TOKEN_TYPE] = e_TOKEN_TYPE_FLOAT,
  646. token[E_TOKEN_FLOAT_VAL] = Float:CallN(l[E_TOKEN_FUNC_PTR], count);
  647. }
  648. default: Parser_Error("Not a pointer.");
  649. }
  650. return;
  651. }
  652. }
  653. // Default action.
  654. Exec_Evaluate(r, tree, token[E_TOKEN_RIGHT]);
  655. token = Exec_ExecToken(token, l, r);
  656. }
  657. #undef EXEC_OP
  658. #undef EXEC_CMP
  659. #undef EXEC_BOOL
  660. #undef EXEC_INT
  661. #undef EXEC_TAG_MISMATCH
  662. #undef EXEC_INCOMPATIBLE
  663. #undef EXEC_NOT_LVALUE
  664. #if defined INTROSPECT_EXEC_TEST
  665. #include "..\amx\amx_memory"
  666. main()
  667. {
  668. // These should all print "1".
  669. new
  670. l [E_TOKEN],
  671. r [E_TOKEN],
  672. op [E_TOKEN],
  673. res[E_TOKEN];
  674. MAKE_TOKEN(l, e_TOKEN_TYPE_INT, 42),
  675. MAKE_TOKEN(r, e_TOKEN_TYPE_INT, 11),
  676. MAKE_TOKEN(op, e_TOKEN_TYPE_OP, e_TOKEN_OP_ADD),
  677. res = Exec_ExecToken(op, l, r);
  678. printf("%d", COMPARE_PARSER_TOKEN(res, {e_TOKEN_TYPE_INT, 53}));
  679. MAKE_TOKEN(l, e_TOKEN_TYPE_INT, 42),
  680. MAKE_TOKEN(r, e_TOKEN_TYPE_INT, 0),
  681. MAKE_TOKEN(op, e_TOKEN_TYPE_OP, e_TOKEN_OP_MUL),
  682. res = Exec_ExecToken(op, l, r);
  683. printf("%d", COMPARE_PARSER_TOKEN(res, {e_TOKEN_TYPE_INT, 0}));
  684. MAKE_TOKEN(l, e_TOKEN_TYPE_INT, 42),
  685. MAKE_TOKEN(r, e_TOKEN_TYPE_INT, 11),
  686. MAKE_TOKEN(op, e_TOKEN_TYPE_OP, e_TOKEN_OP_MUL),
  687. res = Exec_ExecToken(op, l, r);
  688. printf("%d", COMPARE_PARSER_TOKEN(res, {e_TOKEN_TYPE_INT, 462}));
  689. MAKE_TOKEN(l, e_TOKEN_TYPE_INT, 42),
  690. MAKE_TOKEN(r, e_TOKEN_TYPE_INT, 0),
  691. MAKE_TOKEN(op, e_TOKEN_TYPE_OP, e_TOKEN_OP_ADD),
  692. res = Exec_ExecToken(op, l, r);
  693. printf("%d", COMPARE_PARSER_TOKEN(res, {e_TOKEN_TYPE_INT, 42}));
  694. MAKE_TOKEN(l, e_TOKEN_TYPE_INT, 42),
  695. MAKE_TOKEN(r, e_TOKEN_TYPE_FLOAT, _:11.0),
  696. MAKE_TOKEN(op, e_TOKEN_TYPE_OP, e_TOKEN_OP_ADD),
  697. res = Exec_ExecToken(op, l, r);
  698. printf("%d", COMPARE_PARSER_TOKEN(res, {e_TOKEN_TYPE_FLOAT, _:53.0}));
  699. MAKE_TOKEN(l, e_TOKEN_TYPE_INT, 42),
  700. MAKE_TOKEN(r, e_TOKEN_TYPE_FLOAT, _:0.0),
  701. MAKE_TOKEN(op, e_TOKEN_TYPE_OP, e_TOKEN_OP_ADD),
  702. res = Exec_ExecToken(op, l, r);
  703. printf("%d", COMPARE_PARSER_TOKEN(res, {e_TOKEN_TYPE_FLOAT, _:42.0}));
  704. MAKE_TOKEN(l, e_TOKEN_TYPE_INT, 42),
  705. MAKE_TOKEN(r, e_TOKEN_TYPE_FLOAT, _:0.0),
  706. MAKE_TOKEN(op, e_TOKEN_TYPE_OP, e_TOKEN_OP_EQUALS),
  707. res = Exec_ExecToken(op, l, r);
  708. printf("%d", COMPARE_PARSER_TOKEN(res, {e_TOKEN_TYPE_BOOL, _:false}));
  709. MAKE_TOKEN(l, e_TOKEN_TYPE_INT, 42),
  710. MAKE_TOKEN(r, e_TOKEN_TYPE_FLOAT, _:42.0),
  711. MAKE_TOKEN(op, e_TOKEN_TYPE_OP, e_TOKEN_OP_EQUALS),
  712. res = Exec_ExecToken(op, l, r);
  713. printf("%d", COMPARE_PARSER_TOKEN(res, {e_TOKEN_TYPE_BOOL, _:true}));
  714. MAKE_TOKEN(l, e_TOKEN_TYPE_INT, 555),
  715. MAKE_TOKEN(r, e_TOKEN_TYPE_INT, 101),
  716. MAKE_TOKEN(op, e_TOKEN_TYPE_OP, e_TOKEN_OP_GREATER),
  717. res = Exec_ExecToken(op, l, r);
  718. printf("%d", COMPARE_PARSER_TOKEN(res, {e_TOKEN_TYPE_BOOL, _:true}));
  719. MAKE_TOKEN(l, e_TOKEN_TYPE_INT, 65),
  720. MAKE_TOKEN(r, e_TOKEN_TYPE_INT, 101),
  721. MAKE_TOKEN(op, e_TOKEN_TYPE_OP, e_TOKEN_OP_GREATER),
  722. res = Exec_ExecToken(op, l, r);
  723. printf("%d", COMPARE_PARSER_TOKEN(res, {e_TOKEN_TYPE_BOOL, _:false}));
  724. MAKE_TOKEN(l, e_TOKEN_TYPE_INT, 65),
  725. MAKE_TOKEN(r, e_TOKEN_TYPE_INT, 0),
  726. MAKE_TOKEN(op, e_TOKEN_TYPE_OP, e_TOKEN_OP_AND),
  727. res = Exec_ExecToken(op, l, r);
  728. printf("%d", COMPARE_PARSER_TOKEN(res, {e_TOKEN_TYPE_BOOL, _:false}));
  729. MAKE_TOKEN(l, e_TOKEN_TYPE_INT, 65),
  730. MAKE_TOKEN(r, e_TOKEN_TYPE_INT, 0),
  731. MAKE_TOKEN(op, e_TOKEN_TYPE_OP, e_TOKEN_OP_OR),
  732. res = Exec_ExecToken(op, l, r);
  733. printf("%d", COMPARE_PARSER_TOKEN(res, {e_TOKEN_TYPE_BOOL, _:true}));
  734. MAKE_TOKEN(l, e_TOKEN_TYPE_INT, 65),
  735. MAKE_TOKEN(r, e_TOKEN_TYPE_INT, 33),
  736. MAKE_TOKEN(op, e_TOKEN_TYPE_OP, e_TOKEN_OP_AND),
  737. res = Exec_ExecToken(op, l, r);
  738. printf("%d", COMPARE_PARSER_TOKEN(res, {e_TOKEN_TYPE_BOOL, _:true}));
  739. MAKE_TOKEN(l, e_TOKEN_TYPE_INT, 0),
  740. MAKE_TOKEN(r, e_TOKEN_TYPE_INT, 0),
  741. MAKE_TOKEN(op, e_TOKEN_TYPE_OP, e_TOKEN_OP_OR),
  742. res = Exec_ExecToken(op, l, r);
  743. printf("%d", COMPARE_PARSER_TOKEN(res, {e_TOKEN_TYPE_BOOL, _:false}));
  744. MAKE_TOKEN(l, e_TOKEN_TYPE_NONE, 0),
  745. MAKE_TOKEN(r, e_TOKEN_TYPE_INT, 7),
  746. MAKE_TOKEN(op, e_TOKEN_TYPE_OP, e_TOKEN_OP_NEG),
  747. res = Exec_ExecToken(op, l, r);
  748. printf("%d", COMPARE_PARSER_TOKEN(res, {e_TOKEN_TYPE_INT, -7}));
  749. MAKE_TOKEN(l, e_TOKEN_TYPE_NONE, 0),
  750. MAKE_TOKEN(r, e_TOKEN_TYPE_FLOAT, _:88.43),
  751. MAKE_TOKEN(op, e_TOKEN_TYPE_OP, e_TOKEN_OP_NEG),
  752. res = Exec_ExecToken(op, l, r);
  753. printf("%d", COMPARE_PARSER_TOKEN(res, {e_TOKEN_TYPE_FLOAT, _:-88.43}));
  754. new testArr[55][66];
  755. MAKE_TOKEN(l, e_TOKEN_TYPE_ARRAY | (e_TOKEN_TYPE:2 << TOKEN_TYPE_SHIFT), ref(testArr)),
  756. MAKE_TOKEN(r, e_TOKEN_TYPE_INT, 5),
  757. MAKE_TOKEN(op, e_TOKEN_TYPE_INDEX, 0),
  758. res = Exec_ExecToken(op, l, r);
  759. printf("%d", COMPARE_PARSER_TOKEN(res, {e_TOKEN_TYPE_ARRAY | (e_TOKEN_TYPE:1 << TOKEN_TYPE_SHIFT), ReadAmxMemory(ref(testArr) + 20)}));
  760. new testVar;
  761. MAKE_TOKEN(l, e_TOKEN_TYPE_VAR, ref(testVar)),
  762. MAKE_TOKEN(r, e_TOKEN_TYPE_INT, 7),
  763. MAKE_TOKEN(op, e_TOKEN_TYPE_OP, e_TOKEN_OP_ASSIGN),
  764. res = Exec_ExecToken(op, l, r);
  765. printf("%d", COMPARE_PARSER_TOKEN(res, {e_TOKEN_TYPE_INT, 7}));
  766. printf("%d", testVar);
  767. new testA2[10];
  768. MAKE_TOKEN(l, e_TOKEN_TYPE_ARRAY, ref(testA2)),
  769. MAKE_TOKEN(r, e_TOKEN_TYPE_INT, 5),
  770. MAKE_TOKEN(op, e_TOKEN_TYPE_INDEX, 0),
  771. res = Exec_ExecToken(op, l, r);
  772. MAKE_TOKEN(r, e_TOKEN_TYPE_INT, 42),
  773. MAKE_TOKEN(op, e_TOKEN_TYPE_OP, e_TOKEN_OP_ASSIGN),
  774. res = Exec_ExecToken(op, res, r);
  775. //printf("%d", COMPARE_PARSER_TOKEN(res, {e_TOKEN_TYPE_INT, 7}));
  776. printf("%d", testA2[5]);
  777. }
  778. #endif