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