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.

rpn_parse.c 7.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  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. int rpn_tokenizer_start(rpn_tokenizer_t *tokenizer, rpn_tokenized_t *dst,
  45. const char* expr, size_t argc)
  46. {
  47. int err;
  48. bzero(tokenizer, sizeof(rpn_tokenizer_t));
  49. tokenizer->orig = expr;
  50. tokenizer->toks = dst;
  51. tokenizer->toks->argc = argc;
  52. tokenizer->toks->tokens_sz = 0;
  53. tokenizer->toks->tokens = NULL;
  54. if(!(tokenizer->buff = strdup(expr)))
  55. {
  56. err = errno;
  57. snprintf(tokenizer->err_reason, 64,
  58. "Error duplicating expression for tokenization : %s",
  59. strerror(err));
  60. errno = err;
  61. return -1;
  62. }
  63. tokenizer->cur = tokenizer->buff;
  64. return 0;
  65. }
  66. rpn_token_t* rpn_tok(rpn_tokenizer_t *tokenizer)
  67. {
  68. char *token;
  69. rpn_token_t ret, *tmp, *res;
  70. int err;
  71. token = tokenizer->cur;
  72. if(!*token) // end of expression
  73. {
  74. rpn_tokenizer_free(tokenizer);
  75. return NULL;
  76. }
  77. while(*(tokenizer->cur))
  78. {
  79. if(*(tokenizer->cur) == ' ' ||
  80. *(tokenizer->cur) == '\n' ||
  81. *(tokenizer->cur) == '\t')
  82. {
  83. break;
  84. }
  85. tokenizer->cur++;
  86. tokenizer->chr_no++;
  87. }
  88. if(*(tokenizer->cur))
  89. {
  90. // not end, go on next chr for further rpn_tok calls
  91. *(tokenizer->cur) = '\0';
  92. tokenizer->cur++;
  93. tokenizer->chr_no++;
  94. }
  95. // we have a clean token '\0' terminated
  96. if(rpn_tokenize(token, &ret, tokenizer->err_reason) < 0)
  97. {
  98. errno = 0;
  99. return NULL;
  100. }
  101. if(ret.type == RPN_arg && ret.arg_n >= tokenizer->toks->argc)
  102. {
  103. // invalid argument number
  104. if(tokenizer->toks->argc)
  105. {
  106. snprintf(tokenizer->err_reason, 64,
  107. "Argument number is too big : should be in [0..%ld] but \"%s\" found",
  108. tokenizer->toks->argc - 1, token);
  109. }
  110. else
  111. {
  112. snprintf(tokenizer->err_reason, 64,
  113. "No argument accepted but \"%s\" found",
  114. token);
  115. }
  116. errno = EINVAL;
  117. return NULL;
  118. }
  119. if(tokenizer->toks->tokens_sz >= tokenizer->allocated_toks)
  120. {
  121. tokenizer->allocated_toks += 8;
  122. tmp = realloc(tokenizer->toks->tokens,
  123. sizeof(rpn_token_t) * tokenizer->allocated_toks);
  124. if(!tmp)
  125. {
  126. err = errno;
  127. snprintf(tokenizer->err_reason, 64,
  128. "Unable to realloc tokens list : %s",
  129. strerror(err));
  130. errno = err;
  131. return NULL;
  132. }
  133. tokenizer->toks->tokens = tmp;
  134. }
  135. res = &(tokenizer->toks->tokens[tokenizer->toks->tokens_sz]);
  136. *res = ret;
  137. tokenizer->toks->tokens_sz++;
  138. return res;
  139. }
  140. int rpn_tokenize(const char *token, rpn_token_t *dst, char error[64])
  141. {
  142. int rep;
  143. unsigned long num;
  144. const char *orig;
  145. if((rep = rpn_match_token_i(token)) >= 0)
  146. {
  147. dst->type = RPN_op;
  148. dst->op_n = rep;
  149. dst->op = &(rpn_ops[rep]);
  150. return 0;
  151. }
  152. orig = token;
  153. if(*token == 'A')
  154. {
  155. if(!token[1])
  156. {
  157. snprintf(error, 64,
  158. "Argument number is missing, lonely \"A \" found");
  159. return -1;
  160. }
  161. dst->type = RPN_arg;
  162. token++;
  163. }
  164. else
  165. {
  166. dst->type = RPN_val;
  167. }
  168. if(rpn_match_number(token, &num) < 0)
  169. {
  170. snprintf(error, 64,
  171. "Invalid %snumber : \"%s\"",
  172. dst->type == RPN_arg?"argument ":"constant ",
  173. orig);
  174. return -1;
  175. }
  176. if(dst->type == RPN_arg)
  177. {
  178. dst->arg_n = num;
  179. }
  180. else
  181. {
  182. dst->value = num;
  183. }
  184. return 0;
  185. }
  186. void rpn_tokenizer_free(rpn_tokenizer_t *tokenizer)
  187. {
  188. if(tokenizer->buff)
  189. {
  190. free(tokenizer->buff);
  191. bzero(tokenizer, sizeof(rpn_tokenizer_t));
  192. }
  193. }
  194. char* rpn_tokenized_expr(rpn_tokenized_t *tokens, char long_op)
  195. {
  196. size_t expr_sz, i;
  197. int err, written;
  198. char *cur, *tmp, *expr;
  199. rpn_token_t *token;
  200. int ALLOC_CHUNK=22; /* 64 bit uint is 20 decimal digit */
  201. #ifdef DEBUG
  202. if(!tokens)
  203. {
  204. dprintf(2, "Error, NULL ptr given to rpn_rokenize_expr");
  205. err = EINVAL;
  206. goto ret_err;
  207. }
  208. #endif
  209. errno = 0;
  210. err = 0;
  211. expr_sz = 0;
  212. expr_sz = 128;
  213. cur = expr = malloc(sizeof(char)*expr_sz);
  214. if(!expr)
  215. {
  216. err=errno;
  217. dprintf(2,"Error allocating memory for expression : %s",
  218. strerror(err));
  219. goto ret_err;
  220. }
  221. for(i=0; i<tokens->tokens_sz; i++)
  222. {
  223. token = &(tokens->tokens[i]);
  224. if(cur - expr >= expr_sz - ALLOC_CHUNK)
  225. {
  226. expr_sz += 128;
  227. tmp = realloc(expr, sizeof(char) * expr_sz);
  228. if(!tmp)
  229. {
  230. err=errno;
  231. dprintf(2,"Error allocating memory for expression : %s",
  232. strerror(err));
  233. goto ret_err;
  234. }
  235. cur = tmp + (cur - expr);
  236. expr = tmp;
  237. }
  238. switch(token->type)
  239. {
  240. case RPN_op:
  241. if(!long_op)
  242. {
  243. *cur = token->op->chr;
  244. cur[1] = ' ';
  245. cur[2] = '\0';
  246. written = 2;
  247. }
  248. else
  249. {
  250. written = snprintf(cur, ALLOC_CHUNK,
  251. "%s ", token->op->str);
  252. written--;
  253. }
  254. break;
  255. case RPN_arg:
  256. written = snprintf(cur, ALLOC_CHUNK,
  257. "A%lu ", token->arg_n);
  258. break;
  259. case RPN_val:
  260. written = snprintf(cur, ALLOC_CHUNK,
  261. "0x%lX ", token->value);
  262. break;
  263. default:
  264. #ifdef DEBUG
  265. dprintf(2,
  266. "Invalid token type encountered : %d\n",
  267. token->type);
  268. #endif
  269. err = EUCLEAN;
  270. goto free_err;
  271. }
  272. #ifdef DEBUG
  273. if(written > ALLOC_CHUNK)
  274. {
  275. dprintf(2, "Expression too long : %s",
  276. token->op->str);
  277. err = EINVAL;
  278. goto free_err;
  279. }
  280. #endif
  281. cur += written;
  282. }
  283. return expr;
  284. free_err:
  285. free(expr);
  286. ret_err:
  287. errno = err;
  288. return NULL;
  289. }
  290. const rpn_op_t* rpn_match_token(const char* token)
  291. {
  292. int rep;
  293. if((rep = rpn_match_token_i(token)) < 0)
  294. {
  295. return NULL;
  296. }
  297. return &(rpn_ops[rep]);
  298. }
  299. int rpn_match_token_i(const char* token)
  300. {
  301. unsigned char i;
  302. if(token[1] == '\0') //strlen(token) == 1
  303. {
  304. foreach_rpn_ops(i)
  305. {
  306. if(rpn_ops[i].chr == token[0])
  307. {
  308. return (int)i;
  309. }
  310. }
  311. return -1;
  312. }
  313. foreach_rpn_ops(i)
  314. {
  315. if(!strncmp(rpn_ops[i].str, token, 8))
  316. {
  317. return (int)i;
  318. }
  319. }
  320. return -1;
  321. }
  322. int rpn_match_number(const char* token, unsigned long *result)
  323. {
  324. char *endptr;
  325. unsigned long long res;
  326. int base;
  327. if(*token == '\0')
  328. {
  329. return -1;
  330. }
  331. base = 10;
  332. if(*token == '0' && token[1] != '\0')
  333. {
  334. token++;
  335. if(*token == 'x')
  336. {
  337. token++;
  338. base = 16;
  339. }
  340. else if(*token == 'o')
  341. {
  342. token++;
  343. base = 8;
  344. }
  345. else if(*token == 'b')
  346. {
  347. token++;
  348. base = 2;
  349. }
  350. }
  351. res = strtoull(token, &endptr, base);
  352. if(*endptr != '\0')
  353. {
  354. return -1;
  355. }
  356. *result = res;
  357. return 0;
  358. }
  359. size_t rpn_op_sz()
  360. {
  361. return sizeof(rpn_ops)/sizeof(rpn_op_t);
  362. }