Fast IFS using RPN notation
python
c
x86-64
nasm
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. /*
  2. * Copyright (C) 2020 Weber Yann
  3. *
  4. * This file is part of pyrpn.
  5. *
  6. * pyrpn is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * any later version.
  10. *
  11. * pyrpn is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with pyrpn. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "rpn_parse.h"
  20. /**@brief Macro for @ref rpn_ops member definition
  21. * @param NAME @ref rpn_lib.h symbol
  22. * @param s The short (1 char) symbol code
  23. * @param l The long (char*) symbole code
  24. */
  25. #define __op(NAME, s, l) {&NAME, &CODE_SZ(NAME), s, l}
  26. const rpn_op_t rpn_ops[] = {\
  27. __op(rpn_add, '+', "add"),\
  28. __op(rpn_sub, '-', "sub"),\
  29. __op(rpn_div, '/', "div"),\
  30. __op(rpn_mul, '*', "mul"),\
  31. __op(rpn_mod, '%', "mod"),\
  32. __op(rpn_neg, '!', "neg"),\
  33. __op(rpn_not, '~', "not"),\
  34. __op(rpn_and, '&', "and"),\
  35. __op(rpn_or, '|', "or"),\
  36. __op(rpn_xor, '^', "xor"),\
  37. __op(rpn_shr, 'r', ">>"),\
  38. __op(rpn_shl, 'l', "<<"),\
  39. __op(rpn_xchg, 'x', "xchg"),\
  40. __op(rpn_dup, 'd', "dup"),\
  41. __op(rpn_pop_op, 'p', "pop"),\
  42. };
  43. #undef __op
  44. const size_t RPN_OP_SZ = (sizeof(rpn_ops) / sizeof(rpn_op_t));
  45. int rpn_tokenizer_start(rpn_tokenizer_t *tokenizer, rpn_tokenized_t *dst,
  46. const char* expr, size_t argc)
  47. {
  48. int err;
  49. bzero(tokenizer, sizeof(rpn_tokenizer_t));
  50. tokenizer->orig = expr;
  51. tokenizer->toks = dst;
  52. tokenizer->toks->argc = argc;
  53. tokenizer->toks->tokens_sz = 0;
  54. tokenizer->toks->tokens = NULL;
  55. if(!(tokenizer->buff = strdup(expr)))
  56. {
  57. err = errno;
  58. snprintf(tokenizer->err_reason, 64,
  59. "Error duplicating expression for tokenization : %s",
  60. strerror(err));
  61. errno = err;
  62. return -1;
  63. }
  64. tokenizer->cur = tokenizer->buff;
  65. return 0;
  66. }
  67. rpn_token_t* rpn_tok(rpn_tokenizer_t *tokenizer)
  68. {
  69. char *token;
  70. rpn_token_t ret, *tmp, *res;
  71. int err;
  72. token = tokenizer->cur;
  73. if(!*token) // end of expression
  74. {
  75. rpn_tokenizer_free(tokenizer);
  76. return NULL;
  77. }
  78. while(*(tokenizer->cur))
  79. {
  80. if(*(tokenizer->cur) == ' ' ||
  81. *(tokenizer->cur) == '\n' ||
  82. *(tokenizer->cur) == '\t')
  83. {
  84. break;
  85. }
  86. tokenizer->cur++;
  87. tokenizer->chr_no++;
  88. }
  89. if(*(tokenizer->cur))
  90. {
  91. // not end, go on next chr for further rpn_tok calls
  92. *(tokenizer->cur) = '\0';
  93. tokenizer->cur++;
  94. tokenizer->chr_no++;
  95. }
  96. // we have a clean token '\0' terminated
  97. if(rpn_tokenize(token, &ret, tokenizer->err_reason) < 0)
  98. {
  99. errno = 0;
  100. return NULL;
  101. }
  102. if(ret.type == RPN_arg && ret.arg_n >= tokenizer->toks->argc)
  103. {
  104. // invalid argument number
  105. if(tokenizer->toks->argc)
  106. {
  107. snprintf(tokenizer->err_reason, 64,
  108. "Argument number is too big : should be in [0..%ld] but \"%s\" found",
  109. tokenizer->toks->argc - 1, token);
  110. }
  111. else
  112. {
  113. snprintf(tokenizer->err_reason, 64,
  114. "No argument accepted but \"%s\" found",
  115. token);
  116. }
  117. errno = EINVAL;
  118. return NULL;
  119. }
  120. if(tokenizer->toks->tokens_sz >= tokenizer->allocated_toks)
  121. {
  122. tokenizer->allocated_toks += 8;
  123. tmp = realloc(tokenizer->toks->tokens,
  124. sizeof(rpn_token_t) * tokenizer->allocated_toks);
  125. if(!tmp)
  126. {
  127. err = errno;
  128. snprintf(tokenizer->err_reason, 64,
  129. "Unable to realloc tokens list : %s",
  130. strerror(err));
  131. errno = err;
  132. return NULL;
  133. }
  134. tokenizer->toks->tokens = tmp;
  135. }
  136. res = &(tokenizer->toks->tokens[tokenizer->toks->tokens_sz]);
  137. *res = ret;
  138. tokenizer->toks->tokens_sz++;
  139. return res;
  140. }
  141. int rpn_tokenize(const char *token, rpn_token_t *dst, char error[64])
  142. {
  143. int rep;
  144. unsigned long num;
  145. const char *orig;
  146. if((rep = rpn_match_token_i(token)) >= 0)
  147. {
  148. dst->type = RPN_op;
  149. dst->op_n = rep;
  150. dst->op = &(rpn_ops[rep]);
  151. return 0;
  152. }
  153. orig = token;
  154. if(*token == 'A')
  155. {
  156. if(!token[1])
  157. {
  158. snprintf(error, 64,
  159. "Argument number is missing, lonely \"A \" found");
  160. return -1;
  161. }
  162. dst->type = RPN_arg;
  163. token++;
  164. }
  165. else
  166. {
  167. dst->type = RPN_val;
  168. }
  169. if(rpn_match_number(token, &num) < 0)
  170. {
  171. snprintf(error, 64,
  172. "Invalid %snumber : \"%s\"",
  173. dst->type == RPN_arg?"argument ":"constant ",
  174. orig);
  175. return -1;
  176. }
  177. if(dst->type == RPN_arg)
  178. {
  179. dst->arg_n = num;
  180. }
  181. else
  182. {
  183. dst->value = num;
  184. }
  185. return 0;
  186. }
  187. void rpn_tokenizer_free(rpn_tokenizer_t *tokenizer)
  188. {
  189. if(tokenizer->buff)
  190. {
  191. free(tokenizer->buff);
  192. bzero(tokenizer, sizeof(rpn_tokenizer_t));
  193. }
  194. }
  195. char* rpn_tokenized_expr(const rpn_tokenized_t *tokens, char long_op)
  196. {
  197. size_t expr_sz, i;
  198. int err, written;
  199. char *cur, *tmp, *expr;
  200. rpn_token_t *token;
  201. int ALLOC_CHUNK=22; /* 64 bit uint is 20 decimal digit */
  202. #ifdef DEBUG
  203. if(!tokens)
  204. {
  205. dprintf(2, "Error, NULL ptr given to rpn_rokenize_expr");
  206. err = EINVAL;
  207. goto ret_err;
  208. }
  209. #endif
  210. errno = 0;
  211. err = 0;
  212. expr_sz = 0;
  213. expr_sz = 128;
  214. cur = expr = malloc(sizeof(char)*expr_sz);
  215. if(!expr)
  216. {
  217. err=errno;
  218. dprintf(2,"Error allocating memory for expression : %s",
  219. strerror(err));
  220. goto ret_err;
  221. }
  222. for(i=0; i<tokens->tokens_sz; i++)
  223. {
  224. token = &(tokens->tokens[i]);
  225. if((size_t)(cur - expr) >= (expr_sz - ALLOC_CHUNK))
  226. {
  227. expr_sz += 128;
  228. tmp = realloc(expr, sizeof(char) * expr_sz);
  229. if(!tmp)
  230. {
  231. err=errno;
  232. dprintf(2,"Error allocating memory for expression : %s",
  233. strerror(err));
  234. goto free_err;
  235. }
  236. cur = tmp + (cur - expr);
  237. expr = tmp;
  238. }
  239. switch(token->type)
  240. {
  241. case RPN_op:
  242. if(!long_op)
  243. {
  244. *cur = token->op->chr;
  245. cur[1] = ' ';
  246. cur[2] = '\0';
  247. written = 2;
  248. }
  249. else
  250. {
  251. written = snprintf(cur, ALLOC_CHUNK,
  252. "%s ", token->op->str);
  253. written--;
  254. }
  255. break;
  256. case RPN_arg:
  257. written = snprintf(cur, ALLOC_CHUNK,
  258. "A%lu ", token->arg_n);
  259. break;
  260. case RPN_val:
  261. written = snprintf(cur, ALLOC_CHUNK,
  262. "0x%lX ", token->value);
  263. break;
  264. default:
  265. #ifdef DEBUG
  266. dprintf(2,
  267. "Invalid token type encountered : %d\n",
  268. token->type);
  269. #endif
  270. err = EUCLEAN;
  271. goto free_err;
  272. }
  273. #ifdef DEBUG
  274. if(written > ALLOC_CHUNK)
  275. {
  276. dprintf(2, "Expression too long : %s",
  277. token->op->str);
  278. err = EINVAL;
  279. goto free_err;
  280. }
  281. #endif
  282. cur += written;
  283. }
  284. if(cur > expr)
  285. {
  286. *(cur-1) = '\0';
  287. }
  288. return expr;
  289. free_err:
  290. free(expr);
  291. ret_err:
  292. errno = err;
  293. return NULL;
  294. }
  295. const rpn_op_t* rpn_match_token(const char* token)
  296. {
  297. int rep;
  298. if((rep = rpn_match_token_i(token)) < 0)
  299. {
  300. return NULL;
  301. }
  302. return &(rpn_ops[rep]);
  303. }
  304. const rpn_op_t* rpn_op_from_opcode(unsigned char opcode)
  305. {
  306. if(opcode > RPN_OP_SZ)
  307. {
  308. return NULL;
  309. }
  310. return &(rpn_ops[opcode]);
  311. }
  312. int rpn_match_token_i(const char* token)
  313. {
  314. unsigned char i;
  315. if(token[1] == '\0') //strlen(token) == 1
  316. {
  317. foreach_rpn_ops(i)
  318. {
  319. if(rpn_ops[i].chr == token[0])
  320. {
  321. return (int)i;
  322. }
  323. }
  324. return -1;
  325. }
  326. foreach_rpn_ops(i)
  327. {
  328. if(!strncmp(rpn_ops[i].str, token, 8))
  329. {
  330. return (int)i;
  331. }
  332. }
  333. return -1;
  334. }
  335. int rpn_match_number(const char* token, unsigned long *result)
  336. {
  337. char *endptr;
  338. unsigned long long res;
  339. int base;
  340. if(*token == '\0')
  341. {
  342. return -1;
  343. }
  344. base = 10;
  345. if(*token == '0' && token[1] != '\0')
  346. {
  347. token++;
  348. if(*token == 'x')
  349. {
  350. token++;
  351. base = 16;
  352. }
  353. else if(*token == 'o')
  354. {
  355. token++;
  356. base = 8;
  357. }
  358. else if(*token == 'b')
  359. {
  360. token++;
  361. base = 2;
  362. }
  363. }
  364. res = strtoull(token, &endptr, base);
  365. if(*endptr != '\0')
  366. {
  367. return -1;
  368. }
  369. *result = res;
  370. return 0;
  371. }
  372. int rpn_token_snprintf(rpn_token_t *tok, char *dst, size_t sz)
  373. {
  374. switch(tok->type)
  375. {
  376. case RPN_op:
  377. if(tok->op->chr)
  378. {
  379. return snprintf(dst, sz, "%c", tok->op->chr);
  380. }
  381. return snprintf(dst, sz, "%s", tok->op->str);
  382. case RPN_val:
  383. return snprintf(dst, sz, "0x%lX", tok->value);
  384. case RPN_arg:
  385. return snprintf(dst, sz, "A%lu", tok->arg_n);
  386. default:
  387. errno = EINVAL;
  388. return -1;
  389. }
  390. }
  391. size_t rpn_op_sz()
  392. {
  393. return sizeof(rpn_ops)/sizeof(rpn_op_t);
  394. }