PageRenderTime 21ms CodeModel.GetById 9ms app.highlight 9ms RepoModel.GetById 1ms app.codeStats 0ms

/src/ftk_expr.c

http://ftk.googlecode.com/
C | 341 lines | 266 code | 37 blank | 38 comment | 49 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/*
 26 * History:
 27 * ================================================================
 28 * 2009-07-17 Li XianJing <xianjimli@hotmail.com> created
 29 * 2010-10-02 Jiao JinXing <jiaojinxing1987@gmail.com> add rt-thread support.
 30 *
 31 */
 32
 33#include <stdlib.h>
 34#ifndef RT_THREAD
 35#include <stdio.h>

 36#endif
 37#include <ctype.h>
 38#include <assert.h>
 39#include "ftk_util.h"
 40
 41typedef enum tagToken
 42{
 43	TOK_NONE,   
 44	TOK_ADD,      //'+'
 45	TOK_OR,      //'|'
 46	TOK_AND,      //'&'
 47	TOK_SUB,      //'-'
 48	TOK_MULTI,    //'*'
 49	TOK_DIV,      //'/'
 50	TOK_LPAREN,   //'('
 51	TOK_RPAREN,   //')'
 52	TOK_NUM,      //number
 53	TOK_NR
 54}Token;
 55
 56typedef struct tagLex
 57{
 58	const char*  buffer;
 59	size_t read_pos;
 60	
 61	double val;
 62	Token  token_type;
 63	int    b_unget_token;
 64}Lex, *PLex;
 65
 66static double EvalExpr(PLex pLex);
 67
 68static void LexGetNumToken(PLex thiz)
 69{
 70	enum
 71	{
 72		STAT_NONE,
 73		STAT_AFTER_0,
 74		STAT_AFTER_X,
 75		STAT_FINISH
 76	}state = STAT_NONE;
 77
 78	thiz->val = 0;
 79	for(;thiz->buffer[thiz->read_pos] != '\0' && state != STAT_FINISH; thiz->read_pos++)
 80	{
 81		char c = thiz->buffer[thiz->read_pos];
 82		switch(state)
 83		{
 84			case STAT_NONE:
 85			{
 86				if(c == '0')
 87				{
 88					state = STAT_AFTER_0;
 89				}
 90				else
 91				{
 92					thiz->val = ftk_atof(thiz->buffer+thiz->read_pos);
 93					state = STAT_FINISH;
 94				}
 95				break;
 96			}
 97			case STAT_AFTER_0:
 98			{
 99				if(c == 'x' || c == 'X')
100				{
101					state = STAT_AFTER_X;
102				}
103				else if(c == '.')
104				{
105					thiz->val = ftk_atof(thiz->buffer+thiz->read_pos);
106					state = STAT_FINISH;
107				}
108				else 
109				{
110					thiz->val = ftk_strtol(thiz->buffer+thiz->read_pos, NULL, 8);
111					state = STAT_FINISH;
112				}
113				break;
114			}
115			case STAT_AFTER_X:
116			{
117				thiz->val = ftk_strtol(thiz->buffer+thiz->read_pos, NULL, 16);
118				state = STAT_FINISH;
119				break;
120			}
121			default:break;
122		}
123	}
124
125	while(thiz->buffer[thiz->read_pos] != '\0' && 
126		(isdigit(thiz->buffer[thiz->read_pos]) || thiz->buffer[thiz->read_pos] == '.'))
127	{
128		++thiz->read_pos;
129	}
130
131	return;
132}
133
134static Token LexGetToken(PLex thiz)
135{
136	assert(thiz != NULL && thiz->buffer != NULL);
137
138	if(thiz == NULL || thiz->buffer == NULL || thiz->buffer[thiz->read_pos] == '\0')
139	{
140		thiz->token_type = TOK_NONE;
141		
142		return thiz->token_type;
143	}
144
145	if(thiz->b_unget_token)
146	{
147		thiz->b_unget_token = !thiz->b_unget_token;
148		
149		return thiz->token_type;
150	}
151
152	thiz->token_type = TOK_NONE;
153
154	while(thiz->buffer[thiz->read_pos] != '\0')
155	{
156		switch(thiz->buffer[thiz->read_pos])
157		{
158			case '+':
159			{
160				thiz->token_type = TOK_ADD;
161				break;
162			}
163			case '|':
164			{
165				thiz->token_type = TOK_OR;
166				break;
167			}
168			case '&':
169			{
170				thiz->token_type = TOK_AND;
171				break;
172			}
173			case '-':
174			{
175				thiz->token_type = TOK_SUB;
176				break;
177			}
178			case '*':
179			{
180				thiz->token_type = TOK_MULTI;
181				break;
182			}
183			case '/':
184			{
185				thiz->token_type = TOK_DIV;
186				break;
187			}
188			case '(':
189			{
190				thiz->token_type = TOK_LPAREN;
191				break;
192			}
193			case ')':
194			{
195				thiz->token_type = TOK_LPAREN;
196				break;
197			}
198			default:
199			{
200				if(isdigit(thiz->buffer[thiz->read_pos]))
201				{
202					LexGetNumToken(thiz);
203					thiz->token_type = TOK_NUM;
204				}
205				else
206				{
207					//skip invalid cahr.
208				}
209				break;
210			}
211		}
212
213		if(thiz->token_type != TOK_NUM)
214		{
215			++thiz->read_pos;
216		}
217
218		if(thiz->token_type != TOK_NONE)
219		{
220			break;
221		}
222	}
223	
224	return thiz->token_type;
225}
226
227static void LexUngetToken(PLex thiz)
228{
229	assert(thiz != NULL && thiz->buffer != NULL);
230
231	thiz->b_unget_token = !thiz->b_unget_token;
232
233	return;
234}
235
236//<FACTOR> ::= ( <EXPR> ) | number
237static double EvalFactor(PLex pLex)
238{
239	double val = 0;
240	Token token_type = LexGetToken(pLex);
241	
242	switch(token_type)
243	{
244		case TOK_LPAREN:
245		{
246			val = EvalExpr(pLex);
247			break;
248		}
249		case TOK_NUM:
250		{
251			val = pLex->val;
252			break;
253		}
254		default:
255		{
256			//unexpected token.
257			break;
258		}
259	}
260
261	return val;
262}
263
264//<TERM>  ::= <FACTOR>  { <MULOP> <FACTOR> }
265//<MULOP> ::= * | /
266static double EvalTerm(PLex pLex)
267{
268	double val = EvalFactor(pLex);
269	Token token_type = LexGetToken(pLex);
270	
271	while(token_type == TOK_MULTI || token_type == TOK_DIV)
272	{
273		if(token_type == TOK_MULTI)
274		{
275			val *= EvalFactor(pLex);
276		}
277		else
278		{
279			val /= EvalFactor(pLex);
280		}
281		token_type = LexGetToken(pLex);
282	}
283
284	LexUngetToken(pLex);
285	
286	return val;
287}
288
289//EXPR  ::= TERM { ADDOP TERM }
290//ADDOP ::= + | -
291static double EvalExpr(PLex pLex)
292{
293	double val = EvalTerm(pLex);
294	Token token_type = LexGetToken(pLex);
295	
296	while(token_type == TOK_ADD || token_type == TOK_SUB
297		|| token_type == TOK_OR || token_type == TOK_AND)
298	{
299		switch(token_type)
300		{
301			case TOK_ADD:
302			{
303				val += EvalTerm(pLex);
304				break;
305			}
306			case TOK_SUB:
307			{
308				val -= EvalTerm(pLex);
309				break;
310			}
311			case TOK_OR:
312			{
313				int value = (unsigned int)val | (unsigned int)EvalTerm(pLex);
314				val = value;
315				break;
316			}
317			case TOK_AND:
318			{
319				int value = (unsigned int)val & (unsigned int)EvalTerm(pLex);
320				val = value;
321				break;
322			}
323			default:break;
324		}
325		token_type = LexGetToken(pLex);
326	}
327
328	//LexUngetToken(pLex);
329
330	return val;
331}
332		
333double ftk_expr_eval(const char* expr)
334{
335	Lex aLex = {0};
336	aLex.buffer = expr;
337	aLex.read_pos = 0;
338
339	return EvalExpr(&aLex);
340}
341