/src/ftk_expr.c

http://ftk.googlecode.com/ · C · 341 lines · 266 code · 37 blank · 38 comment · 57 complexity · d05260887f3b581a64d8991c1e82e4da MD5 · raw file

  1. /*
  2. * File: expr.c
  3. * Author: Li XianJing <xianjimli@hotmail.com>
  4. * Brief: express eval
  5. *
  6. * Copyright (c) 2009 - 2010 Li XianJing <xianjimli@hotmail.com>
  7. *
  8. * Licensed under the Academic Free License version 2.1
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  23. */
  24. /*
  25. * History:
  26. * ================================================================
  27. * 2009-07-17 Li XianJing <xianjimli@hotmail.com> created
  28. * 2010-10-02 Jiao JinXing <jiaojinxing1987@gmail.com> add rt-thread support.
  29. *
  30. */
  31. #include <stdlib.h>
  32. #ifndef RT_THREAD
  33. #include <stdio.h>
  34. #endif
  35. #include <ctype.h>
  36. #include <assert.h>
  37. #include "ftk_util.h"
  38. typedef enum tagToken
  39. {
  40. TOK_NONE,
  41. TOK_ADD, //'+'
  42. TOK_OR, //'|'
  43. TOK_AND, //'&'
  44. TOK_SUB, //'-'
  45. TOK_MULTI, //'*'
  46. TOK_DIV, //'/'
  47. TOK_LPAREN, //'('
  48. TOK_RPAREN, //')'
  49. TOK_NUM, //number
  50. TOK_NR
  51. }Token;
  52. typedef struct tagLex
  53. {
  54. const char* buffer;
  55. size_t read_pos;
  56. double val;
  57. Token token_type;
  58. int b_unget_token;
  59. }Lex, *PLex;
  60. static double EvalExpr(PLex pLex);
  61. static void LexGetNumToken(PLex thiz)
  62. {
  63. enum
  64. {
  65. STAT_NONE,
  66. STAT_AFTER_0,
  67. STAT_AFTER_X,
  68. STAT_FINISH
  69. }state = STAT_NONE;
  70. thiz->val = 0;
  71. for(;thiz->buffer[thiz->read_pos] != '\0' && state != STAT_FINISH; thiz->read_pos++)
  72. {
  73. char c = thiz->buffer[thiz->read_pos];
  74. switch(state)
  75. {
  76. case STAT_NONE:
  77. {
  78. if(c == '0')
  79. {
  80. state = STAT_AFTER_0;
  81. }
  82. else
  83. {
  84. thiz->val = ftk_atof(thiz->buffer+thiz->read_pos);
  85. state = STAT_FINISH;
  86. }
  87. break;
  88. }
  89. case STAT_AFTER_0:
  90. {
  91. if(c == 'x' || c == 'X')
  92. {
  93. state = STAT_AFTER_X;
  94. }
  95. else if(c == '.')
  96. {
  97. thiz->val = ftk_atof(thiz->buffer+thiz->read_pos);
  98. state = STAT_FINISH;
  99. }
  100. else
  101. {
  102. thiz->val = ftk_strtol(thiz->buffer+thiz->read_pos, NULL, 8);
  103. state = STAT_FINISH;
  104. }
  105. break;
  106. }
  107. case STAT_AFTER_X:
  108. {
  109. thiz->val = ftk_strtol(thiz->buffer+thiz->read_pos, NULL, 16);
  110. state = STAT_FINISH;
  111. break;
  112. }
  113. default:break;
  114. }
  115. }
  116. while(thiz->buffer[thiz->read_pos] != '\0' &&
  117. (isdigit(thiz->buffer[thiz->read_pos]) || thiz->buffer[thiz->read_pos] == '.'))
  118. {
  119. ++thiz->read_pos;
  120. }
  121. return;
  122. }
  123. static Token LexGetToken(PLex thiz)
  124. {
  125. assert(thiz != NULL && thiz->buffer != NULL);
  126. if(thiz == NULL || thiz->buffer == NULL || thiz->buffer[thiz->read_pos] == '\0')
  127. {
  128. thiz->token_type = TOK_NONE;
  129. return thiz->token_type;
  130. }
  131. if(thiz->b_unget_token)
  132. {
  133. thiz->b_unget_token = !thiz->b_unget_token;
  134. return thiz->token_type;
  135. }
  136. thiz->token_type = TOK_NONE;
  137. while(thiz->buffer[thiz->read_pos] != '\0')
  138. {
  139. switch(thiz->buffer[thiz->read_pos])
  140. {
  141. case '+':
  142. {
  143. thiz->token_type = TOK_ADD;
  144. break;
  145. }
  146. case '|':
  147. {
  148. thiz->token_type = TOK_OR;
  149. break;
  150. }
  151. case '&':
  152. {
  153. thiz->token_type = TOK_AND;
  154. break;
  155. }
  156. case '-':
  157. {
  158. thiz->token_type = TOK_SUB;
  159. break;
  160. }
  161. case '*':
  162. {
  163. thiz->token_type = TOK_MULTI;
  164. break;
  165. }
  166. case '/':
  167. {
  168. thiz->token_type = TOK_DIV;
  169. break;
  170. }
  171. case '(':
  172. {
  173. thiz->token_type = TOK_LPAREN;
  174. break;
  175. }
  176. case ')':
  177. {
  178. thiz->token_type = TOK_LPAREN;
  179. break;
  180. }
  181. default:
  182. {
  183. if(isdigit(thiz->buffer[thiz->read_pos]))
  184. {
  185. LexGetNumToken(thiz);
  186. thiz->token_type = TOK_NUM;
  187. }
  188. else
  189. {
  190. //skip invalid cahr.
  191. }
  192. break;
  193. }
  194. }
  195. if(thiz->token_type != TOK_NUM)
  196. {
  197. ++thiz->read_pos;
  198. }
  199. if(thiz->token_type != TOK_NONE)
  200. {
  201. break;
  202. }
  203. }
  204. return thiz->token_type;
  205. }
  206. static void LexUngetToken(PLex thiz)
  207. {
  208. assert(thiz != NULL && thiz->buffer != NULL);
  209. thiz->b_unget_token = !thiz->b_unget_token;
  210. return;
  211. }
  212. //<FACTOR> ::= ( <EXPR> ) | number
  213. static double EvalFactor(PLex pLex)
  214. {
  215. double val = 0;
  216. Token token_type = LexGetToken(pLex);
  217. switch(token_type)
  218. {
  219. case TOK_LPAREN:
  220. {
  221. val = EvalExpr(pLex);
  222. break;
  223. }
  224. case TOK_NUM:
  225. {
  226. val = pLex->val;
  227. break;
  228. }
  229. default:
  230. {
  231. //unexpected token.
  232. break;
  233. }
  234. }
  235. return val;
  236. }
  237. //<TERM> ::= <FACTOR> { <MULOP> <FACTOR> }
  238. //<MULOP> ::= * | /
  239. static double EvalTerm(PLex pLex)
  240. {
  241. double val = EvalFactor(pLex);
  242. Token token_type = LexGetToken(pLex);
  243. while(token_type == TOK_MULTI || token_type == TOK_DIV)
  244. {
  245. if(token_type == TOK_MULTI)
  246. {
  247. val *= EvalFactor(pLex);
  248. }
  249. else
  250. {
  251. val /= EvalFactor(pLex);
  252. }
  253. token_type = LexGetToken(pLex);
  254. }
  255. LexUngetToken(pLex);
  256. return val;
  257. }
  258. //EXPR ::= TERM { ADDOP TERM }
  259. //ADDOP ::= + | -
  260. static double EvalExpr(PLex pLex)
  261. {
  262. double val = EvalTerm(pLex);
  263. Token token_type = LexGetToken(pLex);
  264. while(token_type == TOK_ADD || token_type == TOK_SUB
  265. || token_type == TOK_OR || token_type == TOK_AND)
  266. {
  267. switch(token_type)
  268. {
  269. case TOK_ADD:
  270. {
  271. val += EvalTerm(pLex);
  272. break;
  273. }
  274. case TOK_SUB:
  275. {
  276. val -= EvalTerm(pLex);
  277. break;
  278. }
  279. case TOK_OR:
  280. {
  281. int value = (unsigned int)val | (unsigned int)EvalTerm(pLex);
  282. val = value;
  283. break;
  284. }
  285. case TOK_AND:
  286. {
  287. int value = (unsigned int)val & (unsigned int)EvalTerm(pLex);
  288. val = value;
  289. break;
  290. }
  291. default:break;
  292. }
  293. token_type = LexGetToken(pLex);
  294. }
  295. //LexUngetToken(pLex);
  296. return val;
  297. }
  298. double ftk_expr_eval(const char* expr)
  299. {
  300. Lex aLex = {0};
  301. aLex.buffer = expr;
  302. aLex.read_pos = 0;
  303. return EvalExpr(&aLex);
  304. }