Задача: Разбор строки
Исходник: tokenizer, язык: C++ [code #542, hits: 10506]
автор: - [добавлен: 17.12.2007]
  1. // ПРИМЕР ИСПОЛЬЗОВАНИЯ:
  2. uzing namespace tool;
  3.  
  4. const char *s = "var a=1+1; b='string'; etc. "; // это мы будем парсить
  5.  
  6. tokenz tk(s,strlen(s));
  7. tk.break_chars("+-/*%,;=\n"); // на этом будем 'тормозить'
  8.  
  9. int token;
  10. // ну типа парсим как настояшши пацаны...
  11. while(token = tk.token())
  12. {
  13. switch(token)
  14. {
  15. case tokenz::WORD_VALUE:
  16. printf("token = %s\n",(const char*)tk.token_value());
  17. break;
  18. case tokenz::STRING_VALUE:
  19. printf("string literal = %c%s%c\n",
  20. tk.quote_used(),
  21. (const char*)tk.token_value(),
  22. tk.quote_used());
  23. break;
  24. case tokenz::BREAK_CHAR:
  25. printf("break = %c\n",tk.break_used());
  26. break;
  27. }
  28. }
  29. // собственно конец. (извиняюсь)
  30. printf("end of text.\n");
  31.  
  32. // Файл tl_tokenizer.h >>
  33. //|
  34. //| tl_tokenizer.h
  35. //|
  36. //| Copyright (c) 2001, 2002
  37. //| Andrew Fedoniouk - andrew@terra-informatica.org
  38. //| Portions: Serge Kuznetsov (a.k.a. "ComputerMage") - kuznetsov@deeptown.org
  39. //|
  40.  
  41. #ifndef __tl_tokenizer_h
  42. #define __tl_tokenizer_h
  43.  
  44. //|
  45. //|
  46. //| (semi)universal tokenizer.
  47. //|
  48. //|
  49.  
  50. #include "tl_string.h"
  51.  
  52. namespace tool
  53. {
  54. class tokenz
  55. {
  56. public:
  57. enum cvt_flag
  58. {
  59. cvt_no = 0,
  60. cvt_to_upper = 1,
  61. cvt_to_lower = 2
  62. };
  63.  
  64. enum token_types {
  65. END_OF_TEXT = 0,
  66. BREAK_CHAR,
  67. WORD_VALUE,
  68. STRING_VALUE
  69. };
  70.  
  71. protected:
  72. int _p_state; // current state
  73. cvt_flag _p_flag; // option flag
  74. char _p_curquote; // current quote char
  75.  
  76. string _token; // last token value
  77. const char* _text; // input text
  78. const char* _text_end; // input text end
  79. const char* _pos; // current pos in input
  80.  
  81. string _whites;
  82. string _breaks;
  83. string _quotes;
  84. char _eschar;
  85.  
  86. char _break_used;
  87. char _quote_used;
  88.  
  89. public:
  90.  
  91. tokenz ( const char * text, size_t text_length, cvt_flag flag = cvt_no );
  92.  
  93. void white_chars ( const char * ps ) { _whites = ps; }
  94. void break_chars ( const char * ps ) { _breaks = ps; }
  95. void quote_chars ( const char * ps ) { _quotes = ps; }
  96.  
  97. int token();
  98. string token_value();
  99.  
  100. char break_used() const { return _break_used; }
  101. char quote_used() const { return _quote_used; }
  102.  
  103. protected:
  104. int sindex ( char ch, const char *str );
  105. };
  106. }
  107. #endif //__cs_parser_h
  108.  
  109. // Файл tl_tokenizer.cpp >>
  110. #include "tl_tokenizer.h"
  111.  
  112. namespace tool
  113. {
  114. enum parser_states
  115. {
  116. IN_WHITE,
  117. IN_TOKEN,
  118. IN_QUOTE,
  119. };
  120.  
  121. tokenz::tokenz ( const char * text, size_t text_length, cvt_flag flag ) :
  122. _text(text),
  123. _text_end(text + text_length),
  124. _pos(text),
  125. _p_flag(flag),
  126. _p_state(IN_WHITE),
  127. _p_curquote(0),
  128. _whites(" \t\r"), // blank and tab
  129. _breaks(",;=\n"), // comma and carriage return
  130. _quotes("'\""), // single and double quote
  131. _eschar('\\') // "bakslash" is escape
  132. {
  133. }
  134.  
  135. // look up character in string
  136. int
  137. tokenz::sindex ( char ch, const char * str )
  138. {
  139. const char * cp;
  140. for ( cp = str; *cp; ++cp )
  141. if ( ch == *cp )
  142. return (int) ( cp - str ); // return postion of character
  143. return -1; // eol ... no match found
  144. }
  145.  
  146.  
  147. string tokenz::token_value ()
  148. {
  149. if ( _p_state == IN_QUOTE )
  150. return _token;
  151.  
  152. switch ( _p_flag )
  153. {
  154. case cvt_to_upper: // convert to upper
  155. return _token.to_upper();
  156. case cvt_to_lower: // convert to lower
  157. return _token.to_lower();
  158. default: // use as is
  159. return _token;
  160. }
  161. }
  162.  
  163. // here it is!
  164. int tokenz::token()
  165. {
  166.  
  167. if(_pos >= _text_end)
  168. return END_OF_TEXT;
  169.  
  170. int qp;
  171. char c, nc;
  172.  
  173. _break_used = 0; // initialize to null
  174. _quote_used = 0; // assume not quoted
  175.  
  176. _token.clear();
  177.  
  178. _p_state = IN_WHITE; // initialize state
  179. _p_curquote = 0; // initialize previous quote char
  180.  
  181. for ( ; _pos < _text_end; ++_pos ) // main loop
  182. {
  183. c = *_pos;
  184. if ( ( qp = sindex ( c, _breaks ) ) >= 0 ) // break
  185. {
  186. switch ( _p_state )
  187. {
  188. case IN_WHITE:
  189. ++_pos;
  190. _break_used = _breaks[qp];
  191. return BREAK_CHAR;
  192.  
  193. case IN_TOKEN: // ... get out
  194. return WORD_VALUE;
  195.  
  196. case IN_QUOTE: // keep going
  197. _token += c;
  198. break;
  199. }
  200. }
  201. else if ( ( qp = sindex ( c, _quotes ) ) >= 0 ) // quote
  202. {
  203. switch ( _p_state )
  204. {
  205. case IN_WHITE: // these are identical,
  206. _p_state = IN_QUOTE; // change states
  207. _p_curquote = _quotes [ qp ]; // save quote char
  208. _quote_used = _p_curquote; // set it as long as
  209. break; // something is in quotes
  210.  
  211. case IN_QUOTE:
  212. if ( _quotes [ qp ] == _p_curquote ) // same as the beginning quote?
  213. {
  214. _p_state = IN_WHITE;
  215. _p_curquote = 0;
  216. ++_pos;
  217. return STRING_VALUE;
  218. }
  219. else
  220. _token += c; // treat as regular char
  221. break;
  222.  
  223. case IN_TOKEN:
  224. _break_used = c; // uses quote as break char
  225. _pos++;
  226. return WORD_VALUE;
  227. }
  228. }
  229. else if ( ( qp = sindex ( c, _whites ) ) >= 0 ) // white
  230. {
  231. switch ( _p_state )
  232. {
  233. case IN_WHITE:
  234. break; // keep going
  235.  
  236. case IN_TOKEN:
  237. ++_pos;
  238. return WORD_VALUE;
  239.  
  240. case IN_QUOTE:
  241. _token += c; // it's valid here
  242. break;
  243. }
  244. }
  245. else if ( c == _eschar && (_pos < (_text_end - 1)) ) // escape
  246. {
  247. nc = *(_pos + 1);
  248. switch ( _p_state )
  249. {
  250. case IN_WHITE:
  251. --_pos;
  252. _p_state = IN_TOKEN;
  253. break;
  254. case IN_TOKEN:
  255. case IN_QUOTE:
  256. ++_pos;
  257. _token += nc;
  258. break;
  259. }
  260. }
  261. else // anything else is just a real character
  262. {
  263. switch ( _p_state )
  264. {
  265. case IN_WHITE:
  266. _p_state = IN_TOKEN; // switch states
  267.  
  268. case IN_TOKEN: // these too are
  269. case IN_QUOTE: // identical here
  270. _token += c;
  271. break;
  272. }
  273. }
  274. }
  275. // main loop
  276.  
  277. switch ( _p_state )
  278. {
  279. case IN_TOKEN:
  280. case IN_QUOTE:
  281. return WORD_VALUE;
  282. }
  283. return END_OF_TEXT;
  284. }
  285.  
  286. }
Вот где-то года четыре верой и правдой нам служит...
Может еще кому сгодится.

Источник: http://rsdn.ru/forum/Message.aspx?mid=272773&only=1

+добавить реализацию