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