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  limit = dummy;
228  }
229  }
230  return ret;
231 }
232 
233 
234 #if 0
235 static int compare( const void* a1, const void* a2 )
236 {
237  const KEYWORD* k1 = (const KEYWORD*) a1;
238  const KEYWORD* k2 = (const KEYWORD*) a2;
239 
240  int ret = strcmp( k1->name, k2->name );
241  return ret;
242 }
243 
244 int DSNLEXER::findToken( const std::string& tok )
245 {
246  KEYWORD search;
247 
248  search.name = tok.c_str();
249 
250  const KEYWORD* findings = (const KEYWORD*) bsearch( &search,
252  sizeof(KEYWORD), compare );
253  if( findings )
254  return findings->token;
255  else
256  return DSN_SYMBOL; // not a keyword, some arbitrary symbol.
257 }
258 
259 #else
260 
261 inline int DSNLEXER::findToken( const std::string& tok )
262 {
263  KEYWORD_MAP::const_iterator it = keyword_hash.find( tok.c_str() );
264  if( it != keyword_hash.end() )
265  return it->second;
266 
267  return DSN_SYMBOL; // not a keyword, some arbitrary symbol.
268 }
269 #endif
270 
271 
272 const char* DSNLEXER::Syntax( int aTok )
273 {
274  const char* ret;
275 
276  switch( aTok )
277  {
278  case DSN_NONE:
279  ret = "NONE";
280  break;
281  case DSN_STRING_QUOTE:
282  ret = "string_quote"; // a special DSN syntax token, see specctra spec.
283  break;
284  case DSN_QUOTE_DEF:
285  ret = "quoted text delimiter";
286  break;
287  case DSN_DASH:
288  ret = "-";
289  break;
290  case DSN_SYMBOL:
291  ret = "symbol";
292  break;
293  case DSN_NUMBER:
294  ret = "number";
295  break;
296  case DSN_RIGHT:
297  ret = ")";
298  break;
299  case DSN_LEFT:
300  ret = "(";
301  break;
302  case DSN_STRING:
303  ret = "quoted string";
304  break;
305  case DSN_EOF:
306  ret = "end of input";
307  break;
308  default:
309  ret = "???";
310  }
311 
312  return ret;
313 }
314 
315 
316 const char* DSNLEXER::GetTokenText( int aTok )
317 {
318  const char* ret;
319 
320  if( aTok < 0 )
321  {
322  return Syntax( aTok );
323  }
324  else if( (unsigned) aTok < keywordCount )
325  {
326  ret = keywords[aTok].name;
327  }
328  else
329  ret = "token too big";
330 
331  return ret;
332 }
333 
334 
335 wxString DSNLEXER::GetTokenString( int aTok )
336 {
337  wxString ret;
338 
339  ret << wxT("'") << wxString::FromUTF8( GetTokenText(aTok) ) << wxT("'");
340 
341  return ret;
342 }
343 
344 
345 bool DSNLEXER::IsSymbol( int aTok )
346 {
347  // This is static and not inline to reduce code space.
348 
349  // if aTok is >= 0, then it is a coincidental match to a keyword.
350  return aTok==DSN_SYMBOL || aTok==DSN_STRING || aTok>=0;
351 }
352 
353 
354 void DSNLEXER::Expecting( int aTok ) throw( IO_ERROR )
355 {
356  wxString errText = wxString::Format(
357  _("Expecting '%s'"), GetChars( GetTokenString( aTok ) ) );
358  THROW_PARSE_ERROR( errText, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
359 }
360 
361 
362 void DSNLEXER::Expecting( const char* text ) throw( IO_ERROR )
363 {
364  wxString errText = wxString::Format(
365  _("Expecting '%s'"), GetChars( wxString::FromUTF8( text ) ) );
366  THROW_PARSE_ERROR( errText, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
367 }
368 
369 
370 void DSNLEXER::Unexpected( int aTok ) throw( IO_ERROR )
371 {
372  wxString errText = wxString::Format(
373  _("Unexpected '%s'"), GetChars( GetTokenString( aTok ) ) );
374  THROW_PARSE_ERROR( errText, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
375 }
376 
377 
378 void DSNLEXER::Duplicate( int aTok ) throw( IO_ERROR )
379 {
380  wxString errText = wxString::Format(
381  _("%s is a duplicate"), GetTokenString( aTok ).GetData() );
382  THROW_PARSE_ERROR( errText, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
383 }
384 
385 
386 void DSNLEXER::Unexpected( const char* text ) throw( IO_ERROR )
387 {
388  wxString errText = wxString::Format(
389  _("Unexpected '%s'"), GetChars( wxString::FromUTF8( text ) ) );
390  THROW_PARSE_ERROR( errText, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
391 }
392 
393 
395 {
396  int tok = NextTok();
397  if( tok != DSN_LEFT )
398  Expecting( DSN_LEFT );
399 }
400 
401 
403 {
404  int tok = NextTok();
405  if( tok != DSN_RIGHT )
406  Expecting( DSN_RIGHT );
407 }
408 
409 
411 {
412  int tok = NextTok();
413  if( !IsSymbol( tok ) )
415  return tok;
416 }
417 
418 
420 {
421  int tok = NextTok();
422  if( !IsSymbol( tok ) && tok!=DSN_NUMBER )
423  Expecting( "symbol|number" );
424  return tok;
425 }
426 
427 
428 int DSNLEXER::NeedNUMBER( const char* aExpectation ) throw( IO_ERROR )
429 {
430  int tok = NextTok();
431  if( tok != DSN_NUMBER )
432  {
433  wxString errText = wxString::Format(
434  _("need a NUMBER for '%s'"), wxString::FromUTF8( aExpectation ).GetData() );
435  THROW_PARSE_ERROR( errText, CurSource(), CurLine(), CurLineNumber(), CurOffset() );
436  }
437  return tok;
438 }
439 
440 
447 static bool isSpace( char cc )
448 {
449  // cc is signed, so it is often negative.
450  // Treat negative as large positive to exclude rapidly.
451  if( (unsigned char) cc <= ' ' )
452  {
453  switch( (unsigned char) cc )
454  {
455  case ' ':
456  case '\n':
457  case '\r':
458  case '\t':
459  case '\0': // PCAD s-expression files have this.
460  return true;
461  }
462  }
463  return false;
464 }
465 
466 
467 inline bool isDigit( char cc )
468 {
469  return '0' <= cc && cc <= '9';
470 }
471 
472 
474 inline bool isSep( char cc )
475 {
476  return isSpace( cc ) || cc=='(' || cc==')';
477 }
478 
479 
491 static bool isNumber( const char* cp, const char* limit )
492 {
493  // regex for a float: "^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?" i.e. any number,
494  // code traversal manually here:
495 
496  bool sawNumber = false;
497 
498  if( cp < limit && ( *cp=='-' || *cp=='+' ) )
499  ++cp;
500 
501  while( cp < limit && isDigit( *cp ) )
502  {
503  ++cp;
504  sawNumber = true;
505  }
506 
507  if( cp < limit && *cp == '.' )
508  {
509  ++cp;
510 
511  while( cp < limit && isDigit( *cp ) )
512  {
513  ++cp;
514  sawNumber = true;
515  }
516  }
517 
518  if( sawNumber )
519  {
520  if( cp < limit && ( *cp=='E' || *cp=='e' ) )
521  {
522  ++cp;
523 
524  sawNumber = false; // exponent mandates at least one digit thereafter.
525 
526  if( cp < limit && ( *cp=='-' || *cp=='+' ) )
527  ++cp;
528 
529  while( cp < limit && isDigit( *cp ) )
530  {
531  ++cp;
532  sawNumber = true;
533  }
534  }
535  }
536 
537  return sawNumber && cp==limit;
538 }
539 
540 
542 {
543  const char* cur = next;
544  const char* head = cur;
545 
546  prevTok = curTok;
547 
548  if( curTok == DSN_EOF )
549  goto exit;
550 
551  if( cur >= limit )
552  {
553 L_read:
554  // blank lines are returned as "\n" and will have a len of 1.
555  // EOF will have a len of 0 and so is detectable.
556  int len = readLine();
557  if( len == 0 )
558  {
559  cur = start; // after readLine(), since start can change, set cur offset to start
560  curTok = DSN_EOF;
561  goto exit;
562  }
563 
564  cur = start; // after readLine() since start can change.
565 
566  // skip leading whitespace
567  while( cur<limit && isSpace( *cur ) )
568  ++cur;
569 
570  // If the first non-blank character is #, this line is a comment.
571  // Comments cannot follow any other token on the same line.
572  if( cur<limit && *cur=='#' )
573  {
574  if( commentsAreTokens )
575  {
576  // Grab the entire current line [excluding end of line char(s)] as the
577  // current token. The '#' character may not be at offset zero.
578 
579  while( limit[-1] == '\n' || limit[-1] == '\r' )
580  --limit;
581 
582  curText.clear();
583  curText.append( start, limit );
584 
585  cur = start; // ensure a good curOffset below
587  head = limit; // do a readLine() on next call in here.
588  goto exit;
589  }
590  else
591  goto L_read;
592  }
593  }
594  else
595  {
596  // skip leading whitespace
597  while( cur<limit && isSpace( *cur ) )
598  ++cur;
599  }
600 
601  if( cur >= limit )
602  goto L_read;
603 
604  if( *cur == '(' )
605  {
606  curText = *cur;
607  curTok = DSN_LEFT;
608  head = cur+1;
609  goto exit;
610  }
611 
612  if( *cur == ')' )
613  {
614  curText = *cur;
615  curTok = DSN_RIGHT;
616  head = cur+1;
617  goto exit;
618  }
619 
620  // Non-specctraMode, understands and deciphers escaped \, \r, \n, and \".
621  // Strips off leading and trailing double quotes
622  if( !specctraMode )
623  {
624  // a quoted string, will return DSN_STRING
625  if( *cur == stringDelimiter )
626  {
627  // copy the token, character by character so we can remove doubled up quotes.
628  curText.clear();
629 
630  ++cur; // skip over the leading delimiter, which is always " in non-specctraMode
631 
632  head = cur;
633 
634  while( head<limit )
635  {
636  // ESCAPE SEQUENCES:
637  if( *head =='\\' )
638  {
639  char tbuf[8];
640  char c;
641  int i;
642 
643  if( ++head >= limit )
644  break; // throw exception at L_unterminated
645 
646  switch( *head++ )
647  {
648  case '"':
649  case '\\': c = head[-1]; break;
650  case 'a': c = '\x07'; break;
651  case 'b': c = '\x08'; break;
652  case 'f': c = '\x0c'; break;
653  case 'n': c = '\n'; break;
654  case 'r': c = '\r'; break;
655  case 't': c = '\x09'; break;
656  case 'v': c = '\x0b'; break;
657 
658  case 'x': // 1 or 2 byte hex escape sequence
659  for( i=0; i<2; ++i )
660  {
661  if( !isxdigit( head[i] ) )
662  break;
663  tbuf[i] = head[i];
664  }
665  tbuf[i] = '\0';
666  if( i > 0 )
667  c = (char) strtoul( tbuf, NULL, 16 );
668  else
669  c = 'x'; // a goofed hex escape sequence, interpret as 'x'
670  head += i;
671  break;
672 
673  default: // 1-3 byte octal escape sequence
674  --head;
675  for( i=0; i<3; ++i )
676  {
677  if( head[i] < '0' || head[i] > '7' )
678  break;
679  tbuf[i] = head[i];
680  }
681  tbuf[i] = '\0';
682  if( i > 0 )
683  c = (char) strtoul( tbuf, NULL, 8 );
684  else
685  c = '\\'; // a goofed octal escape sequence, interpret as '\'
686  head += i;
687  break;
688  }
689 
690  curText += c;
691  }
692 
693  else if( *head == '"' ) // end of the non-specctraMode DSN_STRING
694  {
695  curTok = DSN_STRING;
696  ++head; // omit this trailing double quote
697  goto exit;
698  }
699 
700  else
701  curText += *head++;
702 
703  } // while
704 
705  // L_unterminated:
706  wxString errtxt( _( "Un-terminated delimited string" ) );
708  }
709  }
710 
711  else // is specctraMode, tests in this block should not occur in KiCad mode.
712  {
713  /* get the dash out of a <pin_reference> which is embedded for example
714  like: U2-14 or "U2"-"14"
715  This is detectable by a non-space immediately preceeding the dash.
716  */
717  if( *cur == '-' && cur>start && !isSpace( cur[-1] ) )
718  {
719  curText = '-';
720  curTok = DSN_DASH;
721  head = cur+1;
722  goto exit;
723  }
724 
725  // switching the string_quote character
726  if( prevTok == DSN_STRING_QUOTE )
727  {
728  static const wxString errtxt( _("String delimiter must be a single character of ', \", or $"));
729 
730  char cc = *cur;
731  switch( cc )
732  {
733  case '\'':
734  case '$':
735  case '"':
736  break;
737  default:
739  }
740 
741  curText = cc;
742 
743  head = cur+1;
744 
745  if( head<limit && !isSep( *head ) )
746  {
748  }
749 
751  goto exit;
752  }
753 
754  // specctraMode DSN_STRING
755  if( *cur == stringDelimiter )
756  {
757  ++cur; // skip over the leading delimiter: ",', or $
758 
759  head = cur;
760 
761  while( head<limit && !isStringTerminator( *head ) )
762  ++head;
763 
764  if( head >= limit )
765  {
766  wxString errtxt( _( "Un-terminated delimited string" ) );
768  }
769 
770  curText.clear();
771  curText.append( cur, head );
772 
773  ++head; // skip over the trailing delimiter
774 
775  curTok = DSN_STRING;
776  goto exit;
777  }
778  } // specctraMode
779 
780  // non-quoted token, read it into curText.
781  curText.clear();
782 
783  head = cur;
784  while( head<limit && !isSep( *head ) )
785  curText += *head++;
786 
787  if( isNumber( curText.c_str(), curText.c_str() + curText.size() ) )
788  {
789  curTok = DSN_NUMBER;
790  goto exit;
791  }
792 
793  if( specctraMode && curText == "string_quote" )
794  {
796  goto exit;
797  }
798 
799  curTok = findToken( curText );
800 
801 exit: // single point of exit, no returns elsewhere please.
802 
803  curOffset = cur - start;
804 
805  next = head;
806 
807  // printf("tok:\"%s\"\n", curText.c_str() );
808  return curTok;
809 }
810 
811 
812 wxArrayString* DSNLEXER::ReadCommentLines() throw( IO_ERROR )
813 {
814  wxArrayString* ret = 0;
815  bool cmt_setting = SetCommentsAreTokens( true );
816  int tok = NextTok();
817 
818  if( tok == DSN_COMMENT )
819  {
820  ret = new wxArrayString();
821 
822  do
823  {
824  ret->Add( FromUTF8() );
825  }
826  while( ( tok = NextTok() ) == DSN_COMMENT );
827  }
828 
829  SetCommentsAreTokens( cmt_setting );
830 
831  return ret;
832 }
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:428
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:474
int NeedSYMBOLorNUMBER()
Function NeedSYMBOLorNUMBER calls NextTok() and then verifies that the token read in satisfies bool I...
Definition: dsnlexer.cpp:419
const char * GetTokenText(int aTok)
Function GetTokenText returns the C string representation of a DSN_T value.
Definition: dsnlexer.cpp:316
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:261
void Unexpected(int aTok)
Function Unexpected throws an IO_ERROR exception with an input file specific error message...
Definition: dsnlexer.cpp:370
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:812
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:491
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:410
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:394
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:467
static bool IsSymbol(int aTok)
Function IsSymbol tests a token to see if it is a symbol.
Definition: dsnlexer.cpp:345
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:447
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:354
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:378
#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:541
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:335
void NeedRIGHT()
Function NeedRIGHT calls NextTok() and then verifies that the token read in is a DSN_RIGHT.
Definition: dsnlexer.cpp:402
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
Struct IO_ERROR is a class used to hold an error message and may be used when throwing exceptions con...
Definition: ki_exception.h:47
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:272