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