1 // //**************************************************************************
2 //**
3 //**	##   ##    ##    ##   ##   ####     ####   ###     ###
4 //**	##   ##  ##  ##  ##   ##  ##  ##   ##  ##  ####   ####
5 //**	 ## ##  ##    ##  ## ##  ##    ## ##    ## ## ## ## ##
6 //**	 ## ##  ########  ## ##  ##    ## ##    ## ##  ###  ##
7 //**	  ###   ##    ##   ###    ##  ##   ##  ##  ##       ##
8 //**	   #    ##    ##    #      ####     ####   ##       ##
9 //**
10 //**	$Id: vc_lexer.cpp 4297 2010-06-03 22:49:00Z firebrand_kh $
11 //**
12 //**	Copyright (C) 1999-2006 Jānis Legzdiņš
13 //**
14 //**	This program is free software; you can redistribute it and/or
15 //**  modify it under the terms of the GNU General Public License
16 //**  as published by the Free Software Foundation; either version 2
17 //**  of the License, or (at your option) any later version.
18 //**
19 //**	This program is distributed in the hope that it will be useful,
20 //**  but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 //**  GNU General Public License for more details.
23 //**
24 //**************************************************************************
25 
26 // HEADER FILES ------------------------------------------------------------
27 
28 #include "vc_local.h"
29 
30 // MACROS ------------------------------------------------------------------
31 
32 // TYPES -------------------------------------------------------------------
33 
34 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
35 
36 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
37 
38 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
39 
40 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
41 
42 // PUBLIC DATA DEFINITIONS -------------------------------------------------
43 
44 const char*			VLexer::TokenNames[] =
45 {
46 	"",
47 	"END OF FILE",
48 	"IDENTIFIER",
49 	"NAME LITERAL",
50 	"STRING LITERAL",
51 	"INTEGER LITERAL",
52 	"FLOAT LITERAL",
53 	//	Keywords
54 	"abstract",
55 	"array",
56 	"bool",
57 	"break",
58 	"byte",
59 	"case",
60 	"class",
61 	"const",
62 	"continue",
63 	"decorate",
64 	"default",
65 	"defaultproperties",
66 	"delegate",
67 	"do",
68 	"else",
69 	"enum",
70 	"false",
71 	"final",
72 	"float",
73 	"for",
74 	"foreach",
75 	"game",
76 	"get",
77 	"if",
78 	"import",
79 	"int",
80 	"iterator",
81 	"name",
82 	"native",
83 	"none",
84 	"NULL",
85 	"optional",
86 	"out",
87 	"private",
88 	"readonly",
89 	"reliable",
90 	"replication",
91 	"return",
92 	"self",
93 	"set",
94 	"spawner",
95 	"state",
96 	"states",
97 	"static",
98 	"string",
99 	"struct",
100 	"switch",
101 	"transient",
102 	"true",
103 	"unreliable",
104 	"vector",
105 	"void",
106 	"while",
107 	"__mobjinfo__",
108 	"__scriptid__",
109 	//	Punctuation
110 	"...",
111 	"<<=",
112 	">>=",
113 	"+=",
114 	"-=",
115 	"*=",
116 	"/=",
117 	"%=",
118 	"&=",
119 	"|=",
120 	"^=",
121 	"==",
122 	"!=",
123 	"<=",
124 	">=",
125 	"&&",
126 	"||",
127 	"<<",
128 	">>",
129 	"++",
130 	"--",
131 	"->",
132 	"::",
133 	"<",
134 	">",
135 	"?",
136 	"&",
137 	"|",
138 	"^",
139 	"~",
140 	"!",
141 	"+",
142 	"-",
143 	"*",
144 	"/",
145 	"%",
146 	"(",
147 	")",
148 	".",
149 	",",
150 	";",
151 	":",
152 	"=",
153 	"[",
154 	"]",
155 	"{",
156 	"}",
157 };
158 
159 // PRIVATE DATA DEFINITIONS ------------------------------------------------
160 
161 // CODE --------------------------------------------------------------------
162 
163 //==========================================================================
164 //
165 //	VLexer::VLexer
166 //
167 //==========================================================================
168 
VLexer()169 VLexer::VLexer()
170 : SourceOpen(false)
171 , Src(NULL)
172 , Token(TK_NoToken)
173 , Number(0)
174 , Float(0)
175 , Name(NAME_None)
176 {
177 	int i;
178 
179 	memset(TokenStringBuffer, 0, sizeof(TokenStringBuffer));
180 
181 	for (i = 0; i < 256; i++)
182 	{
183 		ASCIIToChrCode[i] = CHR_Special;
184 		ASCIIToHexDigit[i] = NON_HEX_DIGIT;
185 	}
186 	for (i = '0'; i <= '9'; i++)
187 	{
188 		ASCIIToChrCode[i] = CHR_Number;
189 		ASCIIToHexDigit[i] = i-'0';
190 	}
191 	for (i = 'A'; i <= 'F'; i++)
192 	{
193 		ASCIIToHexDigit[i] = 10+(i-'A');
194 	}
195 	for (i = 'a'; i <= 'f'; i++)
196 	{
197 		ASCIIToHexDigit[i] = 10+(i-'a');
198 	}
199 	for (i = 'A'; i <= 'Z'; i++)
200 	{
201 		ASCIIToChrCode[i] = CHR_Letter;
202 	}
203 	for (i = 'a'; i <= 'z'; i++)
204 	{
205 		ASCIIToChrCode[i] = CHR_Letter;
206 	}
207 	ASCIIToChrCode[(int)'\"'] = CHR_Quote;
208 	ASCIIToChrCode[(int)'\''] = CHR_SingleQuote;
209 	ASCIIToChrCode[(int)'_'] = CHR_Letter;
210 	ASCIIToChrCode[0] = CHR_EOF;
211 	ASCIIToChrCode[EOF_CHARACTER] = CHR_EOF;
212 	String = TokenStringBuffer;
213 }
214 
215 //==========================================================================
216 //
217 //	VLexer::OpenSource
218 //
219 //==========================================================================
220 
OpenSource(const VStr & FileName)221 void VLexer::OpenSource(const VStr& FileName)
222 {
223 	//	Read file and prepare for compilation.
224 	PushSource(Location, FileName);
225 
226 	SourceOpen = true;
227 
228 	Token = TK_NoToken;
229 }
230 
231 //==========================================================================
232 //
233 //	VLexer::~VLexer
234 //
235 //==========================================================================
236 
~VLexer()237 VLexer::~VLexer()
238 {
239 	while (Src)
240 	{
241 		PopSource();
242 	}
243 	SourceOpen = false;
244 }
245 
246 //==========================================================================
247 //
248 //	VLexer::PushSource
249 //
250 //==========================================================================
251 
PushSource(TLocation & Loc,const VStr & FileName)252 void VLexer::PushSource(TLocation& Loc, const VStr& FileName)
253 {
254 #ifdef IN_VCC
255 	VStream* Strm = OpenFile(FileName);
256 #else
257 	VStream* Strm = FL_OpenFileRead(FileName);
258 #endif
259 	if (!Strm)
260 	{
261 		FatalError("Couldn't open %s", *FileName);
262 		return;
263 	}
264 
265 	VSourceFile* NewSrc = new VSourceFile();
266 	NewSrc->Next = Src;
267 	Src = NewSrc;
268 
269 	//	Copy file name
270 	NewSrc->FileName = FileName;
271 
272 	//	Extract path to the file.
273 	const char* PathEnd = *FileName + FileName.Length() - 1;
274 	while (PathEnd >= *FileName && *PathEnd != '/' && *PathEnd != '\\')
275 	{
276 		PathEnd--;
277 	}
278 	if (PathEnd >= *FileName)
279 	{
280 		NewSrc->Path = VStr(FileName, 0, (PathEnd - *FileName) + 1);
281 	}
282 
283 	//	Read the file
284 	int FileSize = Strm->TotalSize();
285 	NewSrc->FileStart = new char[FileSize + 1];
286 	Strm->Serialise(NewSrc->FileStart, FileSize);
287 	Strm->Close();
288 	delete Strm;
289 	Strm = NULL;
290 	NewSrc->FileStart[FileSize] = 0;
291 	NewSrc->FileEnd = NewSrc->FileStart + FileSize;
292 	NewSrc->FilePtr = NewSrc->FileStart;
293 
294 	//	Skip garbage some editors add in the begining of UTF-8 files.
295 	if ((vuint8)NewSrc->FilePtr[0] == 0xef &&
296 		(vuint8)NewSrc->FilePtr[1] == 0xbb &&
297 		(vuint8)NewSrc->FilePtr[2] == 0xbf)
298 	{
299 		NewSrc->FilePtr += 3;
300 	}
301 
302 	//	Save current character and location to be able to restore them.
303 	NewSrc->Chr = Chr;
304 	NewSrc->Loc = Location;
305 
306 	NewSrc->SourceIdx = TLocation::AddSourceFile(FileName);
307 	NewSrc->Line = 1;
308 	NewSrc->IncLineNumber = false;
309 	NewSrc->NewLine = true;
310 	NewSrc->Skipping = false;
311 	Location = TLocation(NewSrc->SourceIdx, NewSrc->Line);
312 	NextChr();
313 }
314 
315 //==========================================================================
316 //
317 //	VLexer::PopSource
318 //
319 //==========================================================================
320 
PopSource()321 void VLexer::PopSource()
322 {
323 	if (!Src)
324 	{
325 		return;
326 	}
327 
328 	if (Src->IfStates.Num())
329 	{
330 		ParseError(Location, "#ifdef without a corresponding #endif");
331 	}
332 
333 	VSourceFile* Tmp = Src;
334 	delete[] Tmp->FileStart;
335 	Tmp->FileStart = NULL;
336 	Src = Tmp->Next;
337 	Chr = Tmp->Chr;
338 	Location = Tmp->Loc;
339 	delete Tmp;
340 	Tmp = NULL;
341 }
342 
343 //==========================================================================
344 //
345 //	VLexer::NextToken
346 //
347 //==========================================================================
348 
NextToken()349 void VLexer::NextToken()
350 {
351 	NewLine = Src->NewLine;
352 	do
353 	{
354 		TokenStringBuffer[0] = 0;
355 		SkipWhitespaceAndComments();
356 		if (Src->NewLine)
357 		{
358 			NewLine = true;
359 			//	A new line has been started, check preprocessor directive.
360 			Src->NewLine = false;
361 			if (Chr == '#')
362 			{
363 				ProcessPreprocessor();
364 				continue;
365 			}
366 		}
367 		switch (ASCIIToChrCode[(vuint8)Chr])
368 		{
369 		case CHR_EOF:
370 			PopSource();
371 			if (Src)
372 			{
373 				Token = TK_NoToken;
374 			}
375 			else
376 			{
377 				Token = TK_EOF;
378 			}
379 			break;
380 		case CHR_Letter:
381 			ProcessLetterToken(true);
382 			break;
383 		case CHR_Number:
384 			ProcessNumberToken();
385 			break;
386 		case CHR_Quote:
387 			ProcessQuoteToken();
388 			break;
389 		case CHR_SingleQuote:
390 			ProcessSingleQuoteToken();
391 			break;
392 		default:
393 			ProcessSpecialToken();
394 			break;
395 		}
396 		if (Token != TK_EOF && Src->Skipping)
397 		{
398 			Token = TK_NoToken;
399 		}
400 	} while (Token == TK_NoToken);
401 }
402 
403 //==========================================================================
404 //
405 //	VLexer::NextChr
406 //
407 //==========================================================================
408 
NextChr()409 void VLexer::NextChr()
410 {
411 	if (Src->FilePtr >= Src->FileEnd)
412 	{
413 		Chr = EOF_CHARACTER;
414 		return;
415 	}
416 	if (Src->IncLineNumber)
417 	{
418 		Src->Line++;
419 		Location = TLocation(Src->SourceIdx, Src->Line);
420 		Src->IncLineNumber = false;
421 	}
422 	Chr = *Src->FilePtr++;
423 	if ((vuint8)Chr < ' ')
424 	{
425 		if (Chr == '\n')
426 		{
427 			Src->IncLineNumber = true;
428 			Src->NewLine = true;
429 		}
430 		Chr = ' ';
431 	}
432 }
433 
434 //==========================================================================
435 //
436 //	VLexer::SkipWhitespaceAndComments
437 //
438 //==========================================================================
439 
SkipWhitespaceAndComments()440 void VLexer::SkipWhitespaceAndComments()
441 {
442 	bool Done;
443 	do
444 	{
445 		Done = true;
446 		while (Chr == ' ') NextChr();
447 		if (Chr == '/' && *Src->FilePtr == '*')
448 		{
449 			//	Block comment
450 			NextChr();
451 			do
452 			{
453 				NextChr();
454 				if (Chr == EOF_CHARACTER)
455 				{
456 					ParseError(Location, "End of file inside a comment");
457 					return;
458 				}
459 			} while (Chr != '*' || *Src->FilePtr != '/');
460 			NextChr();
461 			NextChr();
462 			Done = false;
463 		}
464 		else if (Chr == '/' && *Src->FilePtr == '/')
465 		{
466 			//	C++ style comment
467 			NextChr();
468 			do
469 			{
470 				NextChr();
471 				if (Chr == EOF_CHARACTER)
472 				{
473 					ParseError(Location, "End of file inside a comment");
474 					return;
475 				}
476 			} while (!Src->IncLineNumber);
477 			Done = false;
478 		}
479 	} while (!Done);
480 }
481 
482 //==========================================================================
483 //
484 //	VLexer::ProcessPreprocessor
485 //
486 //==========================================================================
487 
ProcessPreprocessor()488 void VLexer::ProcessPreprocessor()
489 {
490 	NextChr();
491 	if (Src->NewLine || Chr == EOF_CHARACTER)
492 	{
493 		ParseError(Location, "Bad directive.");
494 		return;
495 	}
496 	if (ASCIIToChrCode[(vuint8)Chr] != CHR_Letter)
497 	{
498 		ParseError(Location, "Bad directive.");
499 		while (!Src->NewLine && Chr != EOF_CHARACTER) NextChr();
500 		return;
501 	}
502 
503 	ProcessLetterToken(false);
504 	if (!VStr::Cmp(TokenStringBuffer, "line"))
505 	{
506 		//	Read line number
507 		SkipWhitespaceAndComments();
508 		if (ASCIIToChrCode[(vuint8)Chr] != CHR_Number)
509 		{
510 			ParseError(Location, "Bad directive.");
511 		}
512 		ProcessNumberToken();
513 		Src->Line = Number - 1;
514 
515 		//	Read file name
516 		SkipWhitespaceAndComments();
517 		if (ASCIIToChrCode[(vuint8)Chr] != CHR_Quote)
518 		{
519 			ParseError(Location, "Bad directive.");
520 		}
521 		ProcessFileName();
522 		Src->SourceIdx = TLocation::AddSourceFile(String);
523 		Location = TLocation(Src->SourceIdx, Src->Line);
524 
525 		//	Ignore flags
526 		while (!Src->NewLine)
527 		{
528 			NextChr();
529 		}
530 	}
531 	else if (!VStr::Cmp(TokenStringBuffer, "define"))
532 	{
533 		ProcessDefine();
534 	}
535 	else if (!VStr::Cmp(TokenStringBuffer, "ifdef"))
536 	{
537 		ProcessIf(true);
538 	}
539 	else if (!VStr::Cmp(TokenStringBuffer, "ifndef"))
540 	{
541 		ProcessIf(false);
542 	}
543 	else if (!VStr::Cmp(TokenStringBuffer, "else"))
544 	{
545 		ProcessElse();
546 	}
547 	else if (!VStr::Cmp(TokenStringBuffer, "endif"))
548 	{
549 		ProcessEndIf();
550 	}
551 	else if (!VStr::Cmp(TokenStringBuffer, "include"))
552 	{
553 		ProcessInclude();
554 		return;
555 	}
556 	else
557 	{
558 		ParseError(Location, "Bad directive.");
559 		while (!Src->NewLine && Chr != EOF_CHARACTER) NextChr();
560 	}
561 	Token = TK_NoToken;
562 
563 	SkipWhitespaceAndComments();
564 	//	A new-line is expected at the end of preprocessor directive.
565 	if (!Src->NewLine)
566 	{
567 		ParseError(Location, "Bad directive.");
568 	}
569 }
570 
571 //==========================================================================
572 //
573 //	VLexer::ProcessDefine
574 //
575 //==========================================================================
576 
ProcessDefine()577 void VLexer::ProcessDefine()
578 {
579 	SkipWhitespaceAndComments();
580 	//	Argument to the #define must be on the same line.
581 	if (Src->NewLine || Chr == EOF_CHARACTER)
582 	{
583 		ParseError(Location, "Bad directive.");
584 		return;
585 	}
586 
587 	//	Parse name to be defined
588 	if (ASCIIToChrCode[(vuint8)Chr] != CHR_Letter)
589 	{
590 		ParseError(Location, "Bad directive.");
591 		while (!Src->NewLine && Chr != EOF_CHARACTER) NextChr();
592 		return;
593 	}
594 	ProcessLetterToken(false);
595 
596 	if (Src->Skipping)
597 	{
598 		return;
599 	}
600 
601 	AddDefine(TokenStringBuffer);
602 }
603 
604 //==========================================================================
605 //
606 //	VLexer::AddDefine
607 //
608 //==========================================================================
609 
AddDefine(const VStr & CondName)610 void VLexer::AddDefine(const VStr& CondName)
611 {
612 	//	Check for redefined names.
613 	bool Found = false;
614 	for (int i = 0; i < Defines.Num(); i++)
615 	{
616 		if (Defines[i] == CondName)
617 		{
618 			ParseWarning(Location, "Redefined conditional");
619 			Found = true;
620 			break;
621 		}
622 	}
623 	if (!Found)
624 	{
625 		//	Add it.
626 		Defines.Append(CondName);
627 	}
628 }
629 
630 //==========================================================================
631 //
632 //	VLexer::ProcessIf
633 //
634 //==========================================================================
635 
ProcessIf(bool OnTrue)636 void VLexer::ProcessIf(bool OnTrue)
637 {
638 	SkipWhitespaceAndComments();
639 	//	Argument to the #ifdef must be on the same line.
640 	if (Src->NewLine || Chr == EOF_CHARACTER)
641 	{
642 		ParseError(Location, "Bad directive.");
643 		return;
644 	}
645 
646 	//	Parse condition name
647 	if (ASCIIToChrCode[(vuint8)Chr] != CHR_Letter)
648 	{
649 		ParseError(Location, "Bad directive.");
650 		while (!Src->NewLine && Chr != EOF_CHARACTER) NextChr();
651 		return;
652 	}
653 	ProcessLetterToken(false);
654 
655 	if (Src->Skipping)
656 	{
657 		Src->IfStates.Append(IF_Skip);
658 	}
659 	else
660 	{
661 		//	Check if the names has been defined.
662 		bool Found = false;
663 		for (int i = 0; i < Defines.Num(); i++)
664 		{
665 			if (Defines[i] == TokenStringBuffer)
666 			{
667 				Found = true;
668 				break;
669 			}
670 		}
671 		if (Found == OnTrue)
672 		{
673 			Src->IfStates.Append(IF_True);
674 		}
675 		else
676 		{
677 			Src->IfStates.Append(IF_False);
678 			Src->Skipping = true;
679 		}
680 	}
681 }
682 
683 //==========================================================================
684 //
685 //	VLexer::ProcessElse
686 //
687 //==========================================================================
688 
ProcessElse()689 void VLexer::ProcessElse()
690 {
691 	if (!Src->IfStates.Num())
692 	{
693 		ParseError(Location, "#else without an #ifdef/#ifndef");
694 		return;
695 	}
696 	switch (Src->IfStates[Src->IfStates.Num() - 1])
697 	{
698 	case IF_True:
699 		Src->IfStates[Src->IfStates.Num() - 1] = IF_ElseFalse;
700 		Src->Skipping = true;
701 		break;
702 	case IF_False:
703 		Src->IfStates[Src->IfStates.Num() - 1] = IF_ElseTrue;
704 		Src->Skipping = false;
705 		break;
706 	case IF_Skip:
707 		Src->IfStates[Src->IfStates.Num() - 1] = IF_ElseSkip;
708 		break;
709 	case IF_ElseTrue:
710 	case IF_ElseFalse:
711 	case IF_ElseSkip:
712 		ParseError(Location, "Multiple #else directives for a single #ifdef");
713 		Src->Skipping = true;
714 		break;
715 	}
716 }
717 
718 //==========================================================================
719 //
720 //	VLexer::ProcessEndIf
721 //
722 //==========================================================================
723 
ProcessEndIf()724 void VLexer::ProcessEndIf()
725 {
726 	if (!Src->IfStates.Num())
727 	{
728 		ParseError(Location, "#endif without an #ifdef/#ifndef");
729 		return;
730 	}
731 	Src->IfStates.RemoveIndex(Src->IfStates.Num() - 1);
732 	if (Src->IfStates.Num() > 0)
733 	{
734 		switch (Src->IfStates[Src->IfStates.Num() - 1])
735 		{
736 		case IF_True:
737 		case IF_ElseTrue:
738 			Src->Skipping = false;
739 			break;
740 		case IF_False:
741 		case IF_ElseFalse:
742 			Src->Skipping = true;
743 			break;
744 		case IF_Skip:
745 		case IF_ElseSkip:
746 			break;
747 		}
748 	}
749 	else
750 	{
751 		Src->Skipping = false;
752 	}
753 }
754 
755 //==========================================================================
756 //
757 //	VLexer::ProcessInclude
758 //
759 //==========================================================================
760 
ProcessInclude()761 void VLexer::ProcessInclude()
762 {
763 	SkipWhitespaceAndComments();
764 	//	File name must be on the same line.
765 	if (Src->NewLine || Chr == EOF_CHARACTER)
766 	{
767 		ParseError(Location, "Bad directive.");
768 		return;
769 	}
770 
771 	//	Parse file name
772 	if (Chr != '\"')
773 	{
774 		ParseError(Location, "Bad directive.");
775 		while (!Src->NewLine && Chr != EOF_CHARACTER) NextChr();
776 		return;
777 	}
778 	ProcessFileName();
779 	TLocation Loc = Location;
780 
781 	Token = TK_NoToken;
782 	SkipWhitespaceAndComments();
783 	//	A new-line is expected at the end of preprocessor directive.
784 	if (!Src->NewLine)
785 	{
786 		ParseError(Location, "Bad directive.");
787 	}
788 
789 	if (Src->Skipping)
790 	{
791 		return;
792 	}
793 
794 	//	Check if it's an absolute path location.
795 	if (TokenStringBuffer[0] != '/' && TokenStringBuffer[0] != '\\')
796 	{
797 		//	First try relative to the current source file.
798 		if (Src->Path.IsNotEmpty())
799 		{
800 			VStr FileName = Src->Path + VStr(TokenStringBuffer);
801 #ifdef IN_VCC
802 			VStream* Strm = OpenFile(FileName);
803 #else
804 			VStream* Strm = FL_OpenFileRead(FileName);
805 #endif
806 			if (Strm)
807 			{
808 				delete Strm;
809 				Strm = NULL;
810 				PushSource(Loc, FileName);
811 				return;
812 			}
813 		}
814 
815 		for (int i = IncludePath.Num() - 1; i >= 0; i--)
816 		{
817 			VStr FileName = IncludePath[i] + VStr(TokenStringBuffer);
818 #ifdef IN_VCC
819 			VStream* Strm = OpenFile(FileName);
820 #else
821 			VStream* Strm = FL_OpenFileRead(FileName);
822 #endif
823 			if (Strm)
824 			{
825 				delete Strm;
826 				Strm = NULL;
827 				PushSource(Loc, FileName);
828 				return;
829 			}
830 		}
831 	}
832 
833 	//	Either it's relative to the current directory or absolute path.
834 	PushSource(Loc, TokenStringBuffer);
835 }
836 
837 //==========================================================================
838 //
839 //	VLexer::AddIncludePath
840 //
841 //==========================================================================
842 
AddIncludePath(const VStr & DirName)843 void VLexer::AddIncludePath(const VStr& DirName)
844 {
845 	VStr Copy = DirName;
846 	//	Append trailing slash if needed.
847 	if (!Copy.EndsWith("/") && !Copy.EndsWith("\\"))
848 	{
849 		Copy += '/';
850 	}
851 	IncludePath.Append(Copy);
852 }
853 
854 //==========================================================================
855 //
856 //	VLexer::ProcessNumberToken
857 //
858 //==========================================================================
859 
ProcessNumberToken()860 void VLexer::ProcessNumberToken()
861 {
862 	char c;
863 
864 	Token = TK_IntLiteral;
865 	c = Chr;
866 	NextChr();
867 	Number = c - '0';
868 	if (c == '0' && (Chr == 'x' || Chr == 'X'))
869 	{
870 		//  Hexadecimal constant.
871 		NextChr();
872 		while (ASCIIToHexDigit[(vuint8)Chr] != NON_HEX_DIGIT)
873 		{
874 			Number = (Number << 4) + ASCIIToHexDigit[(vuint8)Chr];
875 			NextChr();
876 		}
877 		return;
878 	}
879 	while (ASCIIToChrCode[(vuint8)Chr] == CHR_Number)
880 	{
881 		Number = 10 * Number + (Chr - '0');
882 		NextChr();
883 	}
884 	if (Chr == '.')
885 	{
886 		Token = TK_FloatLiteral;
887 		NextChr(); // Point
888 		Float = Number;
889 		float	fmul = 0.1;
890 		while (ASCIIToChrCode[(vuint8)Chr] == CHR_Number)
891 		{
892 			Float += (Chr - '0') * fmul;
893 			fmul /= 10.0;
894 			NextChr();
895 		}
896 		return;
897 	}
898 	if (Chr == '_')
899 	{
900 		int radix;
901 		int digit;
902 
903 		NextChr(); // Underscore
904 		radix = Number;
905 		if (radix < 2 || radix > 36)
906 		{
907 			ParseError(Location, ERR_BAD_RADIX_CONSTANT);
908 			radix = 2;
909 		}
910 		Number = 0;
911 		do
912 		{
913 			digit = VStr::ToUpper(Chr);
914 			if (digit < '0' || (digit > '9' && digit < 'A') || digit > 'Z')
915 			{
916 				digit = -1;
917 			}
918 			else if(digit > '9')
919 			{
920 				digit = 10 + digit - 'A';
921 			}
922 			else
923 			{
924 				digit -= '0';
925 			}
926 			if (digit >= radix)
927 			{
928 				digit = -1;
929 			}
930 			if (digit != -1)
931 			{
932 				Number = radix * Number + digit;
933 				NextChr();
934 			}
935 		} while (digit != -1);
936 	}
937 }
938 
939 //==========================================================================
940 //
941 //	VLexer::ProcessChar
942 //
943 //==========================================================================
944 
ProcessChar()945 void VLexer::ProcessChar()
946 {
947 	if (Chr == EOF_CHARACTER)
948 	{
949 		ParseError(Location, ERR_EOF_IN_STRING);
950 		BailOut();
951 	}
952 	if (Src->IncLineNumber)
953 	{
954 		ParseError(Location, ERR_NEW_LINE_INSIDE_QUOTE);
955 	}
956 	if (Chr == '\\')
957 	{
958 		//	Special symbol
959 		NextChr();
960 		if (Chr == EOF_CHARACTER)
961 		{
962 			ParseError(Location, ERR_EOF_IN_STRING);
963 			BailOut();
964 		}
965 		if (Src->IncLineNumber)
966 		{
967 			ParseError(Location, ERR_NEW_LINE_INSIDE_QUOTE);
968 		}
969 		if (Chr == 'n')
970 			Chr = '\n';
971 		else if (Chr == '\'')
972 			Chr = '\'';
973 		else if (Chr == '"')
974 			Chr = '"';
975 		else if (Chr == 't')
976 			Chr = '\t';
977 		else if (Chr == '\\')
978 			Chr = '\\';
979 		else if (Chr == 'c')
980 			Chr = TEXT_COLOUR_ESCAPE;
981 		else
982 			ParseError(Location, ERR_UNKNOWN_ESC_CHAR);
983 	}
984 }
985 
986 //==========================================================================
987 //
988 //	VLexer::ProcessQuoteToken
989 //
990 //==========================================================================
991 
ProcessQuoteToken()992 void VLexer::ProcessQuoteToken()
993 {
994 	int len;
995 
996 	Token = TK_StringLiteral;
997 	len = 0;
998 	NextChr();
999 	while (Chr != '\"')
1000 	{
1001 		if (len >= MAX_QUOTED_LENGTH - 1)
1002 		{
1003 			ParseError(Location, ERR_STRING_TOO_LONG);
1004 			NextChr();
1005 			continue;
1006 		}
1007 		ProcessChar();
1008 		TokenStringBuffer[len] = Chr;
1009 		NextChr();
1010 		len++;
1011 	}
1012 	TokenStringBuffer[len] = 0;
1013 	NextChr();
1014 }
1015 
1016 //==========================================================================
1017 //
1018 //	VLexer::ProcessSingleQuoteToken
1019 //
1020 //==========================================================================
1021 
ProcessSingleQuoteToken()1022 void VLexer::ProcessSingleQuoteToken()
1023 {
1024 	int len;
1025 
1026 	Token = TK_NameLiteral;
1027 	len = 0;
1028 	NextChr();
1029 	while (Chr != '\'')
1030 	{
1031 		if (len >= MAX_IDENTIFIER_LENGTH - 1)
1032 		{
1033 			ParseError(Location, ERR_STRING_TOO_LONG);
1034 			NextChr();
1035 			continue;
1036 		}
1037 		ProcessChar();
1038 		TokenStringBuffer[len] = Chr;
1039 		NextChr();
1040 		len++;
1041 	}
1042 	TokenStringBuffer[len] = 0;
1043 	NextChr();
1044 	Name = TokenStringBuffer;
1045 }
1046 
1047 //==========================================================================
1048 //
1049 //	VLexer::ProcessLetterToken
1050 //
1051 //==========================================================================
1052 
ProcessLetterToken(bool CheckKeywords)1053 void VLexer::ProcessLetterToken(bool CheckKeywords)
1054 {
1055 	int		len;
1056 
1057 	Token = TK_Identifier;
1058 	len = 0;
1059 	while (ASCIIToChrCode[(vuint8)Chr] == CHR_Letter
1060 		|| ASCIIToChrCode[(vuint8)Chr] == CHR_Number)
1061 	{
1062 		if (len == MAX_IDENTIFIER_LENGTH - 1)
1063 		{
1064 			ParseError(Location, ERR_IDENTIFIER_TOO_LONG);
1065 			NextChr();
1066 			continue;
1067 		}
1068 		TokenStringBuffer[len] = Chr;
1069 		len++;
1070 		NextChr();
1071 	}
1072 	TokenStringBuffer[len] = 0;
1073 
1074 	if (!CheckKeywords)
1075 	{
1076 		return;
1077 	}
1078 
1079 	register const char* s = TokenStringBuffer;
1080 	switch (s[0])
1081 	{
1082 	case '_':
1083 		if (s[1] == '_')
1084 		{
1085 			if (s[2] == 'm' && s[3] == 'o' && s[4] == 'b' && s[5] == 'j' &&
1086 				s[6] == 'i' && s[7] == 'n' && s[8] == 'f' && s[9] == 'o' &&
1087 				s[10] == '_' && s[11] == '_' && s[12] == 0)
1088 			{
1089 				Token = TK_MobjInfo;
1090 			}
1091 			else if (s[2] == 's' && s[3] == 'c' && s[4] == 'r' &&
1092 				s[5] == 'i' && s[6] == 'p' && s[7] == 't' && s[8] == 'i' &&
1093 				s[9] == 'd' && s[10] == '_' && s[11] == '_' && s[12] == 0)
1094 			{
1095 				Token = TK_ScriptId;
1096 			}
1097 		}
1098 		break;
1099 
1100 	case 'a':
1101 		if (s[1] == 'b' && s[2] == 's' && s[3] == 't' && s[4] == 'r' &&
1102 			s[5] == 'a' && s[6] == 'c' && s[7] == 't' && s[8] == 0)
1103 		{
1104 			Token = TK_Abstract;
1105 		}
1106 		else if (s[1] == 'r' && s[2] == 'r' && s[3] == 'a' && s[4] == 'y' &&
1107 			s[5] == 0)
1108 		{
1109 			Token = TK_Array;
1110 		}
1111 		break;
1112 
1113 	case 'b':
1114 		if (s[1] == 'o' && s[2] == 'o' && s[3] == 'l' && s[4] == 0)
1115 		{
1116 			Token = TK_Bool;
1117 		}
1118 		else if (s[1] == 'r' && s[2] == 'e' && s[3] == 'a' && s[4] == 'k' &&
1119 			s[5] == 0)
1120 		{
1121 			Token = TK_Break;
1122 		}
1123 		else if (s[1] == 'y' && s[2] == 't' && s[3] == 'e' && s[4] == 0)
1124 		{
1125 			Token = TK_Byte;
1126 		}
1127 		break;
1128 
1129 	case 'c':
1130 		if (s[1] == 'a' && s[2] == 's' && s[3] == 'e' && s[4] == 0)
1131 		{
1132 			Token = TK_Case;
1133 		}
1134 		else if (s[1] == 'l' && s[2] == 'a' && s[3] == 's' && s[4] == 's' &&
1135 			s[5] == 0)
1136 		{
1137 			Token = TK_Class;
1138 		}
1139 		else if (s[1] == 'o' && s[2] == 'n')
1140 		{
1141 			if (s[3] == 's' && s[4] == 't' && s[5] == 0)
1142 			{
1143 				Token = TK_Const;
1144 			}
1145 			else if (s[3] == 't' && s[4] == 'i' && s[5] == 'n' &&
1146 				s[6] == 'u' && s[7] == 'e' && s[8] == 0)
1147 			{
1148 				Token = TK_Continue;
1149 			}
1150 		}
1151 		break;
1152 
1153 	case 'd':
1154 		if (s[1] == 'e')
1155 		{
1156 			if (s[2] == 'c' && s[3] == 'o' && s[4] == 'r' &&
1157 				s[5] == 'a' && s[6] == 't' && s[7] == 'e' && s[8] == 0)
1158 			{
1159 				Token = TK_Decorate;
1160 			}
1161 			else if (s[2] == 'f' && s[3] == 'a' && s[4] == 'u' &&
1162 				s[5] == 'l' && s[6] == 't')
1163 			{
1164 				if (s[7] == 0)
1165 				{
1166 					Token = TK_Default;
1167 				}
1168 				else if (s[7] == 'p' && s[8] == 'r' && s[9] == 'o' &&
1169 					s[10] == 'p' && s[11] == 'e' && s[12] == 'r' &&
1170 					s[13] == 't' && s[14] == 'i' && s[15] == 'e' &&
1171 					s[16] == 's' && s[17] == 0)
1172 				{
1173 					Token = TK_DefaultProperties;
1174 				}
1175 			}
1176 			else if (s[2] == 'l' && s[3] == 'e' && s[4] == 'g' &&
1177 				s[5] == 'a' && s[6] == 't' && s[7] == 'e' && s[8] == 0)
1178 			{
1179 				Token = TK_Delegate;
1180 			}
1181 		}
1182 		else if (s[1] == 'o' && s[2] == 0)
1183 		{
1184 			Token = TK_Do;
1185 		}
1186 		break;
1187 
1188 	case 'e':
1189 		if (s[1] == 'l' && s[2] == 's' && s[3] == 'e' && s[4] == 0)
1190 		{
1191 			Token = TK_Else;
1192 		}
1193 		else if (s[1] == 'n' && s[2] == 'u' && s[3] == 'm' && s[4] == 0)
1194 		{
1195 			Token = TK_Enum;
1196 		}
1197 		break;
1198 
1199 	case 'f':
1200 		if (s[1] == 'a' && s[2] == 'l' && s[3] == 's' && s[4] == 'e' &&
1201 			s[5] == 0)
1202 		{
1203 			Token = TK_False;
1204 		}
1205 		else if (s[1] == 'i' && s[2] == 'n' && s[3] == 'a' && s[4] == 'l' &&
1206 			s[5] == 0)
1207 		{
1208 			Token = TK_Final;
1209 		}
1210 		else if (s[1] == 'l' && s[2] == 'o' && s[3] == 'a' && s[4] == 't' &&
1211 			s[5] == 0)
1212 		{
1213 			Token = TK_Float;
1214 		}
1215 		else if (s[1] == 'o' && s[2] == 'r')
1216 		{
1217 			if (s[3] == 0)
1218 			{
1219 				Token = TK_For;
1220 			}
1221 			else if (s[3] == 'e' && s[4] == 'a' && s[5] == 'c' &&
1222 				s[6] == 'h' && s[7] == 0)
1223 			{
1224 				Token = TK_Foreach;
1225 			}
1226 		}
1227 		break;
1228 
1229 	case 'g':
1230 		if (s[1] == 'a' && s[2] == 'm' && s[3] == 'e' && s[4] == 0)
1231 		{
1232 			Token = TK_Game;
1233 		}
1234 		else if (s[1] == 'e' && s[2] == 't' && s[3] == 0)
1235 		{
1236 			Token = TK_Get;
1237 		}
1238 
1239 	case 'i':
1240 		if (s[1] == 'f' && s[2] == 0)
1241 		{
1242 			Token = TK_If;
1243 		}
1244 		else if (s[1] == 'm' && s[2] == 'p' && s[3] == 'o' && s[4] == 'r' &&
1245 			s[5] == 't' && s[6] == 0)
1246 		{
1247 			Token = TK_Import;
1248 		}
1249 		else if (s[1] == 'n' && s[2] == 't' && s[3] == 0)
1250 		{
1251 			Token = TK_Int;
1252 		}
1253 		else if (s[1] == 't' && s[2] == 'e' && s[3] == 'r' && s[4] == 'a' &&
1254 			s[5] == 't' && s[6] == 'o' && s[7] == 'r' && s[8] == 0)
1255 		{
1256 			Token = TK_Iterator;
1257 		}
1258 		break;
1259 
1260 	case 'n':
1261 		if (s[1] == 'a')
1262 		{
1263 			if (s[2] == 'm' && s[3] == 'e' && s[4] == 0)
1264 			{
1265 				Token = TK_Name;
1266 			}
1267 			if (s[2] == 't' && s[3] == 'i' && s[4] == 'v' && s[5] == 'e' &&
1268 				s[6] == 0)
1269 			{
1270 				Token = TK_Native;
1271 			}
1272 		}
1273 		else if (s[1] == 'o' && s[2] == 'n' && s[3] == 'e' && s[4] == 0)
1274 		{
1275 			Token = TK_None;
1276 		}
1277 		break;
1278 
1279 /*	case 'N':
1280 		if (s[1] == 'U' && s[2] == 'L' &&
1281 			s[3] == 'L' && s[4] == 0)
1282 		{
1283 			Token = TK_KEYWORD;
1284 			tk_Keyword = KW_NULL;
1285 		}
1286 		break;*/
1287 
1288 	case 'o':
1289 		if (s[1] == 'p' && s[2] == 't' && s[3] == 'i' && s[4] == 'o' &&
1290 			s[5] == 'n' && s[6] == 'a' && s[7] == 'l' && s[8] == 0)
1291 		{
1292 			Token = TK_Optional;
1293 		}
1294 		else if (s[1] == 'u' && s[2] == 't' && s[3] == 0)
1295 		{
1296 			Token = TK_Out;
1297 		}
1298 		break;
1299 
1300 	case 'p':
1301 		if (s[1] == 'r' && s[2] == 'i' && s[3] == 'v' && s[4] == 'a' &&
1302 			s[5] == 't' && s[6] == 'e' && s[7] == 0)
1303 		{
1304 			Token = TK_Private;
1305 		}
1306 		break;
1307 
1308 	case 'r':
1309 		if (s[1] == 'e')
1310 		{
1311 			if (s[2] == 'a' && s[3] == 'd' && s[4] == 'o' && s[5] == 'n' &&
1312 				s[6] == 'l' && s[7] == 'y' && s[8] == 0)
1313 			{
1314 				Token = TK_ReadOnly;
1315 			}
1316 			else if (s[2] == 'l' && s[3] == 'i' && s[4] == 'a' &&
1317 				s[5] == 'b' && s[6] == 'l' && s[7] == 'e' && s[8] == 0)
1318 			{
1319 				Token = TK_Reliable;
1320 			}
1321 			else if (s[2] == 'p' && s[3] == 'l' && s[4] == 'i' &&
1322 				s[5] == 'c' && s[6] == 'a' && s[7] == 't' && s[8] == 'i' &&
1323 				s[9] == 'o' && s[10] == 'n' && s[11] == 0)
1324 			{
1325 				Token = TK_Replication;
1326 			}
1327 			else if (s[2] == 't' && s[3] == 'u' && s[4] == 'r' &&
1328 				s[5] == 'n' && s[6] == 0)
1329 			{
1330 				Token = TK_Return;
1331 			}
1332 		}
1333 		break;
1334 
1335 	case 's':
1336 		if (s[1] == 'e')
1337 		{
1338 			if (s[2] == 'l' && s[3] == 'f' && s[4] == 0)
1339 			{
1340 				Token = TK_Self;
1341 			}
1342 			else if (s[2] == 't' && s[3] == 0)
1343 			{
1344 				Token = TK_Set;
1345 			}
1346 		}
1347 		else if (s[1] == 'p' && s[2] == 'a' && s[3] == 'w' && s[4] == 'n' &&
1348 			s[5] == 'e' && s[6] == 'r' && s[7] == 0)
1349 		{
1350 			Token = TK_Spawner;
1351 		}
1352 		else if (s[1] == 't')
1353 		{
1354 			if (s[2] == 'a' && s[3] == 't')
1355 			{
1356 				if (s[4] == 'e')
1357 				{
1358 					if (s[5] == 0)
1359 					{
1360 						Token = TK_State;
1361 					}
1362 					else if (s[5] == 's' && s[6] == 0)
1363 					{
1364 						Token = TK_States;
1365 					}
1366 				}
1367 				else if (s[4] == 'i' && s[5] == 'c' && s[6] == 0)
1368 				{
1369 					Token = TK_Static;
1370 				}
1371 			}
1372 			else if (s[2] == 'r')
1373 			{
1374 				if (s[3] == 'i' && s[4] == 'n' && s[5] == 'g' && s[6] == 0)
1375 				{
1376 					Token = TK_String;
1377 				}
1378 				else if (s[3] == 'u' && s[4] == 'c' && s[5] == 't' &&
1379 					s[6] == 0)
1380 				{
1381 					Token = TK_Struct;
1382 				}
1383 			}
1384 		}
1385 		else if (s[1] == 'w' && s[2] == 'i' && s[3] == 't' && s[4] == 'c' &&
1386 			s[5] == 'h' && s[6] == 0)
1387 		{
1388 			Token = TK_Switch;
1389 		}
1390 		break;
1391 
1392 	case 't':
1393 		if (s[1] == 'r')
1394 		{
1395 			if (s[2] == 'a' && s[3] == 'n' && s[4] == 's' && s[5] == 'i' &&
1396 				s[6] == 'e' && s[7] == 'n' && s[8] == 't' && s[9] == 0)
1397 			{
1398 				Token = TK_Transient;
1399 			}
1400 			else if (s[2] == 'u' && s[3] == 'e' && s[4] == 0)
1401 			{
1402 				Token = TK_True;
1403 			}
1404 		}
1405 		break;
1406 
1407 	case 'u':
1408 		if (s[1] == 'n' && s[2] == 'r' && s[3] == 'e' && s[4] == 'l' &&
1409 			s[5] == 'i' && s[6] == 'a' && s[7] == 'b' && s[8] == 'l' &&
1410 			s[9] == 'e' && s[10] == 0)
1411 		{
1412 			Token = TK_Unreliable;
1413 		}
1414 		break;
1415 
1416 	case 'v':
1417 		if (s[1] == 'e' && s[2] == 'c' && s[3] == 't' && s[4] == 'o' &&
1418 			s[5] == 'r' && s[6] == 0)
1419 		{
1420 			Token = TK_Vector;
1421 		}
1422 		else if (s[1] == 'o' && s[2] == 'i' && s[3] == 'd' && s[4] == 0)
1423 		{
1424 			Token = TK_Void;
1425 		}
1426 		break;
1427 
1428 	case 'w':
1429 		if (s[1] == 'h' && s[2] == 'i' && s[3] == 'l' && s[4] == 'e' &&
1430 			s[5] == 0)
1431 		{
1432 			Token = TK_While;
1433 		}
1434 		break;
1435 	}
1436 	if (s[0] == 'N' && s[1] == 'U' && s[2] == 'L' && s[3] == 'L' && s[4] == 0)
1437 	{
1438 		Token = TK_Null;
1439 	}
1440 
1441 	if (Token == TK_Identifier)
1442 	{
1443 		Name = TokenStringBuffer;
1444 	}
1445 }
1446 
1447 //==========================================================================
1448 //
1449 //	VLexer::ProcessSpecialToken
1450 //
1451 //==========================================================================
1452 
ProcessSpecialToken()1453 void VLexer::ProcessSpecialToken()
1454 {
1455 	char c = Chr;
1456 	NextChr();
1457 	switch (c)
1458 	{
1459 	case '+':
1460 		if (Chr == '=')
1461 		{
1462 			Token = TK_AddAssign;
1463 			NextChr();
1464 		}
1465 		else if (Chr == '+')
1466 		{
1467 			Token = TK_Inc;
1468 			NextChr();
1469 		}
1470 		else
1471 		{
1472 			Token = TK_Plus;
1473 		}
1474 		break;
1475 
1476 	case '-':
1477 		if (Chr == '=')
1478 		{
1479 			Token = TK_MinusAssign;
1480 			NextChr();
1481 		}
1482 		else if (Chr == '-')
1483 		{
1484 			Token = TK_Dec;
1485 			NextChr();
1486 		}
1487 		else if (Chr == '>')
1488 		{
1489 			Token = TK_Arrow;
1490 			NextChr();
1491 		}
1492 		else
1493 		{
1494 			Token = TK_Minus;
1495 		}
1496 		break;
1497 
1498 	case '*':
1499 		if (Chr == '=')
1500 		{
1501 			Token = TK_MultiplyAssign;
1502 			NextChr();
1503 		}
1504 		else
1505 		{
1506 			Token = TK_Asterisk;
1507 		}
1508 		break;
1509 
1510 	case '/':
1511 		if (Chr == '=')
1512 		{
1513 			Token = TK_DivideAssign;
1514 			NextChr();
1515 		}
1516 		else
1517 		{
1518 			Token = TK_Slash;
1519 		}
1520 		break;
1521 
1522 	case '%':
1523 		if (Chr == '=')
1524 		{
1525 			Token = TK_ModAssign;
1526 			NextChr();
1527 		}
1528 		else
1529 		{
1530 			Token = TK_Percent;
1531 		}
1532 		break;
1533 
1534 	case '=':
1535 		if (Chr == '=')
1536 		{
1537 			Token = TK_Equals;
1538 			NextChr();
1539 		}
1540 		else
1541 		{
1542 			Token = TK_Assign;
1543 		}
1544 		break;
1545 
1546 	case '<':
1547 		if (Chr == '<')
1548 		{
1549 			NextChr();
1550 			if (Chr == '=')
1551 			{
1552 				Token = TK_LShiftAssign;
1553 				NextChr();
1554 			}
1555 			else
1556 			{
1557 				Token = TK_LShift;
1558 			}
1559 		}
1560 		else if (Chr == '=')
1561 		{
1562 			Token = TK_LessEquals;
1563 			NextChr();
1564 		}
1565 		else
1566 		{
1567 			Token = TK_Less;
1568 		}
1569 		break;
1570 
1571 	case '>':
1572 		if (Chr == '>')
1573 		{
1574 			NextChr();
1575 			if (Chr == '=')
1576 			{
1577 				Token = TK_RShiftAssign;
1578 				NextChr();
1579 			}
1580 			else
1581 			{
1582 				Token = TK_RShift;
1583 			}
1584 		}
1585 		else if (Chr == '=')
1586 		{
1587 			Token = TK_GreaterEquals;
1588 			NextChr();
1589 		}
1590 		else
1591 		{
1592 			Token = TK_Greater;
1593 		}
1594 		break;
1595 
1596 	case '!':
1597 		if (Chr == '=')
1598 		{
1599 			Token = TK_NotEquals;
1600 			NextChr();
1601 		}
1602 		else
1603 		{
1604 			Token = TK_Not;
1605 		}
1606 		break;
1607 
1608 	case '&':
1609 		if (Chr == '=')
1610 		{
1611 			Token = TK_AndAssign;
1612 			NextChr();
1613 		}
1614 		else if (Chr == '&')
1615 		{
1616 			Token = TK_AndLog;
1617 			NextChr();
1618 		}
1619 		else
1620 		{
1621 			Token = TK_And;
1622 		}
1623 		break;
1624 
1625 	case '|':
1626 		if (Chr == '=')
1627 		{
1628 			Token = TK_OrAssign;
1629 			NextChr();
1630 		}
1631 		else if (Chr == '|')
1632 		{
1633 			Token = TK_OrLog;
1634 			NextChr();
1635 		}
1636 		else
1637 		{
1638 			Token = TK_Or;
1639 		}
1640 		break;
1641 
1642 	case '^':
1643 		if (Chr == '=')
1644 		{
1645 			Token = TK_XOrAssign;
1646 			NextChr();
1647 		}
1648 		else
1649 		{
1650 			Token = TK_XOr;
1651 		}
1652 		break;
1653 
1654 	case '.':
1655 		if (Chr == '.' && Src->FilePtr[0] == '.')
1656 		{
1657 			Token = TK_VarArgs;
1658 			NextChr();
1659 			NextChr();
1660 		}
1661 		else
1662 		{
1663 			Token = TK_Dot;
1664 		}
1665 		break;
1666 
1667 	case ':':
1668 		if (Chr == ':')
1669 		{
1670 			Token = TK_DColon;
1671 			NextChr();
1672 		}
1673 		else
1674 		{
1675 			Token = TK_Colon;
1676 		}
1677 		break;
1678 
1679 	case '(':
1680 		Token = TK_LParen;
1681 		break;
1682 
1683 	case ')':
1684 		Token = TK_RParen;
1685 		break;
1686 
1687 	case '?':
1688 		Token = TK_Quest;
1689 		break;
1690 
1691 	case '~':
1692 		Token = TK_Tilde;
1693 		break;
1694 
1695 	case ',':
1696 		Token = TK_Comma;
1697 		break;
1698 
1699 	case ';':
1700 		Token = TK_Semicolon;
1701 		break;
1702 
1703 	case '[':
1704 		Token = TK_LBracket;
1705 		break;
1706 
1707 	case ']':
1708 		Token = TK_RBracket;
1709 		break;
1710 
1711 	case '{':
1712 		Token = TK_LBrace;
1713 		break;
1714 
1715 	case '}':
1716 		Token = TK_RBrace;
1717 		break;
1718 
1719 	default:
1720 		ParseError(Location, ERR_BAD_CHARACTER, "Unknown punctuation \'%c\'", Chr);
1721 		Token = TK_NoToken;
1722 	}
1723 }
1724 
1725 //==========================================================================
1726 //
1727 //	VLexer::ProcessFileName
1728 //
1729 //==========================================================================
1730 
ProcessFileName()1731 void VLexer::ProcessFileName()
1732 {
1733 	int len = 0;
1734 	NextChr();
1735 	while (Chr != '\"')
1736 	{
1737 		if (len >= MAX_QUOTED_LENGTH - 1)
1738 		{
1739 			ParseError(Location, ERR_STRING_TOO_LONG);
1740 			NextChr();
1741 			continue;
1742 		}
1743 		if (Chr == EOF_CHARACTER)
1744 		{
1745 			ParseError(Location, ERR_EOF_IN_STRING);
1746 			break;
1747 		}
1748 		if (Src->IncLineNumber)
1749 		{
1750 			ParseError(Location, ERR_NEW_LINE_INSIDE_QUOTE);
1751 		}
1752 		TokenStringBuffer[len] = Chr;
1753 		NextChr();
1754 		len++;
1755 	}
1756 	TokenStringBuffer[len] = 0;
1757 	NextChr();
1758 }
1759 
1760 //==========================================================================
1761 //
1762 //	VLexer::Check
1763 //
1764 //==========================================================================
1765 
Check(EToken tk)1766 bool VLexer::Check(EToken tk)
1767 {
1768 	if (Token == tk)
1769 	{
1770 		NextToken();
1771 		return true;
1772 	}
1773 	return false;
1774 }
1775 
1776 //==========================================================================
1777 //
1778 //	VLexer::Expect
1779 //
1780 //	Report error, if current token is not equals to tk.
1781 //	Take next token.
1782 //
1783 //==========================================================================
1784 
Expect(EToken tk)1785 void VLexer::Expect(EToken tk)
1786 {
1787 	if (Token != tk)
1788 	{
1789 		ParseError(Location, "expected %s, found %s", TokenNames[tk],
1790 			TokenNames[Token]);
1791 	}
1792 	NextToken();
1793 }
1794 
1795 //==========================================================================
1796 //
1797 //	VLexer::Expect
1798 //
1799 //	Report error, if current token is not equals to tk.
1800 //	Take next token.
1801 //
1802 //==========================================================================
1803 
Expect(EToken tk,ECompileError error)1804 void VLexer::Expect(EToken tk, ECompileError error)
1805 {
1806 	if (Token != tk)
1807 	{
1808 		ParseError(Location, error, "expected %s, found %s", TokenNames[tk],
1809 			TokenNames[Token]);
1810 	}
1811 	NextToken();
1812 }
1813