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