TrinityCore
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
G3D::TextInput Class Reference

A simple tokenizer for parsing text files. More...

#include <TextInput.h>

Classes

class  BadMSVCSpecial
 
class  Settings
 
class  TokenException
 
class  WrongString
 
class  WrongSymbol
 
class  WrongTokenType
 

Public Types

enum  FS { FROM_STRING }
 

Public Member Functions

 TextInput (const std::string &filename, const Settings &settings=Settings())
 
 TextInput (FS fs, const std::string &str, const Settings &settings=Settings())
 
 TextInput (FS fs, const char *str, size_t strLen, const Settings &settings=Settings())
 
bool hasMore ()
 
void pushSettings (const Settings &settings)
 
void popSettings ()
 
Token read ()
 
void read (Token &t)
 
Token readSignificant ()
 
double readNumber ()
 
int readInteger ()
 
bool readBoolean ()
 
Token readStringToken ()
 
std::string readString ()
 
void readString (const std::string &s)
 
std::string readUntilNewlineAsString ()
 
std::string readUntilDelimiterAsString (const char delimiter1, const char delimiter2= '\0')
 
Token readCommentToken ()
 
std::string readComment ()
 
void readComment (const std::string &s)
 
Token readNewlineToken ()
 
std::string readNewline ()
 
void readNewline (const std::string &s)
 
Token readSymbolToken ()
 
void readSymbolToken (Token &t)
 
std::string readSymbol ()
 
void readSymbol (const std::string &symbol)
 
void readSymbols (const std::string &s1, const std::string &s2)
 
void readSymbols (const std::string &s1, const std::string &s2, const std::string &s3)
 
void readSymbols (const std::string &s1, const std::string &s2, const std::string &s3, const std::string &s4)
 
Token peek ()
 
int peekLineNumber ()
 
int peekCharacterNumber ()
 
void push (const Token &t)
 
const std::string & filename () const
 

Static Public Member Functions

static double parseNumber (const std::string &_string)
 
static bool parseBoolean (const std::string &_string)
 

Private Member Functions

void init ()
 
int eatInputChar ()
 
int peekInputChar (int distance=0)
 
int eatAndPeekInputChar ()
 
void nextToken (Token &t)
 
void parseQuotedString (unsigned char delimiter, Token &t)
 
void initFromString (const char *str, int len, const Settings &settings)
 

Private Attributes

Array< SettingssettingsStack
 
std::deque< Tokenstack
 
Array< char > buffer
 
int currentCharOffset
 
int lineNumber
 
int charNumber
 
Settings options
 

Detailed Description

A simple tokenizer for parsing text files.

TextInput handles a superset of C++,Java, Matlab, and Bash code text including single line comments, block comments, quoted strings with escape sequences, and operators. TextInput recognizes several categories of tokens, which are separated by white space, quotation marks, or the end of a recognized operator:

The special ".." and "..." tokens are always recognized in addition to normal C++ operators. Additional tokens can be made available by changing the Settings.

Negative numbers are handled specially because of the ambiguity between unary minus and negative numbers– see the note on TextInput::read.

TextInput does not have helper functions for types with non-obvious formatting, or helpers that would be redundant. Use the serialize methods instead for parsing specific types like int, Vector3, and Color3.

Inside quoted strings escape sequences are converted. Thus the string token for ["a\\nb"] is 'a', followed by a newline, followed by 'b'. Outside of quoted strings, escape sequences are not converted, so the token sequence for [a\nb] is symbol 'a', symbol '\', symbol 'nb' (this matches what a C++ parser would do). The exception is that a specified TextInput::Settings::otherCommentCharacter preceeded by a backslash is assumed to be an escaped comment character and is returned as a symbol token instead of being parsed as a comment (this is what a LaTex or VRML parser would do).

Examples

TextInput ti(TextInput::FROM_STRING, "name = \"Max\", height = 6");
Token t;
t = ti.read();
debugAssert(t.sval == "name");
ti.read();
debugAssert(t.sval == "=");
std::string name = ti.read().sval;
ti.read();
TextInput ti(TextInput::FROM_STRING, "name = \"Max\", height = 6");
ti.readSymbols("name", "=");
std::string name = ti.readString();
ti.readSymbols(",", "height", "=");
double height = ti. readNumber();

Assumes that the file is not modified once opened.

Member Enumeration Documentation

Enumerator
FROM_STRING 
575 {FROM_STRING};
Definition: TextInput.h:575

Constructor & Destructor Documentation

G3D::TextInput::TextInput ( const std::string &  filename,
const Settings settings = Settings() 
)
1186  : options(opt) {
1187  init();
1188  if (options.sourceFileName.empty()) {
1190  }
1191 
1192  std::string zipfile;
1193  if (FileSystem::inZipfile(filename, zipfile)) {
1194  // TODO: this could be faster if we directly read the zipfile
1195  const std::string& input = readWholeFile(filename);
1196  size_t n = input.size();
1197  buffer.resize(n);
1198  System::memcpy(buffer.getCArray(), input.c_str(), n);
1199  } else {
1200  // Read directly into the array
1201  const uint64 n = FileSystem::size(filename);
1202  alwaysAssertM(n != uint64(-1), std::string("File does not exist: ") + filename);
1203  buffer.resize(size_t(n));
1204  FILE* f = FileSystem::fopen(filename.c_str(), "rb");
1205  fread(buffer.getCArray(), 1, size_t(n), f);
1206  FileSystem::fclose(f);
1207  }
1208 }
void resize(size_t n, bool shrinkIfNecessary=true)
Definition: Array.h:490
static void memcpy(void *dst, const void *src, size_t numBytes)
Definition: System.cpp:643
const std::string & filename() const
Definition: TextInput.cpp:1238
T * getCArray()
Definition: Array.h:256
static void fclose(FILE *f)
Definition: FileSystem.h:290
std::string readWholeFile(const std::string &filename)
Definition: fileutils.cpp:101
uint64_t uint64
Definition: g3dmath.h:170
void init()
Definition: TextInput.cpp:194
std::string sourceFileName
Definition: TextInput.h:325
#define input
Definition: wire_format_lite.h:242
static int64 size(const std::string &path)
Definition: FileSystem.h:462
uint64_t uint64
Definition: Define.h:149
Array< char > buffer
Definition: TextInput.h:416
Settings options
Definition: TextInput.h:446
static FILE * fopen(const char *filename, const char *mode)
Definition: FileSystem.h:282
static bool inZipfile(const std::string &path, std::string &zipfile)
Definition: FileSystem.h:264
#define alwaysAssertM(exp, message)
Definition: debugAssert.h:165

+ Here is the call graph for this function:

G3D::TextInput::TextInput ( FS  fs,
const std::string &  str,
const Settings settings = Settings() 
)

Creates input directly from a string. The first argument must be TextInput::FROM_STRING.

1226  {
1227  (void)fs;
1228  initFromString(str.c_str(), (int)str.size(), opt);
1229 }
void initFromString(const char *str, int len, const Settings &settings)
Definition: TextInput.cpp:1211

+ Here is the call graph for this function:

G3D::TextInput::TextInput ( FS  fs,
const char *  str,
size_t  strLen,
const Settings settings = Settings() 
)

Creates input directly from a fixed-length, non-NULL terminated string. The first argument must be TextInput::FROM_STRING.

1232  : options(opt) {
1233  (void)fs;
1234  initFromString(str, (int)len, opt);
1235 }
Settings options
Definition: TextInput.h:446
void initFromString(const char *str, int len, const Settings &settings)
Definition: TextInput.cpp:1211

+ Here is the call graph for this function:

Member Function Documentation

int G3D::TextInput::eatAndPeekInputChar ( )
inlineprivate

Helper function to consume the next character in the input buffer and peek at the one following (without consuming it).

478  {
479  eatInputChar();
480  return peekInputChar(0);
481  }
int eatInputChar()
Definition: TextInput.cpp:217
int peekInputChar(int distance=0)
Definition: TextInput.cpp:252

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int G3D::TextInput::eatInputChar ( )
private

Consumes the next character from the input buffer, and returns that character. Updates lineNumber and charNumber to reflect the location of the next character in the input buffer.

Note: you shouldn't be using the return value of this function in most cases. In general, you should peekInputChar() to get the next character, determine what to do with it, then consume it with this function (or with eatAndPeekInputChar()). Given that usage, in most instances you already know what this function would return!

217  {
218  // Don't go off the end
219  if (currentCharOffset >= buffer.length()) {
220  return EOF;
221  }
222 
223  unsigned char c = buffer[currentCharOffset];
225 
226  // update lineNumber and charNumber to reflect the location of the *next*
227  // character which will be read.
228 
229  // increment line number for \r, \n and \r\n which matches Token::NEWLINE parsing
230  if (c == '\r') {
231  ++lineNumber;
232  charNumber = 1;
233 
234  // check for \r\n
235  if (currentCharOffset < buffer.length()) {
236  unsigned char c2 = buffer[currentCharOffset];
237  if (c2 == '\n') {
238  c = c2;
240  }
241  }
242  } else if (c == '\n') {
243  ++lineNumber;
244  charNumber = 1;
245  } else {
246  ++charNumber;
247  }
248 
249  return c;
250 }
int length() const
Definition: Array.h:438
int charNumber
Definition: TextInput.h:442
Array< char > buffer
Definition: TextInput.h:416
int currentCharOffset
Definition: TextInput.h:422
int lineNumber
Definition: TextInput.h:432

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

const std::string & G3D::TextInput::filename ( ) const

Returns the filename from which this input is drawn, or the first few characters of the string if created from a string. If settings::filename is non-empty that will replace the true filename.

1238  {
1239  return options.sourceFileName;
1240 }
std::string sourceFileName
Definition: TextInput.h:325
Settings options
Definition: TextInput.h:446

+ Here is the caller graph for this function:

bool G3D::TextInput::hasMore ( )

Returns true while there are tokens remaining.

212  {
213  return (peek()._type != Token::END);
214 }
Definition: TextInput.h:63
Token peek()
Definition: TextInput.cpp:99

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void G3D::TextInput::init ( )
private
194  {
195  currentCharOffset = 0;
196  charNumber = 1;
198 
199  if (! options.caseSensitive) {
200  // Convert true and false symbols to all uppercase for fast comparisons
203  }
204 }
Set< std::string > trueSymbols
Definition: TextInput.h:398
bool caseSensitive
Definition: TextInput.h:391
Set< std::string > falseSymbols
Definition: TextInput.h:401
int startingLineNumberOffset
Definition: TextInput.h:331
int charNumber
Definition: TextInput.h:442
Settings options
Definition: TextInput.h:446
std::string toUpper(const std::string &x)
Definition: stringutils.cpp:216
int currentCharOffset
Definition: TextInput.h:422
int lineNumber
Definition: TextInput.h:432

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void G3D::TextInput::initFromString ( const char *  str,
int  len,
const Settings settings 
)
private
1211  {
1212  options = settings;
1213  init();
1214  if (options.sourceFileName.empty()) {
1215  if (len < 14) {
1216  options.sourceFileName = format("\"%.*s\"", len, str);
1217  } else {
1218  options.sourceFileName = format("\"%.*s...\"", 10, str);
1219  }
1220  }
1221  buffer.resize(len);
1223 }
void resize(size_t n, bool shrinkIfNecessary=true)
Definition: Array.h:490
static void memcpy(void *dst, const void *src, size_t numBytes)
Definition: System.cpp:643
T * getCArray()
Definition: Array.h:256
void init()
Definition: TextInput.cpp:194
std::string sourceFileName
Definition: TextInput.h:325
Array< char > buffer
Definition: TextInput.h:416
std::string __cdecl format(const char *fmt...) G3D_CHECK_PRINTF_ARGS
int size() const
Definition: Array.h:430
Settings options
Definition: TextInput.h:446

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void G3D::TextInput::nextToken ( Token t)
private

Read the next token, returning an END token if no more input is available.

263  {
264 
265  t._bytePosition = currentCharOffset;
266  t._line = lineNumber;
267  t._character = charNumber;
268  t._type = Token::END;
269  t._extendedType = Token::END_TYPE;
270 
271  int c = peekInputChar();
272  if (c == EOF) {
273  return;
274  }
275 
276  // loop through white space, newlines and comments
277  // found before other tokens
278  bool whitespaceDone = false;
279  while (! whitespaceDone) {
280  whitespaceDone = true;
281 
282  // generate newlines tokens for '\n' and '\r' and '\r\n'
283  while (isWhiteSpace(c)) {
285  t._type = Token::NEWLINE;
286  t._extendedType = Token::NEWLINE_TYPE;
287  t._bytePosition = currentCharOffset;
288  t._line = lineNumber;
289  t._character = charNumber;
290  t._string = c;
291 
292  int c2 = peekInputChar(1);
293  if (c == '\r' && c2 == '\n') {
294  t._string += c2;
295  }
296 
297  eatInputChar();
298  return;
299  } else {
300  // Consume the single whitespace
301  c = eatAndPeekInputChar();
302  }
303  }
304 
305  // update line and character number to include discarded whitespace
306  t._line = lineNumber;
307  t._character = charNumber;
308  t._bytePosition = currentCharOffset;
309 
310  if (isDigit(c)) {
311  // This is an unsigned number. Jump ahead for fast number reading.
312  goto numLabel;
313  }
314 
315  int c2 = peekInputChar(1);
316 
317  if ((c == '-') && isDigit(c2) && options.signedNumbers) {
318  // This is a simple number. Jump ahead for fast number reading.
319  // We treat this case specially because large (i.e., slow) files
320  // are usually large because they are full of numbers.
321  t._string = "-";
322  c = c2;
323  // Consume the minus sign
324  eatInputChar();
325  goto numLabel;
326  }
327 
328  // parse comments and generate tokens if enabled
329  std::string commentString;
330 
331  // check for line comments first
332  bool isLineComment = false;
333  if (options.cppLineComments && (c == '/' && c2 == '/')) {
334  // set start of line comment and eat markers
335  isLineComment = true;
336  eatInputChar();
337  eatInputChar();
338  } else if ( options.otherCommentCharacter &&
340  // set start of line comment and eat markers
341  isLineComment = true;
342  eatInputChar();
343  } else if ( options.otherCommentCharacter &&
345  // set start of line comment and eat markers
346  isLineComment = true;
347  eatInputChar();
348  }
349 
350  if (isLineComment) {
351 
352  // consume line comment to newline or EOF
353  c = peekInputChar();
354  while (! isNewline(c) && c != EOF) {
355  // build comment string for token
356  commentString += c;
357 
358  c = eatAndPeekInputChar();
359  }
360 
362  t._type = Token::COMMENT;
363  t._extendedType = Token::LINE_COMMENT_TYPE;
364  t._string = commentString;
365  return;
366  } else {
367  // There is whitespace after the comment (in particular, the
368  // newline that terminates the comment). There might also be
369  // whitespace at the start of the next line.
370  whitespaceDone = false;
371  }
372 
373  } else if (options.cppBlockComments && (c == '/' && c2 == '*')) {
374  // consume block comment to end-marker or EOF
375 
376  // consume both start-comment chars, can't let the trailing one
377  // help close the comment.
378  eatInputChar();
379  eatInputChar();
380 
381  // c is the next character we'll read, c2 is the one after *that*
382  c = peekInputChar();
383  c2 = peekInputChar(1);
384  while (! ((c == '*') && (c2 == '/')) && (c != EOF)) {
385  commentString += c;
386 
387  // Eat input char may consume more than one character if there is a newline
388  eatInputChar();
389 
390  c = peekInputChar();
391  c2 = peekInputChar(1);
392  }
393  eatInputChar(); // eat closing '*'
394  eatInputChar(); // eat closing '/'
395 
396  c = peekInputChar();
397 
399  t._type = Token::COMMENT;
400  t._extendedType = Token::BLOCK_COMMENT_TYPE;
401  t._string = commentString;
402  return;
403  } else {
404  // There is whitespace after the comment (in particular, the
405  // newline that terminates the comment). There might also be
406  // whitespace at the start of the next line.
407  whitespaceDone = false;
408  }
409  }
410 
411  } // while (! whitespaceDone)
412 
413  t._line = lineNumber;
414  t._character = charNumber;
415  t._bytePosition = currentCharOffset;
416 
417  // handle EOF
418  if (c == EOF) {
419  return;
420  }
421 
422  // Extended ASCII parses as itself, except for EOF
423  if (c > 127 && c < 255) {
424  t._type = Token::SYMBOL;
425  t._extendedType = Token::SYMBOL_TYPE;
426  t._string = c;
427  c = eatAndPeekInputChar();
428  }
429 
430 
431  // Perform appropriate setup for a symbol (including setting up the token
432  // string to start with c), eat the input character, and overwrite
433  // 'c' with the peeked next input character.
434 #define SETUP_SYMBOL(c) \
435  { \
436  t._type = Token::SYMBOL; \
437  t._extendedType = Token::SYMBOL_TYPE; \
438  t._string = c; \
439  c = eatAndPeekInputChar(); \
440  }
441 
442  switch (c) {
443 
444  case '@': // Simple symbols -> just themselves.
445  case '(':
446  case ')':
447  case ',':
448  case ';':
449  case '{':
450  case '}':
451  case '[':
452  case ']':
453  case '#':
454  case '$':
455  case '?':
456  case '%':
457  SETUP_SYMBOL(c);
458  return;
459 
460  case '-': // negative number, -, --, -=, or ->
461  SETUP_SYMBOL(c);
462 
463  switch (c) {
464  case '>': // ->
465  case '-': // --
466  case '=': // -=
467  t._string += c;
468  eatInputChar();
469  return;
470  }
471 
472  if (options.signedNumbers) {
473  if (isDigit(c) || (c == '.' && isDigit(peekInputChar(1)))) {
474  // Negative number. 'c' is still the first digit, and is
475  // the next input char.
476 
477  goto numLabel;
478  } else {
479  char terminal = peekInputChar(3);
480  if (options.simpleFloatSpecials && (c == 'i') && (peekInputChar(1) == 'n') && (peekInputChar(2) == 'f') &&
481  ! isLetter(terminal) && (terminal != '_')) {
482  // negative infinity
483  t._type = Token::NUMBER;
484  t._extendedType = Token::FLOATING_POINT_TYPE;
485  t._string = "-inf";
486  eatInputChar(); // i
487  eatInputChar(); // n
488  eatInputChar(); // f
489  return;
490  }
491  }
492  }
493 
494 
495  // plain -
496  return;
497 
498  case '+': // positive number, +, ++, or +=
499  SETUP_SYMBOL(c);
500 
501  switch (c) {
502  case '+': // ++
503  case '=': // +=
504  t._string += c;
505  eatInputChar();
506  return;
507  }
508 
509  if (options.signedNumbers) {
510  if (isDigit(c) || (c == '.' && isDigit(peekInputChar(1)))) {
511  // Positive number. 'c' is still the first digit, and is
512  // the next input char.
513 
514  goto numLabel;
515  } else {
516  char terminal = peekInputChar(3);
517  if (options.simpleFloatSpecials && (c == 'i') && (peekInputChar(1) == 'n') && (peekInputChar(2) == 'f') &&
518  ! isLetter(terminal) && (terminal != '_')) {
519  // positive infinity
520  t._type = Token::NUMBER;
521  t._extendedType = Token::FLOATING_POINT_TYPE;
522  t._string = "+inf";
523  eatInputChar(); // i
524  eatInputChar(); // n
525  eatInputChar(); // f
526  return;
527  }
528  }
529  }
530 
531  return;
532 
533  case ':': // : or :: or ::> or ::= or := or :>
534  SETUP_SYMBOL(c);
535 
536  if (c == ':') {
537  t._string += c;
538  eatInputChar();
539 
540  if (options.proofSymbols) {
541  c = peekInputChar(0);
542 
543  if ((c == '>') || (c == '=')) {
544  t._string += c;
545  eatInputChar();
546  }
547  }
548  } else if (options.proofSymbols && (c == '=' || c == '>')) {
549  t._string += c;
550  eatInputChar();
551  }
552  return;
553 
554  case '=': // = or == or =>
555  SETUP_SYMBOL(c);
556 
557  if (c == '=') {
558  t._string += c;
559  eatInputChar();
560  } else if (options.proofSymbols && (c == '>')) {
561  t._string += c;
562  eatInputChar();
563  }
564  return;
565 
566  case '*': // * or *=
567  case '/': // / or /=
568  case '!': // ! or !=
569  case '~': // ~ or ~=
570  case '^': // ^ or ^=
571  SETUP_SYMBOL(c);
572 
573  if (c == '=') {
574  t._string += c;
575  eatInputChar();
576  }
577  return;
578 
579  case '>': // >, >>,or >=
580  case '<': // <<, <<, or <= or <- or <:
581  case '|': // ||, ||, or |= or |-
582  case '&': // &, &&, or &=
583  {
584  int orig_c = c;
585  SETUP_SYMBOL(c);
586 
587  if ((c == '=') || (orig_c == c)) {
588  t._string += c;
589  eatInputChar();
590  } else if (options.proofSymbols) {
591  if ((orig_c == '<') && (c == '-')) {
592  t._string += c;
593  eatInputChar();
594  } else if ((orig_c == '|') && (c == '-')) {
595  t._string += c;
596  eatInputChar();
597  } else if ((orig_c == '<') && (c == ':')) {
598  t._string += c;
599 
600  c = eatAndPeekInputChar();
601 
602  if (c == ':') {
603  t._string += c;
604  eatInputChar();
605  }
606  }
607  }
608  }
609  return;
610 
611  case '\\': // backslash or escaped comment char.
612  SETUP_SYMBOL(c);
613 
614  if ((options.otherCommentCharacter != '\0'
616  || (options.otherCommentCharacter2 != '\0'
617  && c == options.otherCommentCharacter2)) {
618 
619  // escaped comment character. Return the raw comment
620  // char (no backslash).
621 
622  t._string = c;
623  eatInputChar();
624  return;
625  }
626  return;
627 
628  case '.': // number, ., .., or ...
629  if (isDigit(peekInputChar(1))) {
630  // We're parsing a float that began without a leading zero
631  goto numLabel;
632  }
633 
634  SETUP_SYMBOL(c);
635 
636  if (c == '.') { // .. or ...
637  t._string += c;
638  c = eatAndPeekInputChar();
639 
640  if (c == '.') { // ...
641  t._string += c;
642  eatInputChar();
643  }
644  return;
645  }
646 
647  return;
648 
649  } // switch (c)
650 
651 #undef SETUP_SYMBOL
652 
653 numLabel:
654  if (isDigit(c) || (c == '.')) {
655 
656  // A number. Note-- single dots have been
657  // parsed already, so a . indicates a number
658  // less than 1 in floating point form.
659 
660  // [0-9]*(\.[0-9][f]) or [0-9]+ or 0x[0-9,A-F]+
661 
662  if (t._string != "-") {
663  // If we picked up a leading "-" sign above, keep it,
664  // otherwise drop the string parsed thus far
665  t._string = "";
666  }
667  t._type = Token::NUMBER;
668  if (c == '.') {
669  t._extendedType = Token::FLOATING_POINT_TYPE;
670  } else {
671  t._extendedType = Token::INTEGER_TYPE;
672  }
673 
674  if ((c == '0') && (peekInputChar(1) == 'x')) {
675  // Hex number
676  t._string += "0x";
677 
678  // skip the 0x
679  eatInputChar();
680  eatInputChar();
681 
682  c = peekInputChar();
683  while (isDigit(c) || ((c >= 'A') && (c <= 'F')) || ((c >= 'a') && (c <= 'f'))) {
684  t._string += c;
685  c = eatAndPeekInputChar();
686  }
687 
688  } else {
689  // Non-hex number
690 
691  // Read the part before the decimal.
692  while (isDigit(c)) {
693  t._string += c;
694  c = eatAndPeekInputChar();
695  }
696 
697  // True if we are reading a floating-point special type
698  bool isSpecial = false;
699 
700  // Read the decimal, if one exists
701  if (c == '.') {
702  t._extendedType = Token::FLOATING_POINT_TYPE;
703 
704  // The '.' character was a decimal point, not the start of a
705  // method or range operator
706  t._string += c;
707  c = eatAndPeekInputChar();
708 
709  // Floating point specials (msvc format only)
710  if (options.msvcFloatSpecials && (c == '#')) {
711  isSpecial = true;
712  // We are reading a floating point special value
713  // of the form -1.#IND00, -1.#INF00, or 1.#INF00
714  // (with or without the trailing 00
715  c = eatAndPeekInputChar();
716  char test = c;
717  if (! options.caseSensitive) {
718  test = toupper(c);
719  }
720  if (test != 'I') {
721  throw BadMSVCSpecial
722  ("Incorrect floating-point special (inf or nan) "
723  "format.",
724  t.line(), charNumber);
725  }
726  c = eatAndPeekInputChar();
727  test = c;
728  if (! options.caseSensitive) {
729  test = toupper(c);
730  }
731  if (test != 'N') {
732  throw BadMSVCSpecial
733  (
734  "Incorrect floating-point special (inf or nan) "
735  "format.",
736  t.line(), charNumber);
737  }
738  t._string += "#IN";
739  c = eatAndPeekInputChar();
740  test = c;
741  if (! options.caseSensitive) {
742  test = toupper(c);
743  }
744  if ((test != 'F') && (test != 'D')) {
745  throw BadMSVCSpecial
746  (
747  "Incorrect floating-point special (inf or nan) "
748  "format.",
749  t.line(), charNumber);
750  }
751  t._string += c;
752 
753  // On older systems, there may be an extra 00 tacked on.
754  for (int j = 0; j < 2; ++j) {
755  c = eatAndPeekInputChar();
756  if (c == '0') {
757  c = eatAndPeekInputChar();
758  if (c != '0') {
759  throw BadMSVCSpecial
760  (
761  "Incorrect floating-point special (inf or nan) "
762  "format.",
763  t.line(), charNumber);
764  } else {
765  eatInputChar();
766  t._string += "00";
767  }
768  } else {
769  break;
770  }
771  }
772 
773  } else {
774 
775  // Read the part after the decimal
776  while (isDigit((char)c)) {
777  t._string += (char)c;
778  c = eatAndPeekInputChar();
779  }
780  }
781  }
782 
783  if (! isSpecial && ((c == 'e') || (c == 'E'))) {
784  // Read exponent
785  t._extendedType = Token::FLOATING_POINT_TYPE;
786  t._string += c;
787 
788  c = eatAndPeekInputChar();
789  if ((c == '-') || (c == '+')) {
790  t._string += c;
791  c = eatAndPeekInputChar();
792  }
793 
794  while (isDigit(c)) {
795  t._string += c;
796  c = eatAndPeekInputChar();
797  }
798  }
799 
800  if (! isSpecial && (t._extendedType == Token::FLOATING_POINT_TYPE) && (c == 'f')) {
801  // Trailing f on a float
802  t._string += c;
803  c = eatAndPeekInputChar();
804  }
805  }
806  return;
807 
808  } else if (isLetter(c) || (c == '_')) {
809  // Identifier or keyword
810  // [A-Za-z_][A-Za-z_0-9]*
811 
812  t._type = Token::SYMBOL;
813  t._extendedType = Token::SYMBOL_TYPE;
814  t._string = "";
815  do {
816  t._string += c;
817  c = eatAndPeekInputChar();
818  } while (isLetter(c) || isDigit(c) || (c == '_'));
819 
820  // See if this symbol is actually a boolean
821  if ((options.trueSymbols.size() > 0) || (options.falseSymbols.size() > 0)) {
822  std::string str = t._string;
823  if (! options.caseSensitive) {
824  str = toUpper(str);
825  }
826  if (options.trueSymbols.contains(str)) {
827  t._type = Token::BOOLEAN;
828  t._extendedType = Token::BOOLEAN_TYPE;
829  t._bool = true;
830  } else if (options.falseSymbols.contains(str)) {
831  t._type = Token::BOOLEAN;
832  t._extendedType = Token::BOOLEAN_TYPE;
833  t._bool = false;
834  }
835  }
836 
837  if (options.simpleFloatSpecials && ((t._string == "nan") || (t._string == "inf"))) {
838  t._type = Token::NUMBER;
839  t._extendedType = Token::FLOATING_POINT_TYPE;
840  }
841  return;
842 
843  } else if (c == '\"') {
844 
845  // Discard the double-quote.
846  eatInputChar();
847 
848  // Double quoted string
849  parseQuotedString('\"', t);
850  return;
851 
852  } else if (c == options.singleQuoteCharacter) {
853 
854  // Discard the single-quote.
855  eatInputChar();
856 
858  // Single quoted string
860  } else {
861  t._string = c;
862  t._type = Token::SYMBOL;
863  t._extendedType = Token::SYMBOL_TYPE;
864  }
865  return;
866 
867  } // end of special case tokens
868 
869  if ((c == EOF) || (c == '\0')) {
870  t._type = Token::END;
871  t._extendedType = Token::END_TYPE;
872  t._string = "";
873  return;
874  }
875 
876  // Some unknown token
877  throw format("Unrecognized token type beginning with character '%c' (ASCII %d)", c, c);
878  return;
879 }
Definition: TextInput.h:61
Definition: TextInput.h:46
Set< std::string > trueSymbols
Definition: TextInput.h:398
void parseQuotedString(unsigned char delimiter, Token &t)
Definition: TextInput.cpp:882
Definition: TextInput.h:62
Definition: TextInput.h:58
bool caseSensitive
Definition: TextInput.h:391
int eatInputChar()
Definition: TextInput.cpp:217
bool proofSymbols
Definition: TextInput.h:385
char otherCommentCharacter2
Definition: TextInput.h:284
Definition: TextInput.h:45
bool contains(const T &member) const
Definition: Set.h:54
char otherCommentCharacter
Definition: TextInput.h:279
Definition: TextInput.h:50
Definition: TextInput.h:63
Definition: TextInput.h:43
Set< std::string > falseSymbols
Definition: TextInput.h:401
Definition: TextInput.h:48
bool cppBlockComments
Definition: TextInput.h:241
bool isNewline(const unsigned char c)
Definition: stringutils.h:157
Definition: TextInput.h:60
bool msvcFloatSpecials
Definition: TextInput.h:364
bool isDigit(const unsigned char c)
Definition: stringutils.h:164
Definition: TextInput.h:47
int charNumber
Definition: TextInput.h:442
Definition: TextInput.h:59
char singleQuoteCharacter
Definition: TextInput.h:316
int size() const
Definition: Set.h:50
std::string __cdecl format(const char *fmt...) G3D_CHECK_PRINTF_ARGS
Settings options
Definition: TextInput.h:446
std::string toUpper(const std::string &x)
Definition: stringutils.cpp:216
bool generateCommentTokens
Definition: TextInput.h:293
bool isLetter(const unsigned char c)
Definition: stringutils.h:171
int peekInputChar(int distance=0)
Definition: TextInput.cpp:252
#define SETUP_SYMBOL(c)
bool isWhiteSpace(const unsigned char c)
Definition: stringutils.h:150
bool singleQuotedStrings
Definition: TextInput.h:311
bool generateNewlineTokens
Definition: TextInput.h:301
bool cppLineComments
Definition: TextInput.h:249
bool simpleFloatSpecials
Definition: TextInput.h:368
int currentCharOffset
Definition: TextInput.h:422
Definition: TextInput.h:49
int eatAndPeekInputChar()
Definition: TextInput.h:478
int lineNumber
Definition: TextInput.h:432
Definition: TextInput.h:44
bool signedNumbers
Definition: TextInput.h:305

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

bool G3D::TextInput::parseBoolean ( const std::string &  _string)
static

toLower(_string) == "true"

42  {
43  return toLower(_string) == "true";
44 }
std::string toLower(const std::string &x)
Definition: stringutils.cpp:223

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

double G3D::TextInput::parseNumber ( const std::string &  _string)
static

Includes MSVC specials parsing

46  {
47  std::string s = toLower(_string);
48  if (s == "-1.#ind00" || s == "-1.#ind" || s == "nan" || s == "NaN") {
49  return nan();
50  }
51 
52  if (s == "1.#inf00" || s == "1.#inf" || s == "inf" || s == "+inf" || s == "Infinity") {
53  return inf();
54  }
55 
56  if (s == "-1.#inf00" || s == "-1.#inf" || s == "-inf" || s == "-Infinity") {
57  return -inf();
58  }
59 
60  double n;
61  if ((_string.length() > 2) &&
62  (_string[0] == '0') &&
63  (_string[1] == 'x')) {
64  // Hex
65  uint32 i;
66  sscanf(_string.c_str(), "%x", &i);
67  n = i;
68  } else {
69  sscanf(_string.c_str(), "%lg", &n);
70  }
71 
72  return n;
73 }
double inf()
Definition: g3dmath.cpp:40
std::string toLower(const std::string &x)
Definition: stringutils.cpp:223
uint32_t uint32
Definition: Define.h:150
double nan()
Definition: g3dmath.cpp:77

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void G3D::TextInput::parseQuotedString ( unsigned char  delimiter,
Token t 
)
private

Helper for nextToken. Appends characters to t._string until the end delimiter is reached.

When called, the next character in the input buffer should be first the first character after the opening delimiter character.

882  {
883 
884  t._type = Token::STRING;
885 
886  if (delimiter == options.singleQuoteCharacter) {
887  t._extendedType = Token::SINGLE_QUOTED_TYPE;
888  } else {
889  t._extendedType = Token::DOUBLE_QUOTED_TYPE;
890  }
891 
892  while (true) {
893  // We're definitely going to consume the next input char, so we get
894  // it right now. This makes the condition handling below a bit easier.
895  int c = eatInputChar();
896 
897  if (c == EOF) {
898  // END inside a quoted string. (We finish the string.)
899  break;
900  }
901 
902  if (options.escapeSequencesInStrings && (c == '\\')) {
903  // An escaped character. We're definitely going to consume it,
904  // so we get it (and consume it) now.
905 
906  c = eatInputChar();
907 
908  switch (c) {
909  case 'r':
910  t._string += '\r';
911  break;
912  case 'n':
913  t._string += '\n';
914  break;
915  case 't':
916  t._string += '\t';
917  break;
918  case '0':
919  t._string += '\0';
920  break;
921 
922  case '\\':
923  case '\"':
924  t._string += (char)c;
925  break;
926 
927  default:
928  if (c == options.singleQuoteCharacter) {
929  t._string += (char)c;
930  break;
931  }
932 
933  if (((c == options.otherCommentCharacter) &&
934  (options.otherCommentCharacter != '\0')) ||
935  ((c == options.otherCommentCharacter2) &&
936  (options.otherCommentCharacter2 != '\0'))) {
937  t._string += c;
938  }
939  // otherwise, some illegal escape sequence; skip it.
940  break;
941 
942  } // switch
943 
944  } else if (c == delimiter) {
945  // End of the string. Already consumed the character.
946  break;
947  } else {
948  // All other chars, go on to the string. Already consumed the
949  // character.
950  t._string += (char)c;
951  }
952 
953  }
954 }
Definition: TextInput.h:57
int eatInputChar()
Definition: TextInput.cpp:217
char otherCommentCharacter2
Definition: TextInput.h:284
char otherCommentCharacter
Definition: TextInput.h:279
bool escapeSequencesInStrings
Definition: TextInput.h:269
char singleQuoteCharacter
Definition: TextInput.h:316
Settings options
Definition: TextInput.h:446
Definition: TextInput.h:41
Definition: TextInput.h:42

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Token G3D::TextInput::peek ( )

Return a copy of the next token in the input stream, but don't remove it from the input stream.

99  {
100  if (stack.size() == 0) {
101  Token t;
102  nextToken(t);
103  push(t);
104  }
105 
106  return stack.front();
107 }
std::deque< Token > stack
Definition: TextInput.h:411
void nextToken(Token &t)
Definition: TextInput.cpp:263
void push(const Token &t)
Definition: TextInput.cpp:207

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int G3D::TextInput::peekCharacterNumber ( )

Returns the character number (relative to the line) for the next token in the input stream. See also peek.

115  {
116  return peek().character();
117 }
Token peek()
Definition: TextInput.cpp:99
int character() const
Definition: TextInput.h:133

+ Here is the call graph for this function:

int G3D::TextInput::peekInputChar ( int  distance = 0)
private

Returns the next character from the input buffer, without consuming any characters. Can also be used to look deeper into the input buffer. Does not modify lineNumber or charNumber.

Parameters
distanceIndex of the character in the input buffer to peek at, relative to the next character. Default is 0, for the next character in the input buffer.
252  {
253  // Don't go off the end
254  if ((currentCharOffset + distance) >= buffer.length()) {
255  return EOF;
256  }
257 
258  unsigned char c = buffer[currentCharOffset + distance];
259  return c;
260 }
int length() const
Definition: Array.h:438
double distance(double x, double y)
Definition: g3dmath.h:731
Array< char > buffer
Definition: TextInput.h:416
int currentCharOffset
Definition: TextInput.h:422

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int G3D::TextInput::peekLineNumber ( )

Returns the line number for the next token. See also peek.

110  {
111  return peek().line();
112 }
Token peek()
Definition: TextInput.cpp:99
int line() const
Definition: TextInput.h:125

+ Here is the call graph for this function:

void G3D::TextInput::popSettings ( )
inline
596  {
597  options = settingsStack.pop();
598  }
Array< Settings > settingsStack
Definition: TextInput.h:409
Settings options
Definition: TextInput.h:446

+ Here is the call graph for this function:

void G3D::TextInput::push ( const Token t)

Take a previously read token and push it back at the front of the input stream.

Can be used in the case where more than one token of read-ahead is needed (i.e., when peek doesn't suffice).

207  {
208  stack.push_front(t);
209 }
std::deque< Token > stack
Definition: TextInput.h:411

+ Here is the caller graph for this function:

void G3D::TextInput::pushSettings ( const Settings settings)
inline

Temporarily switch parsing to use settings. Note that this will override the currently recorded sourceFilename unless you explicitly set it back.

See also
popSettings
591  {
592  settingsStack.push(options);
593  options = settings;
594  }
Array< Settings > settingsStack
Definition: TextInput.h:409
Settings options
Definition: TextInput.h:446

+ Here is the call graph for this function:

Token G3D::TextInput::read ( )

Read the next token (which will be the END token if ! hasMore()).

Signed numbers can be handled in one of two modes. If the option TextInput::Settings::signedNumbers is true, A '+' or '-' immediately before a number is prepended onto that number and if there is intervening whitespace, it is read as a separate symbol.

If TextInput::Settings::signedNumbers is false, read() does not distinguish between a plus or minus symbol next to a number and a positive/negative number itself. For example, "x - 1" and "x -1" will be parsed the same way by read().

In both cases, readNumber() will contract a leading "-" or "+" onto a number.

120  {
121  Token t;
122  read(t);
123  return t;
124 }
Token read()
Definition: TextInput.cpp:120

+ Here is the caller graph for this function:

void G3D::TextInput::read ( Token t)

Avoids the copy of read()

127  {
128  if (stack.size() > 0) {
129  t = stack.front();
130  stack.pop_front();
131  } else {
132  nextToken(t);
133  }
134 }
std::deque< Token > stack
Definition: TextInput.h:411
void nextToken(Token &t)
Definition: TextInput.cpp:263

+ Here is the call graph for this function:

bool G3D::TextInput::readBoolean ( )
957  {
958  const Token& t = read();
959 
960  if (t._type == Token::BOOLEAN) {
961  return t.boolean();
962  }
963 
964  // Push initial token back, and throw an error. We intentionally
965  // indicate that the wrong type is the type of the initial token.
966  // Logically, the number started there.
967  push(t);
968  throw WrongTokenType(options.sourceFileName, t.line(), t.character(),
969  Token::BOOLEAN, t._type);
970 }
Definition: TextInput.h:60
std::string sourceFileName
Definition: TextInput.h:325
Settings options
Definition: TextInput.h:446
void push(const Token &t)
Definition: TextInput.cpp:207
Token read()
Definition: TextInput.cpp:120

+ Here is the call graph for this function:

std::string G3D::TextInput::readComment ( )

Like readCommentToken, but returns the token's string.

Use this method (rather than readCommentToken) if you want the token's value but don't really care about its location in the input. Use of readCommentToken is encouraged for better error reporting.

1099  {
1100  return readCommentToken()._string;
1101 }
Token readCommentToken()
Definition: TextInput.cpp:1085
std::string _string
Definition: TextInput.h:74

+ Here is the call graph for this function:

void G3D::TextInput::readComment ( const std::string &  s)

Reads a specific comment token or throws either WrongTokenType or WrongString. If the next token in the input is a comment matching s, it will be consumed.

Use this method if you want to match a specific comment from the input. In that case, typically error reporting related to the token is only going to occur because of a mismatch, so no location information is needed by the caller.

WrongTokenType will be thrown if the next token in the input stream is not a comment. WrongString will be thrown if the next token in the input stream is a comment but does not match the s parameter. When an exception is thrown, no tokens are consumed.

1104  {
1105  const Token& t = readCommentToken();
1106 
1107  if (t._string == s) { // fast path
1108  return;
1109  }
1110 
1111  push(t);
1112  throw WrongString(options.sourceFileName, t.line(), t.character(),
1113  s, t._string);
1114 }
std::string sourceFileName
Definition: TextInput.h:325
Settings options
Definition: TextInput.h:446
Token readCommentToken()
Definition: TextInput.cpp:1085
void push(const Token &t)
Definition: TextInput.cpp:207

+ Here is the call graph for this function:

Token G3D::TextInput::readCommentToken ( )

Reads a comment token or throws WrongTokenType, and returns the token.

Use this method (rather than readComment) if you want the token's location as well as its value.

WrongTokenType will be thrown if the next token in the input stream is not a comment. When an exception is thrown, no tokens are consumed.

1085  {
1086  Token t;
1087  read(t);
1088 
1089  if (t._type == Token::COMMENT) { // fast path
1090  return t;
1091  }
1092 
1093  push(t);
1094  throw WrongTokenType(options.sourceFileName, t.line(), t.character(),
1095  Token::COMMENT, t._type);
1096 }
Definition: TextInput.h:61
std::string sourceFileName
Definition: TextInput.h:325
Settings options
Definition: TextInput.h:446
void push(const Token &t)
Definition: TextInput.cpp:207
Token read()
Definition: TextInput.cpp:120

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

int G3D::TextInput::readInteger ( )

Reads a number that must be in C integer format: [ '+' | '-' ] #+ | '0x'#+

973  {
974  Token t;
975  read(t);
976 
977  if (t._extendedType == Token::INTEGER_TYPE) { // common case
978  return int(t.number());
979  } else {
980  // Even if signedNumbers is disabled, readInteger attempts to
981  // read a signed number, so we handle that case here.
982  if (! options.signedNumbers
983  && (t._type == Token::SYMBOL)
984  && ((t._string == "-")
985  || (t._string == "+"))) {
986 
987  Token t2;
988  read(t2);
989 
990  if ((t2._extendedType == Token::INTEGER_TYPE)
991  && (t2._character == t._character + 1)) {
992 
993  if (t._string == "-") {
994  return (int)-t2.number();
995  } else {
996  return (int)t2.number();
997  }
998  }
999 
1000  // push back the second token.
1001  push(t2);
1002  }
1003 
1004  // Push initial token back, and throw an error. We intentionally
1005  // indicate that the wrong type is the type of the initial token.
1006  // Logically, the number started there.
1007  push(t);
1008  throw WrongTokenType(options.sourceFileName, t.line(), t.character(),
1009  Token::NUMBER, t._type);
1010  }
1011 }
Definition: TextInput.h:58
Definition: TextInput.h:45
std::string sourceFileName
Definition: TextInput.h:325
Definition: TextInput.h:59
Settings options
Definition: TextInput.h:446
void push(const Token &t)
Definition: TextInput.cpp:207
Token read()
Definition: TextInput.cpp:120
bool signedNumbers
Definition: TextInput.h:305

+ Here is the call graph for this function:

std::string G3D::TextInput::readNewline ( )

Like readNewlineToken, but returns the token's string.

Use this method (rather than readNewlineToken) if you want the token's value but don't really care about its location in the input. Use of readNewlineToken is encouraged for better error reporting.

1130  {
1131  return readNewlineToken()._string;
1132 }
std::string _string
Definition: TextInput.h:74
Token readNewlineToken()
Definition: TextInput.cpp:1117

+ Here is the call graph for this function:

void G3D::TextInput::readNewline ( const std::string &  s)

Reads a specific newline token or throws either WrongTokenType or WrongString. If the next token in the input is a newline matching s, it will be consumed.

Use this method if you want to match a specific newline from the input. In that case, typically error reporting related to the token is only going to occur because of a mismatch, so no location information is needed by the caller.

WrongTokenType will be thrown if the next token in the input stream is not a newline. WrongString will be thrown if the next token in the input stream is a newlin but does not match the s parameter. When an exception is thrown, no tokens are consumed.

1134  {
1135  const Token& t = readNewlineToken();
1136 
1137  if (t._string == s) { // fast path
1138  return;
1139  }
1140 
1141  push(t);
1142  throw WrongString(options.sourceFileName, t.line(), t.character(),
1143  s, t._string);
1144 }
std::string sourceFileName
Definition: TextInput.h:325
Settings options
Definition: TextInput.h:446
Token readNewlineToken()
Definition: TextInput.cpp:1117
void push(const Token &t)
Definition: TextInput.cpp:207

+ Here is the call graph for this function:

Token G3D::TextInput::readNewlineToken ( )

Reads a newline token or throws WrongTokenType, and returns the token.

Use this method (rather than readNewline) if you want the token's location as well as its value.

WrongTokenType will be thrown if the next token in the input stream is not a newline. When an exception is thrown, no tokens are consumed.

1117  {
1118  Token t;
1119  read(t);
1120 
1121  if (t._type == Token::NEWLINE) { // fast path
1122  return t;
1123  }
1124 
1125  push(t);
1126  throw WrongTokenType(options.sourceFileName, t.line(), t.character(),
1127  Token::NEWLINE, t._type);
1128 }
Definition: TextInput.h:62
std::string sourceFileName
Definition: TextInput.h:325
Settings options
Definition: TextInput.h:446
void push(const Token &t)
Definition: TextInput.cpp:207
Token read()
Definition: TextInput.cpp:120

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

double G3D::TextInput::readNumber ( )

Read one token (or possibly two, for minus sign) as a number or throws WrongTokenType, and returns the number.

If the first token in the input is a number, it is returned directly.

If TextInput::Settings::signedNumbers is false and the input stream contains a '+' or '-' symbol token immediately followed by a number token, both tokens will be consumed and a single token will be returned by this method.

WrongTokenType will be thrown if one of the input conditions described above is not satisfied. When an exception is thrown, no tokens are consumed.

1014  {
1015  Token t;
1016  read(t);
1017 
1018  if (t._type == Token::NUMBER) { // common case
1019  return t.number();
1020  }
1021 
1022  // Even if signedNumbers is disabled, readNumber attempts to
1023  // read a signed number, so we handle that case here.
1024  if (! options.signedNumbers
1025  && (t._type == Token::SYMBOL)
1026  && ((t._string == "-")
1027  || (t._string == "+"))) {
1028 
1029  Token t2(read());
1030 
1031  if ((t2._type == Token::NUMBER)
1032  && (t2._character == t._character + 1)) {
1033 
1034  if (t._string == "-") {
1035  return -t2.number();
1036  } else {
1037  return t2.number();
1038  }
1039  }
1040 
1041  // push back the second token.
1042  push(t2);
1043  }
1044 
1045  // Push initial token back, and throw an error. We intentionally
1046  // indicate that the wrong type is the type of the initial token.
1047  // Logically, the number started there.
1048  push(t);
1049  throw WrongTokenType(options.sourceFileName, t.line(), t.character(),
1050  Token::NUMBER, t._type);
1051 }
Definition: TextInput.h:58
std::string sourceFileName
Definition: TextInput.h:325
Definition: TextInput.h:59
Settings options
Definition: TextInput.h:446
void push(const Token &t)
Definition: TextInput.cpp:207
Token read()
Definition: TextInput.cpp:120
bool signedNumbers
Definition: TextInput.h:305

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

Token G3D::TextInput::readSignificant ( )

Calls read() until the result is not a newline or comment

24  {
25  Token t;
26  do {
27  t = read();
28  } while ((t.type() == Token::COMMENT) || (t.type() == Token::NEWLINE));
29  return t;
30 }
Definition: TextInput.h:61
Definition: TextInput.h:62
Token read()
Definition: TextInput.cpp:120

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

std::string G3D::TextInput::readString ( )

Like readStringToken, but returns the token's string.

Use this method (rather than readStringToken) if you want the token's value but don't really care about its location in the input. Use of readStringToken is encouraged for better error reporting.

1067  {
1068  return readStringToken()._string;
1069 }
Token readStringToken()
Definition: TextInput.cpp:1054
std::string _string
Definition: TextInput.h:74

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void G3D::TextInput::readString ( const std::string &  s)

Reads a specific string token or throws either WrongTokenType or WrongString. If the next token in the input is a string matching s, it will be consumed.

Use this method if you want to match a specific string from the input. In that case, typically error reporting related to the token is only going to occur because of a mismatch, so no location information is needed by the caller.

WrongTokenType will be thrown if the next token in the input stream is not a string. WrongString will be thrown if the next token in the input stream is a string but does not match the s parameter. When an exception is thrown, no tokens are consumed.

See also
readString(), readStringToken(), readUntilNewlineAsString(), readUntilDelimiterAsString()
1072  {
1073  const Token& t = readStringToken();
1074 
1075  if (t._string == s) { // fast path
1076  return;
1077  }
1078 
1079  push(t);
1080  throw WrongString(options.sourceFileName, t.line(), t.character(),
1081  s, t._string);
1082 }
Token readStringToken()
Definition: TextInput.cpp:1054
std::string sourceFileName
Definition: TextInput.h:325
Settings options
Definition: TextInput.h:446
void push(const Token &t)
Definition: TextInput.cpp:207

+ Here is the call graph for this function:

Token G3D::TextInput::readStringToken ( )

Reads a string token or throws WrongTokenType, and returns the token.

Use this method (rather than readString) if you want the token's location as well as its value.

WrongTokenType will be thrown if the next token in the input stream is not a string. When an exception is thrown, no tokens are consumed.

1054  {
1055  Token t;
1056  read(t);
1057 
1058  if (t._type == Token::STRING) { // fast path
1059  return t;
1060  }
1061 
1062  push(t);
1063  throw WrongTokenType(options.sourceFileName, t.line(), t.character(),
1064  Token::STRING, t._type);
1065 }
Definition: TextInput.h:57
std::string sourceFileName
Definition: TextInput.h:325
Settings options
Definition: TextInput.h:446
void push(const Token &t)
Definition: TextInput.cpp:207
Token read()
Definition: TextInput.cpp:120

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

std::string G3D::TextInput::readSymbol ( )

Like readSymbolToken, but returns the token's string.

Use this method (rather than readSymbolToken) if you want the token's value but don't really care about its location in the input. Use of readSymbolToken is encouraged for better error reporting.

1167  {
1168  return readSymbolToken()._string;
1169 }
Token readSymbolToken()
Definition: TextInput.cpp:1147
std::string _string
Definition: TextInput.h:74

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void G3D::TextInput::readSymbol ( const std::string &  symbol)

Reads a specific symbol token or throws either WrongTokenType or WrongSymbol. If the next token in the input is a symbol matching symbol, it will be consumed.

Use this method if you want to match a specific symbol from the input. In that case, typically error reporting related to the token is only going to occur because of a mismatch, so no location information is needed by the caller.

WrongTokenType will be thrown if the next token in the input stream is not a symbol. WrongSymbol will be thrown if the next token in the input stream is a symbol but does not match the symbol parameter. When an exception is thrown, no tokens are consumed.

1172  {
1173  Token t;
1174  readSymbolToken(t);
1175 
1176  if (t._string == symbol) { // fast path
1177  return;
1178  }
1179 
1180  push(t);
1181  throw WrongSymbol(options.sourceFileName, t.line(), t.character(),
1182  symbol, t._string);
1183 }
Token readSymbolToken()
Definition: TextInput.cpp:1147
std::string sourceFileName
Definition: TextInput.h:325
Settings options
Definition: TextInput.h:446
void push(const Token &t)
Definition: TextInput.cpp:207

+ Here is the call graph for this function:

void G3D::TextInput::readSymbols ( const std::string &  s1,
const std::string &  s2 
)
inline

Read a series of two specific symbols. See readSymbol.

804  {
805  readSymbol(s1);
806  readSymbol(s2);
807  }
std::string readSymbol()
Definition: TextInput.cpp:1167

+ Here is the call graph for this function:

void G3D::TextInput::readSymbols ( const std::string &  s1,
const std::string &  s2,
const std::string &  s3 
)
inline

Read a series of three specific symbols. See readSymbol.

813  {
814  readSymbol(s1);
815  readSymbol(s2);
816  readSymbol(s3);
817  }
std::string readSymbol()
Definition: TextInput.cpp:1167

+ Here is the call graph for this function:

void G3D::TextInput::readSymbols ( const std::string &  s1,
const std::string &  s2,
const std::string &  s3,
const std::string &  s4 
)
inline

Read a series of four specific symbols. See readSymbol.

824  {
825  readSymbol(s1);
826  readSymbol(s2);
827  readSymbol(s3);
828  readSymbol(s4);
829  }
std::string readSymbol()
Definition: TextInput.cpp:1167

+ Here is the call graph for this function:

Token G3D::TextInput::readSymbolToken ( )

Reads a symbol token or throws WrongTokenType, and returns the token.

Use this method (rather than readSymbol) if you want the token's location as well as its value.

WrongTokenType will be thrown if the next token in the input stream is not a symbol. When an exception is thrown, no tokens are consumed.

1147  {
1148  Token t;
1149  readSymbolToken(t);
1150  return t;
1151 }
Token readSymbolToken()
Definition: TextInput.cpp:1147

+ Here is the caller graph for this function:

void G3D::TextInput::readSymbolToken ( Token t)

Avoids the copy of readSymbolToken()

1154  {
1155  read(t);
1156 
1157  if (t._type == Token::SYMBOL) { // fast path
1158  return;
1159  }
1160 
1161  push(t);
1162  throw WrongTokenType(options.sourceFileName, t.line(), t.character(),
1163  Token::SYMBOL, t._type);
1164 }
Definition: TextInput.h:58
std::string sourceFileName
Definition: TextInput.h:325
Settings options
Definition: TextInput.h:446
void push(const Token &t)
Definition: TextInput.cpp:207
Token read()
Definition: TextInput.cpp:120

+ Here is the call graph for this function:

std::string G3D::TextInput::readUntilDelimiterAsString ( const char  delimiter1,
const char  delimiter2 = '\0' 
)

Read from the beginning of the next token until the following delimiter character and return the result as a string, ignoring all parsing in between. The delimiter is not returned in the string, and the following token read will begin at the delimiter or end of file token (if they are enabled for parsing).

137  {
138 /*
139  // Reset the read position back to the start of that token
140  currentCharOffset = t.bytePosition();
141  lineNumber = t.line();
142  charNumber = t.character();
143  stack.clear();
144 
145  if (currentCharOffset == buffer.size()) {
146  // End of file
147  return "";
148  }
149  */
150  std::string s;
151 
152  if (stack.size() > 0) {
153  // Need to back up. This only works if the stack is actually
154  // in proper order reflecting the real file, and doesn't
155  // contain incorrectly pushed elements.
156  Token t = stack.back();
157  stack.clear();
158  currentCharOffset = (int)t.bytePosition();
159  lineNumber = t.line();
160  charNumber = t.character();
161  }
162 
163  // Read until delimiter or eof
164  while (currentCharOffset < buffer.size()) {
165  const char c = buffer[currentCharOffset];
166  if ((c == delimiter1) || (c == delimiter2)) {
167  // Done
168  break;
169  } else {
170  s += c;
172  ++charNumber;
173  }
174  }
175 
176  return s;
177 }
std::deque< Token > stack
Definition: TextInput.h:411
int charNumber
Definition: TextInput.h:442
Array< char > buffer
Definition: TextInput.h:416
int size() const
Definition: Array.h:430
int currentCharOffset
Definition: TextInput.h:422
int lineNumber
Definition: TextInput.h:432

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

std::string G3D::TextInput::readUntilNewlineAsString ( )

Read from the beginning of the next token until the following newline and return the result as a string, ignoring all parsing in between. The newline is not returned in the string, and the following token read will be a newline or end of file token (if they are enabled for parsing).

180  {
181  return readUntilDelimiterAsString('\r', '\n');
182 }
std::string readUntilDelimiterAsString(const char delimiter1, const char delimiter2= '\0')
Definition: TextInput.cpp:137

+ Here is the call graph for this function:

Member Data Documentation

Array<char> G3D::TextInput::buffer
private

Characters to be tokenized.

int G3D::TextInput::charNumber
private

Character number (within the line) of the next character to be consumed from the input buffer. (1 indicates first character of the line).

Note that this is the character number of the next character to be consumed from the input, not the character number of the last character consumed!

int G3D::TextInput::currentCharOffset
private

Offset of current character (the next character to consumed) in input buffer.

int G3D::TextInput::lineNumber
private

Line number of next character to be consumed from the input buffer. (1 indicates first line of input.)

Note that this is the line number of the next character to be consumed from the input, not the line number of the last character consumed!

Settings G3D::TextInput::options
private

Configuration options. This includes the file name that will be reported in tokens and exceptions.

Array<Settings> G3D::TextInput::settingsStack
private
std::deque<Token> G3D::TextInput::stack
private

The documentation for this class was generated from the following files: