Visualization Library 2.1.0

A lightweight C++ OpenGL middleware for 2D/3D graphics

VL     Star     Watch     Fork     Issue

[Download] [Tutorials] [All Classes] [Grouped Classes]
VLTTokenizer.cpp
Go to the documentation of this file.
1 /**************************************************************************************/
2 /* */
3 /* Visualization Library */
4 /* http://visualizationlibrary.org */
5 /* */
6 /* Copyright (c) 2005-2020, Michele Bosi */
7 /* All rights reserved. */
8 /* */
9 /* Redistribution and use in source and binary forms, with or without modification, */
10 /* are permitted provided that the following conditions are met: */
11 /* */
12 /* - Redistributions of source code must retain the above copyright notice, this */
13 /* list of conditions and the following disclaimer. */
14 /* */
15 /* - Redistributions in binary form must reproduce the above copyright notice, this */
16 /* list of conditions and the following disclaimer in the documentation and/or */
17 /* other materials provided with the distribution. */
18 /* */
19 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */
20 /* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */
21 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */
22 /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */
23 /* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */
24 /* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */
25 /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */
26 /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */
27 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
28 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
29 /* */
30 /**************************************************************************************/
31 
32 #include <vlX/VLTTokenizer.hpp>
33 #include <vlCore/Log.hpp>
34 #include <vlCore/Say.hpp>
35 #include <ctime>
36 
37 using namespace vl;
38 using namespace vlX;
39 
40 bool VLTTokenizer::getToken(VLTToken& token)
41 {
42  token.mType = VLTToken::TOKEN_ERROR;
43  /*token.mString.resize(0);*/
44 
45  // Must be done before StringTurbo is declared
46  if (mRawtextBlock)
47  return getRawtextBlock(token);
48 
49  struct StringTurbo
50  {
51  inline StringTurbo(std::string* str): mString(str)
52  {
53  mPosition = 0;
54  }
55 
56  inline ~StringTurbo()
57  {
58  mBuffer[mPosition] = '\0';
59  *mString = mBuffer;
60  }
61 
62  inline void push_back(const char& ch)
63  {
64  mBuffer[mPosition++] = ch;
65  }
66 
67  inline void operator=(const char& ch)
68  {
69  mBuffer[0] = ch;
70  mPosition = 1;
71  }
72 
73  inline void operator=(const char* s)
74  {
75  size_t len = strlen(s);
76  memcpy( mBuffer, s, len);
77  mPosition = len;
78  }
79 
80  inline bool operator==(const char* str)
81  {
82  size_t len = strlen(str);
83  if (len != mPosition)
84  return false;
85  else
86  return memcmp(mBuffer, str, len) == 0;
87  }
88 
89  char mBuffer[1024*4];
90  size_t mPosition;
91  std::string* mString;
92  } string_turbo(&token.mString);
93 
94  // read chars skipping spaces
95  char ch1=0, ch2=0;
96  do
97  {
98  if (!readTextChar(ch1))
99  {
100  token.mType = VLTToken::TOKEN_EOF;
101  return true;
102  }
103 
104  if (ch1 == '\n')
105  ++mLineNumber;
106  else
107  // eat comments
108  if (ch1 == '/')
109  {
110  if(readTextChar(ch2))
111  {
112  if (ch2 == '/') // single line comment
113  {
114  // eat everything till the end of the line
115  for(ch1 = 0; readTextChar(ch1) && ch1 != '\n'; )
116  {
117  // eat everything
118  }
119  if (ch1 == '\n')
120  ++mLineNumber;
121  }
122  else
123  if (ch2 == '*') // multi line comment
124  {
125  // eat everything till the end of the line
126  while(readTextChar(ch1))
127  {
128  if (ch1 == '*' && readTextChar(ch2) && ch2 == '/')
129  {
130  ch1 = '\n'; // pretend it's a space to stay in the loop
131  break;
132  }
133  // eat everything
134  if (ch1 == '\n')
135  ++mLineNumber;
136  }
137  }
138  else
139  {
140  Log::error( Say("Line %n : unexpected character '%c' after '/'.\n") << mLineNumber << ch2 );
141  return false;
142  }
143  }
144  else
145  {
146  Log::error( Say("Line %n : unexpected end of file in comment.\n") << mLineNumber);
147  return false;
148  }
149  continue;
150  }
151 
152  } while(ch1 == ' ' || ch1 == '\t' || ch1 == '\n');
153 
154  switch(ch1)
155  {
156  case '(':
157  token.mType = VLTToken::LeftRoundBracket;
158  string_turbo = "(";
159  return true;
160 
161  case ')':
162  token.mType = VLTToken::RightRoundBracket;
163  string_turbo = ")";
164  return true;
165 
166  case '[':
167  token.mType = VLTToken::LeftSquareBracket;
168  string_turbo = "[";
169  return true;
170 
171  case ']':
172  token.mType = VLTToken::RightSquareBracket;
173  string_turbo = "]";
174  return true;
175 
176  case '{':
177  if(readTextChar(ch2) && ch2 == '<')
178  {
179  // actual data starts at the next new line
180  // eat all the spaces until the end of the current line
181  while(ch2 != '\n' && readTextChar(ch2))
182  {
183  switch(ch2)
184  {
185  case '\f':
186  case '\b':
187  case '\v':
188  case '\t':
189  case ' ':
190  continue;
191 
192  case '\n':
193  ++mLineNumber;
194  break;
195 
196  default:
197  string_turbo = ch2;
198  return false;
199  }
200  }
201 
202  if (ch2 == '\n')
203  {
204  token.mType = VLTToken::LeftFancyBracket;
205  string_turbo = "{<";
206  mRawtextBlock = true;
207  return true;
208  }
209  else
210  {
211  string_turbo = ch2;
212  return false;
213  }
214  }
215  else
216  {
217  token.mType = VLTToken::LeftCurlyBracket;
218  string_turbo = "{";
219  if(!isEndOfFile())
220  ungetToken(ch2);
221  }
222  return true;
223 
224  case '}':
225  token.mType = VLTToken::RightCurlyBracket;
226  string_turbo = "}";
227  return true;
228 
229  case '>':
230  if(readTextChar(ch2))
231  {
232  if(ch2 == '}')
233  {
234  token.mType = VLTToken::RightFancyBracket;
235  string_turbo = ">}";
236  return true;
237  }
238  else
239  {
240  Log::error( Say("Line %n : expected '}' instead of '%c' after '>'.\n") << mLineNumber << ch2 );
241  return false;
242  }
243  }
244  else
245  {
246  Log::error( Say("Line %n : unexpected end of file.\n") << mLineNumber );
247  return false;
248  }
249 
250  case '=':
251  token.mType = VLTToken::Equals;
252  string_turbo = "=";
253  return true;
254 
255  case '<':
256  string_turbo = "<";
257  while(readTextChar(ch1) && ch1 != '>')
258  {
259  if ( (ch1 >= 'a' && ch1 <= 'z') || (ch1 >= 'A' && ch1 <= 'Z') || (ch1 >= '0' && ch1 <= '9') || ch1 == '_' || ch1 == ':' )
260  string_turbo.push_back(ch1);
261  else
262  {
263  Log::error( Say("Line %n : unexpected character '%c'.\n") << mLineNumber << ch1 );
264  return false;
265  }
266  }
267  string_turbo.push_back('>');
268  if (isEndOfFile())
269  {
270  Log::error( Say("Line %n : unexpected end of file while reading object header.\n") << mLineNumber );
271  return false;
272  }
273  token.mType = VLTToken::TagHeader;
274  return true;
275 
276  case '#':
277  string_turbo = "#";
278  while(readTextChar(ch1))
279  {
280  if ( (ch1 >= 'a' && ch1 <= 'z') || (ch1 >= 'A' && ch1 <= 'Z') || (ch1 >= '0' && ch1 <= '9') || ch1 == '_' )
281  string_turbo.push_back(ch1);
282  else
283  {
284  ungetToken(ch1);
285  break;
286  }
287  }
288  if (string_turbo == "#_")
289  {
290  Log::error( Say("Line %n : illegal id '#_' found.\n") << mLineNumber );
291  return false;
292  }
293  token.mType = VLTToken::ID;
294  return true;
295 
296  case '"':
297  while(readTextChar(ch1))
298  {
299  // end string
300  if (ch1 == '"')
301  break;
302  else
303  // return found before end of string
304  if (ch1 == '\n')
305  {
306  Log::error( Say("Line %n : end of line found before end of string, did you forget a \"?.\n") << mLineNumber );
307  return false;
308  }
309  else
310  // escape sequences
311  if (ch1 == '\\' && readTextChar(ch2))
312  {
313  if (ch2 == '"')
314  ch1 = '"';
315  else
316  if (ch2 == '\\')
317  ch1 = '\\';
318  else
319  if (ch2 == 'b')
320  ch1 = '\b';
321  else
322  if (ch2 == 'f')
323  ch1 = '\f';
324  else
325  if (ch2 == 'r')
326  ch1 = '\r';
327  else
328  if (ch2 == 'n')
329  ch1 = '\n';
330  else
331  if (ch2 == 't')
332  ch1 = '\t';
333  else
334  ungetToken(ch2);
335  string_turbo.push_back(ch1);
336  }
337  else
338  // accept everyhing else
339  string_turbo.push_back(ch1);
340  }
341  if (isEndOfFile())
342  {
343  Log::error( Say("Line %n : end of file found before end of string, did you forget a \"?.\n") << mLineNumber );
344  return false;
345  }
346  else
347  {
348  token.mType = VLTToken::String;
349  return true;
350  }
351 
352  default:
353  // identifier
354  if ( (ch1 >= 'a' && ch1 <= 'z') || (ch1 >= 'A' && ch1 <= 'Z') || ch1 == '_' )
355  {
356  string_turbo.push_back(ch1);
357  while(readTextChar(ch1))
358  {
359  if ( (ch1 >= 'a' && ch1 <= 'z') || (ch1 >= 'A' && ch1 <= 'Z') || (ch1 >= '0' && ch1 <= '9') || ch1 == '_' )
360  string_turbo.push_back(ch1);
361  else
362  {
363  ungetToken(ch1);
364  break;
365  }
366  }
367  if (string_turbo == "_")
368  {
369  Log::error( Say("Line %n : unexpected character '_'.\n") << mLineNumber );
370  return false;
371  }
372  else
373  {
374  // check if it's a boolean
375  if (string_turbo == "true" || string_turbo == "false")
376  token.mType = VLTToken::Boolean;
377  else
378  token.mType = VLTToken::Identifier;
379  return true;
380  }
381  }
382  else
383  // Integer / real
384  //
385  // ACCEPTED:
386  // 123
387  // +123.123E+10 -123.123e-10
388  // +123
389  // +.123
390  // 0.123
391  // 123.123
392  //
393  // REJECTED:
394  // 01234
395  // 01.234
396  // 123.
397  // 123.123E
398  // 123.123e+
399  if ( (ch1 >= '0' && ch1 <= '9') || ch1 == '.' || ch1 == '+' || ch1 == '-' )
400  {
401  token.mType = VLTToken::TOKEN_ERROR;
402  string_turbo.push_back(ch1);
403 
404  enum { sZERO, sPLUS_MINUS, sINT, sFRAC, sPOINT, sE, sPLUS_MINUS_EXP, sEXP } state = sINT;
405 
406  if ( ch1 >= '1' && ch1 <= '9' )
407  state = sINT;
408  else
409  if (ch1 == '0')
410  state = sZERO;
411  else
412  if (ch1 == '.')
413  state = sPOINT;
414  else
415  if (ch1 == '+' || ch1 == '-')
416  state = sPLUS_MINUS;
417 
418  while(readTextChar(ch1))
419  {
420  switch(state)
421  {
422  // if starting with 0 must be 0.0-9
423  case sZERO:
424  if (ch1 == '.')
425  {
426  string_turbo.push_back(ch1);
427  state = sPOINT;
428  }
429  else
430  {
431  token.mType = VLTToken::Integer;
432  ungetToken(ch1);
433  return true;
434  }
435  break;
436 
437  case sPLUS_MINUS:
438  if (ch1 == '0')
439  {
440  string_turbo.push_back(ch1);
441  state = sZERO;
442  }
443  else
444  if (ch1 >= '1' && ch1 <= '9')
445  {
446  string_turbo.push_back(ch1);
447  state = sINT;
448  }
449  else
450  if (ch1 == '.')
451  {
452  string_turbo.push_back(ch1);
453  state = sPOINT;
454  }
455  else
456  {
457  Log::error( Say("Line %n :unexpected character '%c'.\n") << mLineNumber << ch1 );
458  return false;
459  }
460  break;
461 
462  case sINT:
463  if (ch1 >= '0' && ch1 <= '9')
464  string_turbo.push_back(ch1);
465  else
466  if (ch1 == '.')
467  {
468  string_turbo.push_back(ch1);
469  state = sPOINT;
470  }
471  else
472  {
473  token.mType = VLTToken::Integer;
474  ungetToken(ch1);
475  return true;
476  }
477  break;
478 
479  case sPOINT:
480  if (ch1 >= '0' && ch1 <= '9')
481  {
482  string_turbo.push_back(ch1);
483  state = sFRAC;
484  }
485  else
486  {
487  Log::error( Say("Line %n :unexpected character '%c'.\n") << mLineNumber << ch1 );
488  return false;
489  }
490  break;
491 
492  case sFRAC:
493  if (ch1 >= '0' && ch1 <= '9')
494  string_turbo.push_back(ch1);
495  else
496  if (ch1 == 'E' || ch1 == 'e')
497  {
498  string_turbo.push_back(ch1);
499  state = sE;
500  }
501  else
502  {
503  token.mType = VLTToken::real;
504  ungetToken(ch1);
505  return true;
506  }
507  break;
508 
509  case sE:
510  if (ch1 == '+' || ch1 == '-')
511  {
512  string_turbo.push_back(ch1);
513  state = sPLUS_MINUS_EXP;
514  }
515  else
516  {
517  Log::error( Say("Line %n :unexpected character '%c'.\n") << mLineNumber << ch1 );
518  return false;
519  }
520  break;
521 
522  case sPLUS_MINUS_EXP:
523  if (ch1 >= '0' && ch1 <= '9')
524  {
525  string_turbo.push_back(ch1);
526  state = sEXP;
527  }
528  else
529  {
530  Log::error( Say("Line %n :unexpected character '%c'.\n") << mLineNumber << ch1 );
531  return false;
532  }
533  break;
534 
535  case sEXP:
536  if (ch1 >= '0' && ch1 <= '9')
537  string_turbo.push_back(ch1);
538  else
539  {
540  token.mType = VLTToken::real;
541  ungetToken(ch1);
542  return true;
543  }
544  break;
545  }
546  }
547  // reached TOKEN_EOF in the middle of the parsing so we check where we were, note that it cannot be a Integer or a real
548  if (state == sINT)
549  {
550  token.mType = VLTToken::Integer;
551  return true;
552  }
553  else
554  if (state == sFRAC || state == sEXP)
555  {
556  token.mType = VLTToken::real;
557  return true;
558  }
559  else
560  return false;
561  }
562  else
563  {
564  Log::error( Say("Line %n : unexpected character '%c'.\n") << mLineNumber << ch1 );
565  return false;
566  }
567  }
568 }
569 //-----------------------------------------------------------------------------
570 bool VLTTokenizer::getRawtextBlock(VLTToken& token)
571 {
572  mRawtextBlock = false;
573 
574  token.mType = VLTToken::TOKEN_ERROR;
575  token.mString.resize(0);
576 
577  char ch =0;
578  while(readTextChar(ch))
579  {
580  if (ch == '\n')
581  ++mLineNumber;
582 
583  if (ch == '>')
584  {
585  // check for rawtext block end >}
586  char ch2 = 0;
587  if (readTextChar(ch2))
588  {
589  if(ch2 == '}')
590  {
591  // check if it was escaped
592  if (!token.mString.empty() && token.mString[ token.mString.size() - 1 ] == '\\')
593  {
594  token.mString.resize( token.mString.size() - 1 );
595  token.mString += ">}";
596  continue;
597  }
598  else
599  {
600  token.mType = VLTToken::RawtextBlock;
601  ungetToken('}');
602  ungetToken('>');
603  return true;
604  }
605  }
606  else
607  ungetToken(ch2);
608  }
609  }
610 
611  token.mString.push_back(ch);
612  }
613 
614  return false;
615 }
616 //-----------------------------------------------------------------------------
A simple String formatting class.
Definition: Say.hpp:124
static void error(const String &message)
Use this function to provide information about run-time errors: file not found, out of memory...
Definition: Log.cpp:165
std::string mString
A token of information as defined by VLT specification.
Visualization Library main namespace.
bool operator==(const ref< T1 > &o1, const ref< T2 > &o2)
Definition: Object.hpp:144