KiCad PCB EDA Suite
Loading...
Searching...
No Matches
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 <[email protected]>
5 * Copyright (C) 2007-2024 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 default:
280 ret = "???";
281 }
282
283 return ret;
284}
285
286
287const char* DSNLEXER::GetTokenText( int aTok ) const
288{
289 const char* ret;
290
291 if( aTok < 0 )
292 {
293 return Syntax( aTok );
294 }
295 else if( (unsigned) aTok < keywordCount )
296 {
297 ret = keywords[aTok].name;
298 }
299 else
300 ret = "token too big";
301
302 return ret;
303}
304
305
306wxString DSNLEXER::GetTokenString( int aTok ) const
307{
308 wxString ret;
309
310 ret << wxT("'") << wxString::FromUTF8( GetTokenText(aTok) ) << wxT("'");
311
312 return ret;
313}
314
315
316bool DSNLEXER::IsSymbol( int aTok )
317{
318 // This is static and not inline to reduce code space.
319
320 // if aTok is >= 0, then it is a coincidental match to a keyword.
321 return aTok == DSN_SYMBOL || aTok == DSN_STRING || aTok >= 0;
322}
323
324
325void DSNLEXER::Expecting( int aTok ) const
326{
327 wxString errText = wxString::Format(
328 _( "Expecting %s" ), GetTokenString( aTok ) );
330}
331
332
333void DSNLEXER::Expecting( const char* text ) const
334{
335 wxString errText = wxString::Format(
336 _( "Expecting '%s'" ), wxString::FromUTF8( text ) );
338}
339
340
341void DSNLEXER::Unexpected( int aTok ) const
342{
343 wxString errText = wxString::Format(
344 _( "Unexpected %s" ), GetTokenString( aTok ) );
346}
347
348
349void DSNLEXER::Duplicate( int aTok )
350{
351 wxString errText = wxString::Format(
352 _("%s is a duplicate"), GetTokenString( aTok ).GetData() );
354}
355
356
357void DSNLEXER::Unexpected( const char* text ) const
358{
359 wxString errText = wxString::Format(
360 _( "Unexpected '%s'" ), wxString::FromUTF8( text ) );
362}
363
364
366{
367 int tok = NextTok();
368 if( tok != DSN_LEFT )
370}
371
372
374{
375 int tok = NextTok();
376
377 if( tok != DSN_RIGHT )
379}
380
381
383{
384 int tok = NextTok();
385
386 if( !IsSymbol( tok ) )
388
389 return tok;
390}
391
392
394{
395 int tok = NextTok();
396
397 if( !IsSymbol( tok ) && tok!=DSN_NUMBER )
398 Expecting( "a symbol or number" );
399
400 return tok;
401}
402
403
404int DSNLEXER::NeedNUMBER( const char* aExpectation )
405{
406 int tok = NextTok();
407
408 if( tok != DSN_NUMBER )
409 {
410 wxString errText = wxString::Format( _( "need a number for '%s'" ),
411 wxString::FromUTF8( aExpectation ).GetData() );
413 }
414
415 return tok;
416}
417
418
425static bool isSpace( char cc )
426{
427 // cc is signed, so it is often negative.
428 // Treat negative as large positive to exclude rapidly.
429 if( (unsigned char) cc <= ' ' )
430 {
431 switch( (unsigned char) cc )
432 {
433 case ' ':
434 case '\n':
435 case '\r':
436 case '\t':
437 case '\0': // PCAD s-expression files have this.
438 return true;
439 }
440 }
441
442 return false;
443}
444
445
446inline bool isDigit( char cc )
447{
448 return '0' <= cc && cc <= '9';
449}
450
451
453inline bool isSep( char cc )
454{
455 return isSpace( cc ) || cc=='(' || cc==')';
456}
457
458
468static bool isNumber( const char* cp, const char* limit )
469{
470 // regex for a float: "^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?" i.e. any number,
471 // code traversal manually here:
472
473 bool sawNumber = false;
474
475 if( cp < limit && ( *cp=='-' || *cp=='+' ) )
476 ++cp;
477
478 while( cp < limit && isDigit( *cp ) )
479 {
480 ++cp;
481 sawNumber = true;
482 }
483
484 if( cp < limit && *cp == '.' )
485 {
486 ++cp;
487
488 while( cp < limit && isDigit( *cp ) )
489 {
490 ++cp;
491 sawNumber = true;
492 }
493 }
494
495 if( sawNumber )
496 {
497 if( cp < limit && ( *cp=='E' || *cp=='e' ) )
498 {
499 ++cp;
500
501 sawNumber = false; // exponent mandates at least one digit thereafter.
502
503 if( cp < limit && ( *cp=='-' || *cp=='+' ) )
504 ++cp;
505
506 while( cp < limit && isDigit( *cp ) )
507 {
508 ++cp;
509 sawNumber = true;
510 }
511 }
512 }
513
514 return sawNumber && cp==limit;
515}
516
517
519{
520 const char* cur = next;
521 const char* head = cur;
522
523 prevTok = curTok;
524
525 if( curTok == DSN_EOF )
526 goto exit;
527
528 if( cur >= limit )
529 {
530L_read:
531 // blank lines are returned as "\n" and will have a len of 1.
532 // EOF will have a len of 0 and so is detectable.
533 int len = readLine();
534
535 if( len == 0 )
536 {
537 cur = start; // after readLine(), since start can change, set cur offset to start
538 curTok = DSN_EOF;
539 goto exit;
540 }
541
542 cur = start; // after readLine() since start can change.
543
544 // skip leading whitespace
545 while( cur < limit && isSpace( *cur ) )
546 ++cur;
547
548 // If the first non-blank character is #, this line is a comment.
549 // Comments cannot follow any other token on the same line.
550 if( cur<limit && *cur=='#' )
551 {
553 {
554 // Grab the entire current line [excluding end of line char(s)] as the
555 // current token. The '#' character may not be at offset zero.
556
557 while( limit[-1] == '\n' || limit[-1] == '\r' )
558 --limit;
559
560 curText.clear();
561 curText.append( start, limit );
562
563 cur = start; // ensure a good curOffset below
565 head = limit; // do a readLine() on next call in here.
566 goto exit;
567 }
568 else
569 {
570 goto L_read;
571 }
572 }
573 }
574 else
575 {
576 // skip leading whitespace
577 while( cur < limit && isSpace( *cur ) )
578 ++cur;
579 }
580
581 if( cur >= limit )
582 goto L_read;
583
584 if( *cur == '(' )
585 {
586 curText = *cur;
588 head = cur+1;
589 goto exit;
590 }
591
592 if( *cur == ')' )
593 {
594 curText = *cur;
596 head = cur+1;
597 goto exit;
598 }
599
600 // Non-specctraMode, understands and deciphers escaped \, \r, \n, and \".
601 // Strips off leading and trailing double quotes
602 if( !specctraMode )
603 {
604 // a quoted string, will return DSN_STRING
605 if( *cur == stringDelimiter )
606 {
607 // copy the token, character by character so we can remove doubled up quotes.
608 curText.clear();
609
610 ++cur; // skip over the leading delimiter, which is always " in non-specctraMode
611
612 head = cur;
613
614 while( head<limit )
615 {
616 // ESCAPE SEQUENCES:
617 if( *head =='\\' )
618 {
619 char tbuf[8];
620 char c;
621 int i;
622
623 if( ++head >= limit )
624 break; // throw exception at L_unterminated
625
626 switch( *head++ )
627 {
628 case '"':
629 case '\\': c = head[-1]; break;
630 case 'a': c = '\x07'; break;
631 case 'b': c = '\x08'; break;
632 case 'f': c = '\x0c'; break;
633 case 'n': c = '\n'; break;
634 case 'r': c = '\r'; break;
635 case 't': c = '\x09'; break;
636 case 'v': c = '\x0b'; break;
637
638 case 'x': // 1 or 2 byte hex escape sequence
639 for( i = 0; i < 2; ++i )
640 {
641 if( !isxdigit( head[i] ) )
642 break;
643
644 tbuf[i] = head[i];
645 }
646
647 tbuf[i] = '\0';
648
649 if( i > 0 )
650 c = (char) strtoul( tbuf, nullptr, 16 );
651 else
652 c = 'x'; // a goofed hex escape sequence, interpret as 'x'
653
654 head += i;
655 break;
656
657 default: // 1-3 byte octal escape sequence
658 --head;
659
660 for( i=0; i<3; ++i )
661 {
662 if( head[i] < '0' || head[i] > '7' )
663 break;
664
665 tbuf[i] = head[i];
666 }
667
668 tbuf[i] = '\0';
669
670 if( i > 0 )
671 c = (char) strtoul( tbuf, nullptr, 8 );
672 else
673 c = '\\'; // a goofed octal escape sequence, interpret as '\'
674
675 head += i;
676 break;
677 }
678
679 curText += c;
680 }
681
682 else if( *head == '"' ) // end of the non-specctraMode DSN_STRING
683 {
685 ++head; // omit this trailing double quote
686 goto exit;
687 }
688
689 else
690 curText += *head++;
691
692 } // while
693
694 // L_unterminated:
695 wxString errtxt( _( "Un-terminated delimited string" ) );
697 cur - start + curText.length() );
698 }
699 }
700 else // is specctraMode, tests in this block should not occur in KiCad mode.
701 {
702 /* get the dash out of a <pin_reference> which is embedded for example
703 like: U2-14 or "U2"-"14"
704 This is detectable by a non-space immediately preceding the dash.
705 */
706 if( *cur == '-' && cur>start && !isSpace( cur[-1] ) )
707 {
708 curText = '-';
710 head = cur+1;
711 goto exit;
712 }
713
714 // switching the string_quote character
716 {
717 static const wxString errtxt( _("String delimiter must be a single character of "
718 "', \", or $") );
719
720 char cc = *cur;
721 switch( cc )
722 {
723 case '\'':
724 case '$':
725 case '"':
726 break;
727 default:
729 }
730
731 curText = cc;
732
733 head = cur+1;
734
735 if( head<limit && !isSep( *head ) )
736 {
738 }
739
741 goto exit;
742 }
743
744 // specctraMode DSN_STRING
745 if( *cur == stringDelimiter )
746 {
747 ++cur; // skip over the leading delimiter: ",', or $
748
749 head = cur;
750
751 while( head<limit && !isStringTerminator( *head ) )
752 ++head;
753
754 if( head >= limit )
755 {
756 wxString errtxt( _( "Un-terminated delimited string" ) );
758 }
759
760 curText.clear();
761 curText.append( cur, head );
762
763 ++head; // skip over the trailing delimiter
764
766 goto exit;
767 }
768 } // specctraMode
769
770 // non-quoted token, read it into curText.
771 curText.clear();
772
773 head = cur;
774 while( head<limit && !isSep( *head ) )
775 curText += *head++;
776
777 if( isNumber( curText.c_str(), curText.c_str() + curText.size() ) )
778 {
780 goto exit;
781 }
782
783 if( specctraMode && curText == "string_quote" )
784 {
786 goto exit;
787 }
788
790
791exit: // single point of exit, no returns elsewhere please.
792
793 curOffset = cur - start;
794
795 next = head;
796
797 return curTok;
798}
799
800
802{
803 wxArrayString* ret = nullptr;
804 bool cmt_setting = SetCommentsAreTokens( true );
805 int tok = NextTok();
806
807 if( tok == DSN_COMMENT )
808 {
809 ret = new wxArrayString();
810
811 do
812 {
813 ret->Add( FromUTF8() );
814 }
815 while( ( tok = NextTok() ) == DSN_COMMENT );
816 }
817
818 SetCommentsAreTokens( cmt_setting );
819
820 return ret;
821}
822
823
825{
826#if ( defined( __GNUC__ ) && __GNUC__ < 11 ) || ( defined( __clang__ ) && __clang_major__ < 13 )
827 // GCC older than 11 "supports" C++17 without supporting the C++17 std::from_chars for doubles
828 // clang is similar
829
830 char* tmp;
831
832 errno = 0;
833
834 double fval = strtod( CurText(), &tmp );
835
836 if( errno )
837 {
838 wxString error;
839 error.Printf( _( "Invalid floating point number in\nfile: '%s'\nline: %d\noffset: %d" ),
841
842 THROW_IO_ERROR( error );
843 }
844
845 if( CurText() == tmp )
846 {
847 wxString error;
848 error.Printf( _( "Missing floating point number in\nfile: '%s'\nline: %d\noffset: %d" ),
850
851 THROW_IO_ERROR( error );
852 }
853
854 return fval;
855#else
856 // Use std::from_chars which is designed to be locale independent and performance oriented for data interchange
857
858 const std::string& str = CurStr();
859
860 // Offset any leading whitespace, this is one thing from_chars does not handle
861 size_t woff = 0;
862 while( std::isspace( str[woff] ) && woff < str.length() )
863 {
864 woff++;
865 }
866
867 double dval{};
868 std::from_chars_result res =
869 std::from_chars( str.data() + woff, str.data() + str.size(), dval );
870
871 if( res.ec != std::errc() )
872 {
873 THROW_PARSE_ERROR( _( "Invalid floating point number" ), CurSource(), CurLine(),
875 }
876
877 return dval;
878#endif
879}
Implement a lexical analyzer for the SPECCTRA DSN file format.
Definition: dsnlexer.h:80
int NeedSYMBOLorNUMBER()
Call NextTok() and then verifies that the token read in satisfies bool IsSymbol() or the next token i...
Definition: dsnlexer.cpp:393
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:365
const char * next
Definition: dsnlexer.h:525
std::string curText
the text of the current token
Definition: dsnlexer.h:551
unsigned keywordCount
count of keywords table
Definition: dsnlexer.h:554
int NeedNUMBER(const char *aExpectation)
Call NextTok() and then verifies that the token read is type DSN_NUMBER.
Definition: dsnlexer.cpp:404
bool commentsAreTokens
true if should return comments as tokens
Definition: dsnlexer.h:545
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:399
static bool IsSymbol(int aTok)
Test a token to see if it is a symbol.
Definition: dsnlexer.cpp:316
void init()
Definition: dsnlexer.cpp:39
const char * start
Definition: dsnlexer.h:524
const char * GetTokenText(int aTok) const
Return the C string representation of a DSN_T value.
Definition: dsnlexer.cpp:287
wxArrayString * ReadCommentLines()
Check the next sequence of tokens and reads them into a wxArrayString if they are comments.
Definition: dsnlexer.cpp:801
int curTok
the current token obtained on last NextTok()
Definition: dsnlexer.h:550
bool space_in_quoted_tokens
blank spaces within quoted strings
Definition: dsnlexer.h:543
bool specctraMode
if true, then: 1) stringDelimiter can be changed 2) Kicad quoting protocol is not in effect 3) space_...
Definition: dsnlexer.h:536
int NextTok()
Return the next token found in the input file or DSN_EOF when reaching the end of file.
Definition: dsnlexer.cpp:518
int NeedSYMBOL()
Call NextTok() and then verifies that the token read in satisfies IsSymbol().
Definition: dsnlexer.cpp:382
int curOffset
offset within current line of the current token
Definition: dsnlexer.h:548
char stringDelimiter
Definition: dsnlexer.h:542
LINE_READER * reader
Definition: dsnlexer.h:534
const char * limit
Definition: dsnlexer.h:526
bool isStringTerminator(char cc) const
Definition: dsnlexer.h:491
const KEYWORD * keywords
table sorted by CMake for bsearch()
Definition: dsnlexer.h:553
void NeedRIGHT()
Call NextTok() and then verifies that the token read in is a DSN_RIGHT.
Definition: dsnlexer.cpp:373
int readLine()
Definition: dsnlexer.h:462
READER_STACK readerStack
all the LINE_READERs by pointer.
Definition: dsnlexer.h:531
char dummy[1]
when there is no reader.
Definition: dsnlexer.h:527
double parseDouble()
Parse the current token as an ASCII numeric string with possible leading whitespace into a double pre...
Definition: dsnlexer.cpp:824
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:416
void Expecting(int aTok) const
Throw an IO_ERROR exception with an input file specific error message.
Definition: dsnlexer.cpp:325
const wxString & CurSource() const
Return the current LINE_READER source.
Definition: dsnlexer.h:442
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:407
const char * CurLine() const
Return the current line of text from which the CurText() would return its token.
Definition: dsnlexer.h:432
bool SetCommentsAreTokens(bool val)
Change the handling of comments.
Definition: dsnlexer.h:297
wxString GetTokenString(int aTok) const
Return a quote wrapped wxString representation of a token value.
Definition: dsnlexer.cpp:306
int CurOffset() const
Return the byte offset within the current line, using a 1 based index.
Definition: dsnlexer.h:452
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:547
const KEYWORD_MAP * keywordsLookup
fast, specialized "C string" hashtable
Definition: dsnlexer.h:555
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:341
int CurLineNumber() const
Return the current line number within my LINE_READER.
Definition: dsnlexer.h:424
bool iOwnReaders
on readerStack, should I delete them?
Definition: dsnlexer.h:523
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:468
bool isDigit(char cc)
Definition: dsnlexer.cpp:446
static bool isSpace(char cc)
Test for whitespace.
Definition: dsnlexer.cpp:425
static const KEYWORD empty_keywords[1]
Definition: dsnlexer.cpp:109
#define FMT_CLIPBOARD
Definition: dsnlexer.cpp:34
bool isSep(char cc)
Definition: dsnlexer.cpp:453
@ DSN_QUOTE_DEF
Definition: dsnlexer.h:63
@ DSN_STRING_QUOTE
Definition: dsnlexer.h:62
@ DSN_LEFT
Definition: dsnlexer.h:68
@ DSN_RIGHT
Definition: dsnlexer.h:67
@ DSN_NUMBER
Definition: dsnlexer.h:66
@ DSN_NONE
Definition: dsnlexer.h:60
@ DSN_DASH
Definition: dsnlexer.h:64
@ DSN_SYMBOL
Definition: dsnlexer.h:65
@ DSN_COMMENT
Definition: dsnlexer.h:61
@ DSN_STRING
Definition: dsnlexer.h:69
@ DSN_EOF
Definition: dsnlexer.h:70
#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:126
Hold a keyword string and its unique integer token.
Definition: dsnlexer.h:41
const char * name
unique keyword.
Definition: dsnlexer.h:42
VECTOR3I res