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