KiCad PCB EDA Suite
dsnlexer.cpp
Go to the documentation of this file.
1 
2 /*
3  * This program source code file is part of KiCad, a free EDA CAD application.
4  *
5  * Copyright (C) 2007-2013 SoftPLC Corporation, Dick Hollenbeck <dick@softplc.com>
6  * Copyright (C) 2007-2020 KiCad Developers, see AUTHORS.txt for contributors.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, you may find one here:
20  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
21  * or you may search the http://www.gnu.org website for the version 2 license,
22  * or you may write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
24  */
25 
26 
27 #include <cstdarg>
28 #include <cstdio>
29 #include <cstdlib> // bsearch()
30 #include <cctype>
31 
32 #include <dsnlexer.h>
33 
34 #define FMT_CLIPBOARD _( "clipboard" )
35 
36 
37 //-----<DSNLEXER>-------------------------------------------------------------
38 
40 {
41  curTok = DSN_NONE;
42  prevTok = DSN_NONE;
43 
44  stringDelimiter = '"';
45 
46  specctraMode = false;
47  space_in_quoted_tokens = false;
48  commentsAreTokens = false;
49 
50  curOffset = 0;
51 
52 #if 1
53  if( keywordCount > 11 )
54  {
55  // resize the hashtable bucket count
56  keyword_hash.reserve( keywordCount );
57  }
58 
59  // fill the specialized "C string" hashtable from keywords[]
60  const KEYWORD* it = keywords;
61  const KEYWORD* end = it + keywordCount;
62 
63  for( ; it < end; ++it )
64  {
65  keyword_hash[it->name] = it->token;
66  }
67 #endif
68 }
69 
70 
71 DSNLEXER::DSNLEXER( const KEYWORD* aKeywordTable, unsigned aKeywordCount,
72  FILE* aFile, const wxString& aFilename ) :
73  iOwnReaders( true ),
74  start( NULL ),
75  next( NULL ),
76  limit( NULL ),
77  reader( NULL ),
78  keywords( aKeywordTable ),
79  keywordCount( aKeywordCount )
80 {
81  FILE_LINE_READER* fileReader = new FILE_LINE_READER( aFile, aFilename );
82  PushReader( fileReader );
83  init();
84 }
85 
86 
87 DSNLEXER::DSNLEXER( const KEYWORD* aKeywordTable, unsigned aKeywordCount,
88  const std::string& aClipboardTxt, const wxString& aSource ) :
89  iOwnReaders( true ),
90  start( NULL ),
91  next( NULL ),
92  limit( NULL ),
93  reader( NULL ),
94  keywords( aKeywordTable ),
95  keywordCount( aKeywordCount )
96 {
97  STRING_LINE_READER* stringReader = new STRING_LINE_READER( aClipboardTxt, aSource.IsEmpty() ?
98  wxString( FMT_CLIPBOARD ) : aSource );
99  PushReader( stringReader );
100  init();
101 }
102 
103 
104 DSNLEXER::DSNLEXER( const KEYWORD* aKeywordTable, unsigned aKeywordCount,
105  LINE_READER* aLineReader ) :
106  iOwnReaders( false ),
107  start( NULL ),
108  next( NULL ),
109  limit( NULL ),
110  reader( NULL ),
111  keywords( aKeywordTable ),
112  keywordCount( aKeywordCount )
113 {
114  if( aLineReader )
115  PushReader( aLineReader );
116  init();
117 }
118 
119 
120 static const KEYWORD empty_keywords[1] = {};
121 
122 DSNLEXER::DSNLEXER( const std::string& aSExpression, const wxString& aSource ) :
123  iOwnReaders( true ),
124  start( NULL ),
125  next( NULL ),
126  limit( NULL ),
127  reader( NULL ),
128  keywords( empty_keywords ),
129  keywordCount( 0 )
130 {
131  STRING_LINE_READER* stringReader = new STRING_LINE_READER( aSExpression, aSource.IsEmpty() ?
132  wxString( FMT_CLIPBOARD ) : aSource );
133  PushReader( stringReader );
134  init();
135 }
136 
137 
139 {
140  if( iOwnReaders )
141  {
142  // delete the LINE_READERs from the stack, since I own them.
143  for( READER_STACK::iterator it = readerStack.begin(); it!=readerStack.end(); ++it )
144  delete *it;
145  }
146 }
147 
148 void DSNLEXER::SetSpecctraMode( bool aMode )
149 {
150  specctraMode = aMode;
151  if( aMode )
152  {
153  // specctra mode defaults, some of which can still be changed in this mode.
154  space_in_quoted_tokens = true;
155  }
156  else
157  {
158  space_in_quoted_tokens = false;
159  stringDelimiter = '"';
160  }
161 }
162 
163 
165 {
166  // Synchronize the pointers handling the data read by the LINE_READER
167  // only if aLexer shares the same LINE_READER, because only in this case
168  // the char buffer is be common
169 
170  if( reader != aLexer.reader )
171  return false;
172 
173  // We can synchronize the pointers which handle the data currently read
174  start = aLexer.start;
175  next = aLexer.next;
176  limit = aLexer.limit;
177 
178  // Sync these parameters is not mandatory, but could help
179  // for instance in debug
180  curText = aLexer.curText;
181  curOffset = aLexer.curOffset;
182 
183  return true;
184 }
185 
186 
187 void DSNLEXER::PushReader( LINE_READER* aLineReader )
188 {
189  readerStack.push_back( aLineReader );
190  reader = aLineReader;
191  start = (const char*) (*reader);
192 
193  // force a new readLine() as first thing.
194  limit = start;
195  next = start;
196 }
197 
198 
200 {
201  LINE_READER* ret = 0;
202 
203  if( readerStack.size() )
204  {
205  ret = reader;
206  readerStack.pop_back();
207 
208  if( readerStack.size() )
209  {
210  reader = readerStack.back();
211  start = reader->Line();
212 
213  // force a new readLine() as first thing.
214  limit = start;
215  next = start;
216  }
217  else
218  {
219  reader = 0;
220  start = dummy;
221  limit = dummy;
222  }
223  }
224  return ret;
225 }
226 
227 
228 int DSNLEXER::findToken( const std::string& tok ) const
229 {
230  KEYWORD_MAP::const_iterator it = keyword_hash.find( tok.c_str() );
231 
232  if( it != keyword_hash.end() )
233  return it->second;
234 
235  return DSN_SYMBOL; // not a keyword, some arbitrary symbol.
236 }
237 
238 
239 const char* DSNLEXER::Syntax( int aTok )
240 {
241  const char* ret;
242 
243  switch( aTok )
244  {
245  case DSN_NONE:
246  ret = "NONE";
247  break;
248  case DSN_STRING_QUOTE:
249  ret = "string_quote"; // a special DSN syntax token, see specctra spec.
250  break;
251  case DSN_QUOTE_DEF:
252  ret = "quoted text delimiter";
253  break;
254  case DSN_DASH:
255  ret = "-";
256  break;
257  case DSN_SYMBOL:
258  ret = "symbol";
259  break;
260  case DSN_NUMBER:
261  ret = "number";
262  break;
263  case DSN_RIGHT:
264  ret = ")";
265  break;
266  case DSN_LEFT:
267  ret = "(";
268  break;
269  case DSN_STRING:
270  ret = "quoted string";
271  break;
272  case DSN_EOF:
273  ret = "end of input";
274  break;
275  default:
276  ret = "???";
277  }
278 
279  return ret;
280 }
281 
282 
283 const char* DSNLEXER::GetTokenText( int aTok ) const
284 {
285  const char* ret;
286 
287  if( aTok < 0 )
288  {
289  return Syntax( aTok );
290  }
291  else if( (unsigned) aTok < keywordCount )
292  {
293  ret = keywords[aTok].name;
294  }
295  else
296  ret = "token too big";
297 
298  return ret;
299 }
300 
301 
302 wxString DSNLEXER::GetTokenString( int aTok ) const
303 {
304  wxString ret;
305 
306  ret << wxT("'") << wxString::FromUTF8( GetTokenText(aTok) ) << wxT("'");
307 
308  return ret;
309 }
310 
311 
312 bool DSNLEXER::IsSymbol( int aTok )
313 {
314  // This is static and not inline to reduce code space.
315 
316  // if aTok is >= 0, then it is a coincidental match to a keyword.
317  return aTok == DSN_SYMBOL || aTok == DSN_STRING || aTok >= 0;
318 }
319 
320 
321 void DSNLEXER::Expecting( int aTok ) const
322 {
323  wxString errText = wxString::Format(
324  _( "Expecting %s" ), GetTokenString( aTok ) );
326 }
327 
328 
329 void DSNLEXER::Expecting( const char* text ) const
330 {
331  wxString errText = wxString::Format(
332  _( "Expecting '%s'" ), wxString::FromUTF8( text ) );
334 }
335 
336 
337 void DSNLEXER::Unexpected( int aTok ) const
338 {
339  wxString errText = wxString::Format(
340  _( "Unexpected %s" ), GetTokenString( aTok ) );
342 }
343 
344 
345 void DSNLEXER::Duplicate( int aTok )
346 {
347  wxString errText = wxString::Format(
348  _("%s is a duplicate"), GetTokenString( aTok ).GetData() );
350 }
351 
352 
353 void DSNLEXER::Unexpected( const char* text ) const
354 {
355  wxString errText = wxString::Format(
356  _( "Unexpected '%s'" ), wxString::FromUTF8( text ) );
358 }
359 
360 
362 {
363  int tok = NextTok();
364  if( tok != DSN_LEFT )
365  Expecting( DSN_LEFT );
366 }
367 
368 
370 {
371  int tok = NextTok();
372  if( tok != DSN_RIGHT )
373  Expecting( DSN_RIGHT );
374 }
375 
376 
378 {
379  int tok = NextTok();
380  if( !IsSymbol( tok ) )
382  return tok;
383 }
384 
385 
387 {
388  int tok = NextTok();
389  if( !IsSymbol( tok ) && tok!=DSN_NUMBER )
390  Expecting( "a symbol or number" );
391  return tok;
392 }
393 
394 
395 int DSNLEXER::NeedNUMBER( const char* aExpectation )
396 {
397  int tok = NextTok();
398  if( tok != DSN_NUMBER )
399  {
400  wxString errText = wxString::Format(
401  _( "need a number for '%s'" ), wxString::FromUTF8( aExpectation ).GetData() );
403  }
404  return tok;
405 }
406 
407 
414 static bool isSpace( char cc )
415 {
416  // cc is signed, so it is often negative.
417  // Treat negative as large positive to exclude rapidly.
418  if( (unsigned char) cc <= ' ' )
419  {
420  switch( (unsigned char) cc )
421  {
422  case ' ':
423  case '\n':
424  case '\r':
425  case '\t':
426  case '\0': // PCAD s-expression files have this.
427  return true;
428  }
429  }
430  return false;
431 }
432 
433 
434 inline bool isDigit( char cc )
435 {
436  return '0' <= cc && cc <= '9';
437 }
438 
439 
441 inline bool isSep( char cc )
442 {
443  return isSpace( cc ) || cc=='(' || cc==')';
444 }
445 
446 
458 static bool isNumber( const char* cp, const char* limit )
459 {
460  // regex for a float: "^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?" i.e. any number,
461  // code traversal manually here:
462 
463  bool sawNumber = false;
464 
465  if( cp < limit && ( *cp=='-' || *cp=='+' ) )
466  ++cp;
467 
468  while( cp < limit && isDigit( *cp ) )
469  {
470  ++cp;
471  sawNumber = true;
472  }
473 
474  if( cp < limit && *cp == '.' )
475  {
476  ++cp;
477 
478  while( cp < limit && isDigit( *cp ) )
479  {
480  ++cp;
481  sawNumber = true;
482  }
483  }
484 
485  if( sawNumber )
486  {
487  if( cp < limit && ( *cp=='E' || *cp=='e' ) )
488  {
489  ++cp;
490 
491  sawNumber = false; // exponent mandates at least one digit thereafter.
492 
493  if( cp < limit && ( *cp=='-' || *cp=='+' ) )
494  ++cp;
495 
496  while( cp < limit && isDigit( *cp ) )
497  {
498  ++cp;
499  sawNumber = true;
500  }
501  }
502  }
503 
504  return sawNumber && cp==limit;
505 }
506 
507 
509 {
510  const char* cur = next;
511  const char* head = cur;
512 
513  prevTok = curTok;
514 
515  if( curTok == DSN_EOF )
516  goto exit;
517 
518  if( cur >= limit )
519  {
520 L_read:
521  // blank lines are returned as "\n" and will have a len of 1.
522  // EOF will have a len of 0 and so is detectable.
523  int len = readLine();
524  if( len == 0 )
525  {
526  cur = start; // after readLine(), since start can change, set cur offset to start
527  curTok = DSN_EOF;
528  goto exit;
529  }
530 
531  cur = start; // after readLine() since start can change.
532 
533  // skip leading whitespace
534  while( cur<limit && isSpace( *cur ) )
535  ++cur;
536 
537  // If the first non-blank character is #, this line is a comment.
538  // Comments cannot follow any other token on the same line.
539  if( cur<limit && *cur=='#' )
540  {
541  if( commentsAreTokens )
542  {
543  // Grab the entire current line [excluding end of line char(s)] as the
544  // current token. The '#' character may not be at offset zero.
545 
546  while( limit[-1] == '\n' || limit[-1] == '\r' )
547  --limit;
548 
549  curText.clear();
550  curText.append( start, limit );
551 
552  cur = start; // ensure a good curOffset below
554  head = limit; // do a readLine() on next call in here.
555  goto exit;
556  }
557  else
558  goto L_read;
559  }
560  }
561  else
562  {
563  // skip leading whitespace
564  while( cur<limit && isSpace( *cur ) )
565  ++cur;
566  }
567 
568  if( cur >= limit )
569  goto L_read;
570 
571  if( *cur == '(' )
572  {
573  curText = *cur;
574  curTok = DSN_LEFT;
575  head = cur+1;
576  goto exit;
577  }
578 
579  if( *cur == ')' )
580  {
581  curText = *cur;
582  curTok = DSN_RIGHT;
583  head = cur+1;
584  goto exit;
585  }
586 
587  // Non-specctraMode, understands and deciphers escaped \, \r, \n, and \".
588  // Strips off leading and trailing double quotes
589  if( !specctraMode )
590  {
591  // a quoted string, will return DSN_STRING
592  if( *cur == stringDelimiter )
593  {
594  // copy the token, character by character so we can remove doubled up quotes.
595  curText.clear();
596 
597  ++cur; // skip over the leading delimiter, which is always " in non-specctraMode
598 
599  head = cur;
600 
601  while( head<limit )
602  {
603  // ESCAPE SEQUENCES:
604  if( *head =='\\' )
605  {
606  char tbuf[8];
607  char c;
608  int i;
609 
610  if( ++head >= limit )
611  break; // throw exception at L_unterminated
612 
613  switch( *head++ )
614  {
615  case '"':
616  case '\\': c = head[-1]; break;
617  case 'a': c = '\x07'; break;
618  case 'b': c = '\x08'; break;
619  case 'f': c = '\x0c'; break;
620  case 'n': c = '\n'; break;
621  case 'r': c = '\r'; break;
622  case 't': c = '\x09'; break;
623  case 'v': c = '\x0b'; break;
624 
625  case 'x': // 1 or 2 byte hex escape sequence
626  for( i=0; i<2; ++i )
627  {
628  if( !isxdigit( head[i] ) )
629  break;
630  tbuf[i] = head[i];
631  }
632  tbuf[i] = '\0';
633  if( i > 0 )
634  c = (char) strtoul( tbuf, NULL, 16 );
635  else
636  c = 'x'; // a goofed hex escape sequence, interpret as 'x'
637  head += i;
638  break;
639 
640  default: // 1-3 byte octal escape sequence
641  --head;
642  for( i=0; i<3; ++i )
643  {
644  if( head[i] < '0' || head[i] > '7' )
645  break;
646  tbuf[i] = head[i];
647  }
648  tbuf[i] = '\0';
649  if( i > 0 )
650  c = (char) strtoul( tbuf, NULL, 8 );
651  else
652  c = '\\'; // a goofed octal escape sequence, interpret as '\'
653  head += i;
654  break;
655  }
656 
657  curText += c;
658  }
659 
660  else if( *head == '"' ) // end of the non-specctraMode DSN_STRING
661  {
662  curTok = DSN_STRING;
663  ++head; // omit this trailing double quote
664  goto exit;
665  }
666 
667  else
668  curText += *head++;
669 
670  } // while
671 
672  // L_unterminated:
673  wxString errtxt( _( "Un-terminated delimited string" ) );
675  cur - start + curText.length() );
676  }
677  }
678 
679  else // is specctraMode, tests in this block should not occur in KiCad mode.
680  {
681  /* get the dash out of a <pin_reference> which is embedded for example
682  like: U2-14 or "U2"-"14"
683  This is detectable by a non-space immediately preceeding the dash.
684  */
685  if( *cur == '-' && cur>start && !isSpace( cur[-1] ) )
686  {
687  curText = '-';
688  curTok = DSN_DASH;
689  head = cur+1;
690  goto exit;
691  }
692 
693  // switching the string_quote character
694  if( prevTok == DSN_STRING_QUOTE )
695  {
696  static const wxString errtxt( _("String delimiter must be a single character of ', \", or $"));
697 
698  char cc = *cur;
699  switch( cc )
700  {
701  case '\'':
702  case '$':
703  case '"':
704  break;
705  default:
707  }
708 
709  curText = cc;
710 
711  head = cur+1;
712 
713  if( head<limit && !isSep( *head ) )
714  {
716  }
717 
719  goto exit;
720  }
721 
722  // specctraMode DSN_STRING
723  if( *cur == stringDelimiter )
724  {
725  ++cur; // skip over the leading delimiter: ",', or $
726 
727  head = cur;
728 
729  while( head<limit && !isStringTerminator( *head ) )
730  ++head;
731 
732  if( head >= limit )
733  {
734  wxString errtxt( _( "Un-terminated delimited string" ) );
736  }
737 
738  curText.clear();
739  curText.append( cur, head );
740 
741  ++head; // skip over the trailing delimiter
742 
743  curTok = DSN_STRING;
744  goto exit;
745  }
746  } // specctraMode
747 
748  // non-quoted token, read it into curText.
749  curText.clear();
750 
751  head = cur;
752  while( head<limit && !isSep( *head ) )
753  curText += *head++;
754 
755  if( isNumber( curText.c_str(), curText.c_str() + curText.size() ) )
756  {
757  curTok = DSN_NUMBER;
758  goto exit;
759  }
760 
761  if( specctraMode && curText == "string_quote" )
762  {
764  goto exit;
765  }
766 
767  curTok = findToken( curText );
768 
769 exit: // single point of exit, no returns elsewhere please.
770 
771  curOffset = cur - start;
772 
773  next = head;
774 
775  return curTok;
776 }
777 
778 
780 {
781  wxArrayString* ret = 0;
782  bool cmt_setting = SetCommentsAreTokens( true );
783  int tok = NextTok();
784 
785  if( tok == DSN_COMMENT )
786  {
787  ret = new wxArrayString();
788 
789  do
790  {
791  ret->Add( FromUTF8() );
792  }
793  while( ( tok = NextTok() ) == DSN_COMMENT );
794  }
795 
796  SetCommentsAreTokens( cmt_setting );
797 
798  return ret;
799 }
int curOffset
offset within current line of the current token
Definition: dsnlexer.h:519
CITER next(CITER it)
Definition: ptree.cpp:126
int CurLineNumber() const
Return the current line number within my LINE_READER.
Definition: dsnlexer.h:416
int NeedNUMBER(const char *aExpectation)
Call NextTok() and then verifies that the token read is type DSN_NUMBER.
Definition: dsnlexer.cpp:395
bool commentsAreTokens
true if should return comments as tokens
Definition: dsnlexer.h:516
bool SetCommentsAreTokens(bool val)
Change the handling of comments.
Definition: dsnlexer.h:289
An abstract class from which implementation specific LINE_READERs may be derived to read single lines...
Definition: richio.h:80
void PushReader(LINE_READER *aLineReader)
Manage a stack of LINE_READERs in order to handle nested file inclusion.
Definition: dsnlexer.cpp:187
bool isSep(char cc)
return true if cc is an s-expression separator character
Definition: dsnlexer.cpp:441
bool isStringTerminator(char cc) const
Definition: dsnlexer.h:483
char * Line() const
Return a pointer to the last line that was read in.
Definition: richio.h:117
int NeedSYMBOLorNUMBER()
Call NextTok() and then verifies that the token read in satisfies bool IsSymbol() or the next token i...
Definition: dsnlexer.cpp:386
const KEYWORD * keywords
table sorted by CMake for bsearch()
Definition: dsnlexer.h:524
virtual ~DSNLEXER()
Definition: dsnlexer.cpp:138
const char * name
unique keyword.
Definition: dsnlexer.h:41
wxArrayString * ReadCommentLines()
Check the next sequence of tokens and reads them into a wxArrayString if they are comments.
Definition: dsnlexer.cpp:779
KEYWORD_MAP keyword_hash
fast, specialized "C string" hashtable
Definition: dsnlexer.h:526
static bool isNumber(const char *cp, const char *limit)
Function isNumber returns true if the next sequence of text is a number: either an integer,...
Definition: dsnlexer.cpp:458
void SetSpecctraMode(bool aMode)
Change the behavior of this lexer into or out of "specctra mode".
Definition: dsnlexer.cpp:148
bool space_in_quoted_tokens
blank spaces within quoted strings
Definition: dsnlexer.h:514
int findToken(const std::string &aToken) const
Take aToken string and looks up the string in the keywords table.
Definition: dsnlexer.cpp:228
wxString GetTokenString(int aTok) const
Return a quote wrapped wxString representation of a token value.
Definition: dsnlexer.cpp:302
const char * next
Definition: dsnlexer.h:496
int NeedSYMBOL()
Call NextTok() and then verifies that the token read in satisfies IsSymbol().
Definition: dsnlexer.cpp:377
LINE_READER * PopReader()
Delete the top most LINE_READER from an internal stack of LINE_READERs and in the case of FILE_LINE_R...
Definition: dsnlexer.cpp:199
void NeedLEFT()
Call NextTok() and then verifies that the token read in is a DSN_LEFT.
Definition: dsnlexer.cpp:361
A LINE_READER that reads from an open file.
Definition: richio.h:172
#define THROW_PARSE_ERROR(aProblem, aSource, aInputLine, aLineNumber, aByteIndex)
Definition: ki_exception.h:164
const char * limit
Definition: dsnlexer.h:497
#define NULL
bool isDigit(char cc)
Definition: dsnlexer.cpp:434
static bool IsSymbol(int aTok)
Test a token to see if it is a symbol.
Definition: dsnlexer.cpp:312
static bool isSpace(char cc)
Function isSpace tests for whitespace.
Definition: dsnlexer.cpp:414
const char * GetTokenText(int aTok) const
Return the C string representation of a DSN_T value.
Definition: dsnlexer.cpp:283
bool iOwnReaders
on readerStack, should I delete them?
Definition: dsnlexer.h:494
READER_STACK readerStack
all the LINE_READERs by pointer.
Definition: dsnlexer.h:502
static const KEYWORD empty_keywords[1]
Definition: dsnlexer.cpp:120
LINE_READER * reader
Definition: dsnlexer.h:505
bool specctraMode
if true, then: 1) stringDelimiter can be changed 2) Kicad quoting protocol is not in effect 3) space_...
Definition: dsnlexer.h:507
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200
int prevTok
curTok from previous NextTok() call.
Definition: dsnlexer.h:518
int readLine()
Definition: dsnlexer.h:454
int CurOffset() const
Return the byte offset within the current line, using a 1 based index.
Definition: dsnlexer.h:444
const char * start
Definition: dsnlexer.h:495
bool SyncLineReaderWith(DSNLEXER &aLexer)
Usable only for DSN lexers which share the same LINE_READER.
Definition: dsnlexer.cpp:164
void Duplicate(int aTok)
Throw an IO_ERROR exception with a message saying specifically that aTok is a duplicate of one alread...
Definition: dsnlexer.cpp:345
#define _(s)
Definition: 3d_actions.cpp:33
#define FMT_CLIPBOARD
Definition: dsnlexer.cpp:34
std::string curText
the text of the current token
Definition: dsnlexer.h:522
int NextTok()
Return the next token found in the input file or DSN_EOF when reaching the end of file.
Definition: dsnlexer.cpp:508
void Expecting(int aTok) const
Throw an IO_ERROR exception with an input file specific error message.
Definition: dsnlexer.cpp:321
const char * CurLine() const
Return the current line of text from which the CurText() would return its token.
Definition: dsnlexer.h:424
void NeedRIGHT()
Call NextTok() and then verifies that the token read in is a DSN_RIGHT.
Definition: dsnlexer.cpp:369
unsigned keywordCount
count of keywords table
Definition: dsnlexer.h:525
const wxString & CurSource() const
Return the current LINE_READER source.
Definition: dsnlexer.h:434
char dummy[1]
when there is no reader.
Definition: dsnlexer.h:498
int curTok
the current token obtained on last NextTok()
Definition: dsnlexer.h:521
Is a LINE_READER that reads from a multiline 8 bit wide std::string.
Definition: richio.h:237
void Unexpected(int aTok) const
Throw an IO_ERROR exception with an input file specific error message.
Definition: dsnlexer.cpp:337
Hold a keyword string and its unique integer token.
Definition: dsnlexer.h:39
void init()
Definition: dsnlexer.cpp:39
Implement a lexical analyzer for the SPECCTRA DSN file format.
Definition: dsnlexer.h:78
char stringDelimiter
Definition: dsnlexer.h:513
DSNLEXER(const KEYWORD *aKeywordTable, unsigned aKeywordCount, FILE *aFile, const wxString &aFileName)
Initialize a DSN lexer and prepares to read from aFile which is already open and has aFilename.
Definition: dsnlexer.cpp:71
wxString FromUTF8() const
Return the current token text as a wxString, assuming that the input byte stream is UTF8 encoded.
Definition: dsnlexer.h:408
int token
a zero based index into an array of KEYWORDs
Definition: dsnlexer.h:42
static const char * Syntax(int aTok)
Definition: dsnlexer.cpp:239