1 /*******************************************************************************
2 * tokenize.cpp
3 *
4 * This module implements the first part of a two part parser for the scene
5 * description files. This phase changes the input file into tokens.
6 *
7 * This module tokenizes the input file and sends the tokens created
8 * to the parser (the second stage). Tokens sent to the parser contain a
9 * token ID, the line number of the token, and if necessary, some data for
10 * the token.
11 *
12 * ---------------------------------------------------------------------------
13 * Persistence of Vision Ray Tracer ('POV-Ray') version 3.7.
14 * Copyright 1991-2013 Persistence of Vision Raytracer Pty. Ltd.
15 *
16 * POV-Ray is free software: you can redistribute it and/or modify
17 * it under the terms of the GNU Affero General Public License as
18 * published by the Free Software Foundation, either version 3 of the
19 * License, or (at your option) any later version.
20 *
21 * POV-Ray is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU Affero General Public License for more details.
25 *
26 * You should have received a copy of the GNU Affero General Public License
27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28 * ---------------------------------------------------------------------------
29 * POV-Ray is based on the popular DKB raytracer version 2.12.
30 * DKBTrace was originally written by David K. Buck.
31 * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
32 * ---------------------------------------------------------------------------
33 * $File: //depot/public/povray/3.x/source/backend/parser/tokenize.cpp $
34 * $Revision: #1 $
35 * $Change: 6069 $
36 * $DateTime: 2013/11/06 11:59:40 $
37 * $Author: chrisc $
38 *******************************************************************************/
39
40 #include <ctype.h>
41
42 // frame.h must always be the first POV file included (pulls in platform config)
43 #include "backend/frame.h"
44 #include "base/povmsgid.h"
45 #include "base/stringutilities.h"
46 #include "backend/parser/parse.h"
47 #include "backend/colour/colour.h"
48 #include "backend/texture/texture.h"
49 #include "backend/math/matrices.h"
50 #include "backend/support/fileutil.h"
51 #include "backend/support/msgutil.h"
52
53 // this must be the last file included
54 #include "base/povdebug.h"
55
56 namespace pov
57 {
58
59 using namespace pov_base;
60
61 /*****************************************************************************
62 * Local preprocessor defines
63 ******************************************************************************/
64
65 #define CALL(x) { if (!(x)) return (false); }
66
67 /*****************************************************************************
68 *
69 * FUNCTION
70 *
71 * INPUT
72 *
73 * OUTPUT
74 *
75 * RETURNS
76 *
77 * AUTHOR
78 *
79 * DESCRIPTION
80 *
81 * CHANGES
82 *
83 ******************************************************************************/
84
Initialize_Tokenizer()85 void Parser::Initialize_Tokenizer()
86 {
87 IStream *rfile = NULL;
88 UCS2String b;
89 int c;
90
91 pre_init_tokenizer ();
92
93 rfile = Locate_File(this, sceneData, sceneData->inputFile.c_str(),POV_File_Text_POV,b,true);
94 if(rfile != NULL)
95 {
96 Input_File->In_File = new ITextStream(b.c_str(), rfile);
97 sceneData->inputFile = b;
98 }
99
100 if (Input_File->In_File == NULL)
101 {
102 Error ("Cannot open input file.");
103 }
104
105 Input_File->R_Flag = false;
106
107 Got_EOF = false;
108
109 /* Init conditional stack. */
110
111 Cond_Stack = (CS_ENTRY*)POV_MALLOC(sizeof(CS_ENTRY) * COND_STACK_SIZE, "conditional stack");
112
113 Cond_Stack[0].Cond_Type = ROOT_COND;
114 Cond_Stack[0].Switch_Value = 0.0;
115
116 init_sym_tables();
117 Max_Trace_Level = MAX_TRACE_LEVEL_DEFAULT;
118 Had_Max_Trace_Level = false;
119
120 /* ignore any leading characters if they have character codes above 127, this
121 takes care of UTF-8 files with encoding info at the beginning of the file */
122 for(c = Echo_getc(); c > 127; c = Echo_getc())
123 sceneData->stringEncoding = 1; // switch to UTF-8 automatically [trf]
124 Echo_ungetc(c);
125 }
126
127
128
129 /*****************************************************************************
130 *
131 * FUNCTION
132 *
133 * INPUT
134 *
135 * OUTPUT
136 *
137 * RETURNS
138 *
139 * AUTHOR
140 *
141 * DESCRIPTION
142 *
143 * CHANGES
144 *
145 ******************************************************************************/
146
pre_init_tokenizer()147 void Parser::pre_init_tokenizer ()
148 {
149 int i;
150
151 Token.Token_File_Pos.lineno = 0;
152 Token.Token_File_Pos.offset = 0;
153 Token.Token_Col_No = 0;
154 Token.Token_String = NULL;
155 Token.Unget_Token = false;
156 Token.End_Of_File = false;
157 Token.Data = NULL;
158 Token.FileHandle = NULL;
159
160 line_count = 10;
161 token_count = 0;
162 Current_Token_Count = 0;
163 Include_File_Index = 0;
164 Echo_Indx=0;
165
166 // make sure these are NULL otherwise cleanup() will crash if we terminate early
167 Default_Texture = NULL;
168 Brace_Stack = NULL;
169
170 CS_Index = 0;
171 Skipping = false;
172 Inside_Ifdef = false;
173 Inside_MacroDef = false;
174 Cond_Stack = NULL;
175 Table_Index = -1;
176
177 Input_File = &Include_Files[0];
178 Include_Files[0].In_File = NULL ;
179
180 for(i = 0; i < LAST_TOKEN; i++)
181 {
182 Conversion_Util_Table[i] = i;
183 if(i < FLOAT_FUNCT_TOKEN)
184 Conversion_Util_Table[i] = FLOAT_FUNCT_TOKEN;
185 else
186 {
187 if(i < VECTOR_FUNCT_TOKEN)
188 Conversion_Util_Table[i] = VECTOR_FUNCT_TOKEN;
189 else
190 {
191 if(i < COLOUR_KEY_TOKEN)
192 Conversion_Util_Table[i] = COLOUR_KEY_TOKEN;
193 }
194 }
195 }
196 }
197
198
199 /*****************************************************************************
200 *
201 * FUNCTION
202 *
203 * INPUT
204 *
205 * OUTPUT
206 *
207 * RETURNS
208 *
209 * AUTHOR
210 *
211 * DESCRIPTION
212 *
213 * CHANGES
214 *
215 ******************************************************************************/
216
Terminate_Tokenizer()217 void Parser::Terminate_Tokenizer()
218 {
219 Token.FileHandle = NULL ;
220
221 while(Table_Index >= 0)
222 {
223 Destroy_Table(Table_Index--);
224 }
225
226 if(Input_File->In_File != NULL)
227 {
228 delete Input_File->In_File;
229 Input_File->In_File = NULL;
230 Got_EOF = false;
231 }
232
233 while(Include_File_Index >= 0)
234 {
235 Input_File = &Include_Files[Include_File_Index--];
236
237 if(Input_File->In_File != NULL)
238 {
239 delete Input_File->In_File;
240 Input_File->In_File = NULL;
241 Got_EOF = false;
242 }
243 }
244
245 if(Cond_Stack != NULL)
246 {
247 for(int i = 0; i <= CS_Index; i++)
248 {
249 if((Cond_Stack[i].Cond_Type == INVOKING_MACRO_COND) && (Cond_Stack[i].Macro_Same_Flag == false))
250 delete Cond_Stack[i].Macro_File;
251 }
252 POV_FREE(Cond_Stack);
253
254 Cond_Stack = NULL;
255 }
256
257 if((String != NULL) && (String != String_Fast_Buffer))
258 POV_FREE(String);
259 String=NULL;
260
261 if((String2 != NULL) && (String2 != String_Fast_Buffer))
262 POV_FREE(String2);
263 String2=NULL;
264 }
265
266
267
268 /*****************************************************************************
269 *
270 * FUNCTION
271 *
272 * INPUT
273 *
274 * OUTPUT
275 *
276 * RETURNS
277 *
278 * AUTHOR
279 *
280 * DESCRIPTION
281 *
282 * The main tokenizing routine. Set up the files and continue parsing
283 * until the end of file
284 *
285 * Read a token from the input file and store it in the Token variable.
286 * If the token is an INCLUDE token, then set the include file name and
287 * read another token.
288 *
289 * This function performs most of the work involved in tokenizing. It
290 * reads the first character of the token and decides which function to
291 * call to tokenize the rest. For simple tokens, it simply writes them
292 * out to the token buffer.
293 *
294 * CHANGES
295 *
296 ******************************************************************************/
297
Get_Token()298 void Parser::Get_Token ()
299 {
300 int c,c2;
301 int col;
302
303 if (Token.Unget_Token)
304 {
305 Token.Unget_Token = false;
306
307 return;
308 }
309
310 if (Token.End_Of_File)
311 {
312 return;
313 }
314
315 Token.Token_Id = END_OF_FILE_TOKEN;
316 Token.is_array_elem = false;
317
318 while (Token.Token_Id == END_OF_FILE_TOKEN)
319 {
320 Skip_Spaces();
321
322 Token.Token_Col_No = col = Echo_Indx;
323 c = Echo_getc();
324
325 if (c == EOF)
326 {
327 if (Input_File->R_Flag)
328 {
329 Token.Token_Id = END_OF_FILE_TOKEN;
330 Token.is_array_elem = false;
331 Token.End_Of_File = true;
332 return;
333 }
334
335 if (Include_File_Index == 0)
336 {
337 if (CS_Index !=0)
338 Error("End of file reached but #end expected.");
339
340 Token.Token_Id = END_OF_FILE_TOKEN;
341 Token.is_array_elem = false;
342
343 Token.End_Of_File = true;
344
345 return;
346 }
347
348 if (Input_File->In_File == Token.FileHandle)
349 Token.FileHandle = NULL;
350
351 delete Input_File->In_File; /* added to fix open file buildup JLN 12/91 */
352 Input_File->In_File = NULL ;
353 Got_EOF=false;
354
355 Destroy_Table(Table_Index--);
356
357 Input_File = &Include_Files[--Include_File_Index];
358 if (Token.FileHandle == NULL)
359 Token.FileHandle = Input_File->In_File;
360
361 continue;
362 }
363
364 Begin_String_Fast();
365
366 String[0] = c; /* This isn't necessary but helps debugging */
367
368 String[1] = '\0';
369
370 /*String_Index = 0;*/
371
372 switch (c)
373 {
374 case '\n':
375 break;
376
377 case '{' :
378 Write_Token (LEFT_CURLY_TOKEN, col);
379 break;
380
381 case '}' :
382 Write_Token (RIGHT_CURLY_TOKEN, col);
383 break;
384
385 case '@' :
386 Write_Token (AT_TOKEN, col);
387 break;
388
389 case '&' :
390 Write_Token (AMPERSAND_TOKEN, col);
391 break;
392
393 case '`' :
394 Write_Token (BACK_QUOTE_TOKEN, col);
395 break;
396
397 case '\\':
398 Write_Token (BACK_SLASH_TOKEN, col);
399 break;
400
401 case '|' :
402 Write_Token (BAR_TOKEN, col);
403 break;
404
405 case ':' :
406 Write_Token (COLON_TOKEN, col);
407 break;
408
409 case ',' :
410 Write_Token (COMMA_TOKEN, col);
411 break;
412
413 case '-' :
414 Write_Token (DASH_TOKEN, col);
415 break;
416
417 case '$' :
418 Write_Token (DOLLAR_TOKEN, col);
419 break;
420
421 case '=' :
422 Write_Token (EQUALS_TOKEN, col);
423 break;
424
425 case '!' :
426 c2 = Echo_getc();
427 if (c2 == (int)'=')
428 {
429 Write_Token (REL_NE_TOKEN, col);
430 }
431 else
432 {
433 Echo_ungetc(c2);
434 Write_Token (EXCLAMATION_TOKEN, col);
435 }
436 break;
437
438 case '#' :
439 Parse_Directive(true);
440 /* Write_Token (HASH_TOKEN, col);*/
441 break;
442
443 case '^' :
444 Write_Token (HAT_TOKEN, col);
445 break;
446
447 case '<' :
448 c2 = Echo_getc();
449 if (c2 == (int)'=')
450 {
451 Write_Token (REL_LE_TOKEN, col);
452 }
453 else
454 {
455 Echo_ungetc(c2);
456 Write_Token (LEFT_ANGLE_TOKEN, col);
457 }
458 break;
459
460 case '(' :
461 Write_Token (LEFT_PAREN_TOKEN, col);
462 break;
463
464 case '[' :
465 Write_Token (LEFT_SQUARE_TOKEN, col);
466 break;
467
468 case '%' :
469 Write_Token (PERCENT_TOKEN, col);
470 break;
471
472 case '+' :
473 Write_Token (PLUS_TOKEN, col);
474 break;
475
476 case '?' :
477 Write_Token (QUESTION_TOKEN, col);
478 break;
479
480 case '>' :
481 c2 = Echo_getc();
482 if (c2 == (int)'=')
483 {
484 Write_Token (REL_GE_TOKEN, col);
485 }
486 else
487 {
488 Echo_ungetc(c2);
489 Write_Token (RIGHT_ANGLE_TOKEN, col);
490 }
491 break;
492
493 case ')' :
494 Write_Token (RIGHT_PAREN_TOKEN, col);
495 break;
496
497 case ']' :
498 Write_Token (RIGHT_SQUARE_TOKEN, col);
499 break;
500
501 case ';' : /* Parser doesn't use it, so let's ignore it */
502 Write_Token (SEMI_COLON_TOKEN, col);
503 break;
504
505 case '\'':
506 Write_Token (SINGLE_QUOTE_TOKEN, col);
507 break;
508
509 /* enable C++ style commenting */
510 case '/' :
511 c2 = Echo_getc();
512 if(c2 != (int) '/' && c2 != (int) '*')
513 {
514 Echo_ungetc(c2);
515 Write_Token (SLASH_TOKEN, col);
516 break;
517 }
518 if(c2 == (int)'*')
519 {
520 Parse_C_Comments();
521 break;
522 }
523 while(c2 != (int)'\n')
524 {
525 c2=Echo_getc();
526 if(c2==EOF)
527 {
528 Echo_ungetc(c2);
529 break;
530 }
531 }
532 break;
533
534 case '*' :
535 Write_Token (STAR_TOKEN, col);
536 break;
537
538 case '~' :
539 Write_Token (TILDE_TOKEN, col);
540 break;
541
542 case '"' :
543 Parse_String_Literal ();
544 break;
545
546 case '0':
547 case '1':
548 case '2':
549 case '3':
550 case '4':
551 case '5':
552 case '6':
553 case '7':
554 case '8':
555 case '9':
556 case '.':
557 Echo_ungetc(c);
558 if (Read_Float () != true)
559 return;
560 break;
561
562 case 'a':
563 case 'b':
564 case 'c':
565 case 'd':
566 case 'e':
567 case 'f':
568 case 'g':
569 case 'h':
570 case 'i':
571 case 'j':
572 case 'k':
573 case 'l':
574 case 'm':
575 case 'n':
576 case 'o':
577 case 'p':
578 case 'q':
579 case 'r':
580 case 's':
581 case 't':
582 case 'u':
583 case 'v':
584 case 'w':
585 case 'x':
586 case 'y':
587 case 'z':
588
589 case 'A':
590 case 'B':
591 case 'C':
592 case 'D':
593 case 'E':
594 case 'F':
595 case 'G':
596 case 'H':
597 case 'I':
598 case 'J':
599 case 'K':
600 case 'L':
601 case 'M':
602 case 'N':
603 case 'O':
604 case 'P':
605 case 'Q':
606 case 'R':
607 case 'S':
608 case 'T':
609 case 'U':
610 case 'V':
611 case 'W':
612 case 'X':
613 case 'Y':
614 case 'Z':
615 case '_':
616 Echo_ungetc(c);
617 Read_Symbol ();
618 break;
619 case '\t':
620 case '\r':
621 case '\032': /* Control Z - EOF on many systems */
622 case '\0':
623 break;
624
625 default:
626 Error("Illegal character in input file, value is %02x.", c);
627 break;
628 }
629 }
630
631 Current_Token_Count++;
632 token_count++;
633
634 if(token_count > TOKEN_OVERFLOW_RESET_COUNT) // NEVER, ever change the operator here! Other code using token_count depends on it!!! [trf]
635 {
636 token_count = 0;
637
638 if((ElapsedRealTime() - last_progress) > 1000) // update progress at most every second
639 {
640 POVMS_Object obj(kPOVObjectClass_ParserProgress);
641 obj.SetLong(kPOVAttrib_RealTime, ElapsedRealTime());
642 obj.SetLong(kPOVAttrib_CurrentTokenCount, Current_Token_Count);
643 RenderBackend::SendSceneOutput(sceneData->sceneId, sceneData->frontendAddress, kPOVMsgIdent_Progress, obj);
644
645 Cooperate();
646
647 last_progress = ElapsedRealTime();
648 }
649 }
650 }
651
652
653
654 /*****************************************************************************
655 *
656 * FUNCTION
657 *
658 * INPUT
659 *
660 * OUTPUT
661 *
662 * RETURNS
663 *
664 * AUTHOR
665 *
666 * DESCRIPTION
667 *
668 * Mark that the token has been put back into the input stream. The next
669 * call to Get_Token will return the last-read token instead of reading a
670 * new one from the file.
671 *
672 * CHANGES
673 *
674 ******************************************************************************/
675
Unget_Token()676 void Parser::Unget_Token ()
677 {
678 Token.Unget_Token = true;
679 }
680
681
682
683 /*****************************************************************************
684 *
685 * FUNCTION
686 *
687 * INPUT
688 *
689 * OUTPUT
690 *
691 * RETURNS
692 *
693 * AUTHOR
694 *
695 * DESCRIPTION
696 *
697 * Skip over spaces in the input file.
698 *
699 * CHANGES
700 *
701 ******************************************************************************/
702
Skip_Spaces()703 bool Parser::Skip_Spaces()
704 {
705 int c;
706
707 while(true)
708 {
709 c = Echo_getc();
710
711 if (c == EOF)
712 return false;
713
714 if(!(isspace(c)))
715 break;
716 }
717
718 Echo_ungetc(c);
719
720 return true;
721 }
722
723
724
725 /*****************************************************************************
726 *
727 * FUNCTION
728 *
729 * INPUT
730 *
731 * OUTPUT
732 *
733 * RETURNS
734 *
735 * AUTHOR
736 *
737 * DESCRIPTION
738 *
739 * C style comments with asterik and slash - CdW 8/91.
740 *
741 * CHANGES
742 *
743 ******************************************************************************/
744
Parse_C_Comments()745 int Parser::Parse_C_Comments()
746 {
747 int c, c2;
748 bool End_Of_Comment = false;
749
750 while(!End_Of_Comment)
751 {
752 c = Echo_getc();
753
754 if(c == EOF)
755 Error("No */ closing comment found.");
756
757 if(c == (int) '*')
758 {
759 c2 = Echo_getc();
760
761 if(c2 != (int) '/')
762 Echo_ungetc(c2);
763 else
764 End_Of_Comment = true;
765 }
766
767 /* Check for and handle nested comments */
768
769 if(c == (int) '/')
770 {
771 c2 = Echo_getc();
772
773 if(c2 != (int) '*')
774 Echo_ungetc(c2);
775 else
776 Parse_C_Comments();
777 }
778 }
779
780 return true;
781 }
782
783
784
785 /* The following routines make it easier to handle strings. They stuff
786 characters into a string buffer one at a time making all the proper
787 range checks. Call Begin_String to start, Stuff_Character to put
788 characters in, and End_String to finish. The String variable contains
789 the final string. */
790
791 /*****************************************************************************
792 *
793 * FUNCTION
794 *
795 * INPUT
796 *
797 * OUTPUT
798 *
799 * RETURNS
800 *
801 * AUTHOR
802 *
803 * DESCRIPTION
804 *
805 * CHANGES
806 *
807 ******************************************************************************/
808
Begin_String()809 inline void Parser::Begin_String()
810 {
811 if((String != NULL) && (String != String_Fast_Buffer))
812 POV_FREE(String);
813
814 String = (char *)POV_MALLOC(256, "C String");
815 String_Buffer_Free = 256;
816 String_Index = 0;
817 }
818
819
820
821 /*****************************************************************************
822 *
823 * FUNCTION
824 *
825 * INPUT
826 *
827 * OUTPUT
828 *
829 * RETURNS
830 *
831 * AUTHOR
832 *
833 * DESCRIPTION
834 *
835 * CHANGES
836 *
837 ******************************************************************************/
838
Stuff_Character(int chr)839 inline void Parser::Stuff_Character(int chr)
840 {
841 if(String_Buffer_Free <= 0)
842 {
843 Error("String too long.");
844 // This caused too many problems with buffer overflows [trf]
845 // String = (char *)POV_REALLOC(String, String_Index + 256, "String Literal Buffer");
846 // String_Buffer_Free += 256;
847 }
848
849 String[String_Index] = chr;
850 String_Buffer_Free--;
851 String_Index++;
852 }
853
854
855
856 /*****************************************************************************
857 *
858 * FUNCTION
859 *
860 * INPUT
861 *
862 * OUTPUT
863 *
864 * RETURNS
865 *
866 * AUTHOR
867 *
868 * DESCRIPTION
869 *
870 * CHANGES
871 *
872 ******************************************************************************/
873
End_String()874 inline void Parser::End_String()
875 {
876 Stuff_Character(0);
877
878 if(String_Buffer_Free > 0)
879 String = (char *)POV_REALLOC(String, String_Index, "String Literal Buffer");
880
881 String_Buffer_Free = 0;
882 }
883
884
885
886 /*****************************************************************************
887 *
888 * FUNCTION
889 *
890 * INPUT
891 *
892 * OUTPUT
893 *
894 * RETURNS
895 *
896 * AUTHOR
897 *
898 * DESCRIPTION
899 *
900 * CHANGES
901 *
902 ******************************************************************************/
903
Begin_String_Fast()904 inline void Parser::Begin_String_Fast()
905 {
906 if((String != NULL) && (String != String_Fast_Buffer))
907 POV_FREE(String);
908
909 String = String_Fast_Buffer;
910 String_Index = 0;
911 }
912
913
914
915 /*****************************************************************************
916 *
917 * FUNCTION
918 *
919 * INPUT
920 *
921 * OUTPUT
922 *
923 * RETURNS
924 *
925 * AUTHOR
926 *
927 * DESCRIPTION
928 *
929 * CHANGES
930 *
931 ******************************************************************************/
932
Stuff_Character_Fast(int chr)933 inline void Parser::Stuff_Character_Fast(int chr)
934 {
935 String[String_Index & MAX_STRING_LEN_MASK] = chr;
936 String_Index++;
937 }
938
939
940
941 /*****************************************************************************
942 *
943 * FUNCTION
944 *
945 * INPUT
946 *
947 * OUTPUT
948 *
949 * RETURNS
950 *
951 * AUTHOR
952 *
953 * DESCRIPTION
954 *
955 * CHANGES
956 *
957 ******************************************************************************/
958
End_String_Fast()959 inline void Parser::End_String_Fast()
960 {
961 Stuff_Character_Fast(0);
962
963 String_Index--; // Stuff_Character_Fast incremented this
964
965 if(String_Index != (String_Index & MAX_STRING_LEN_MASK))
966 Error("String too long.");
967 }
968
969
970
971 /*****************************************************************************
972 *
973 * FUNCTION
974 *
975 * INPUT
976 *
977 * OUTPUT
978 *
979 * RETURNS
980 *
981 * AUTHOR
982 *
983 * DESCRIPTION
984 *
985 * Parse a string from the input file into a token.
986 *
987 * CHANGES
988 *
989 ******************************************************************************/
990
Parse_String_Literal()991 void Parser::Parse_String_Literal()
992 {
993 int c;
994 int col = Echo_Indx;
995
996 Begin_String();
997
998 while(true)
999 {
1000 c = Echo_getc();
1001
1002 if(c == EOF)
1003 Error("No end quote for string.");
1004
1005 if(c == '\\')
1006 {
1007 switch(c = Echo_getc())
1008 {
1009 case '\n':
1010 case '\r':
1011 Error("Unterminated string literal.");
1012 break;
1013 case '\"':
1014 c = '\"';
1015 break;
1016 case EOF:
1017 Error("No end quote for string.");
1018 break;
1019 default:
1020 Stuff_Character('\\');
1021 }
1022
1023 Stuff_Character(c);
1024 }
1025 else
1026 {
1027 if(c != (int)'"')
1028 Stuff_Character(c);
1029 else
1030 break;
1031 }
1032 }
1033
1034 End_String();
1035
1036 Write_Token(STRING_LITERAL_TOKEN, col);
1037
1038 Token.Token_String = String;
1039 }
1040
1041
1042
1043 /*****************************************************************************
1044 *
1045 * FUNCTION
1046 *
1047 * INPUT
1048 *
1049 * OUTPUT
1050 *
1051 * RETURNS
1052 *
1053 * AUTHOR
1054 *
1055 * DESCRIPTION
1056 *
1057 * Read a float from the input file and tokenize it as one token. The phase
1058 * variable is 0 for the first character, 1 for all subsequent characters
1059 * up to the decimal point, 2 for all characters after the decimal
1060 * point, 3 for the E+/- and 4 for the exponent. This helps to insure
1061 * that the number is formatted properly. E format added 9/91 CEY
1062 *
1063 * CHANGES
1064 *
1065 ******************************************************************************/
1066
Read_Float()1067 bool Parser::Read_Float()
1068 {
1069 int c, Phase;
1070 bool Finished;
1071 int col = Echo_Indx;
1072
1073 Finished = false;
1074
1075 Phase = 0;
1076
1077 Begin_String_Fast();
1078
1079 while (!Finished)
1080 {
1081 c = Echo_getc();
1082
1083 if (c == EOF)
1084 {
1085 Error ("Unexpected end of file.");
1086 }
1087
1088 if (Phase > 1 && c == '.')
1089 {
1090 Error ("Unexpected additional '.' in floating-point number");
1091 }
1092
1093 switch (Phase)
1094 {
1095 case 0:
1096
1097 Phase = 1;
1098
1099 if (isdigit(c))
1100 {
1101 Stuff_Character_Fast(c);
1102 }
1103 else
1104 {
1105 if (c == '.')
1106 {
1107 c = Echo_getc();
1108
1109 if (c == EOF)
1110 {
1111 Error ("Unexpected end of file");
1112 }
1113
1114 if (isdigit(c))
1115 {
1116 Stuff_Character_Fast('0');
1117 Stuff_Character_Fast('.');
1118 Stuff_Character_Fast(c);
1119
1120 Phase = 2;
1121 }
1122 else
1123 {
1124 Echo_ungetc(c);
1125
1126 Write_Token (PERIOD_TOKEN, col);
1127
1128 return(true);
1129 }
1130 }
1131 else
1132 {
1133 Error ("Invalid decimal number");
1134 }
1135 }
1136
1137 break;
1138
1139 case 1:
1140 if (isdigit(c))
1141 {
1142 Stuff_Character_Fast(c);
1143 }
1144 else
1145 {
1146 if (c == (int) '.')
1147 {
1148 Stuff_Character_Fast(c); Phase = 2;
1149 }
1150 else
1151 {
1152 if ((c == 'e') || (c == 'E'))
1153 {
1154 Stuff_Character_Fast(c); Phase = 3;
1155 }
1156 else
1157 {
1158 Finished = true;
1159 }
1160 }
1161 }
1162
1163 break;
1164
1165 case 2:
1166
1167 if (isdigit(c))
1168 {
1169 Stuff_Character_Fast(c);
1170 }
1171 else
1172 {
1173 if ((c == 'e') || (c == 'E'))
1174 {
1175 Stuff_Character_Fast(c); Phase = 3;
1176 }
1177 else
1178 {
1179 Finished = true;
1180 }
1181 }
1182
1183 break;
1184
1185 case 3:
1186
1187 if (isdigit(c) || (c == '+') || (c == '-'))
1188 {
1189 Stuff_Character_Fast(c); Phase = 4;
1190 }
1191 else
1192 {
1193 Finished = true;
1194 }
1195
1196 break;
1197
1198 case 4:
1199
1200 if (isdigit(c))
1201 {
1202 Stuff_Character_Fast(c);
1203 }
1204 else
1205 {
1206 Finished = true;
1207 }
1208
1209 break;
1210 }
1211 }
1212
1213 Echo_ungetc(c);
1214
1215 End_String_Fast();
1216
1217 Write_Token (FLOAT_TOKEN, col);
1218
1219 if (sscanf (String, DBL_FORMAT_STRING, &Token.Token_Float) == 0)
1220 {
1221 return (false);
1222 }
1223
1224 return (true);
1225 }
1226
1227
1228
1229 /*****************************************************************************
1230 *
1231 * FUNCTION
1232 *
1233 * INPUT
1234 *
1235 * OUTPUT
1236 *
1237 * RETURNS
1238 *
1239 * AUTHOR
1240 *
1241 * DESCRIPTION
1242 *
1243 * Read in a symbol from the input file. Check to see if it is a reserved
1244 * word. If it is, write out the appropriate token. Otherwise, write the
1245 * symbol out to the symbol table and write out an IDENTIFIER token. An
1246 * identifier token is a token whose token number is greater than the
1247 * highest reserved word.
1248 *
1249 * CHANGES
1250 *
1251 ******************************************************************************/
1252
Read_Symbol()1253 void Parser::Read_Symbol()
1254 {
1255 int c;
1256 int Local_Index,i,j,k;
1257 POV_ARRAY *a;
1258 SYM_ENTRY *Temp_Entry;
1259 POV_PARAM *Par;
1260 DBL val;
1261
1262 Begin_String_Fast();
1263
1264 while (true)
1265 {
1266 c = Echo_getc();
1267
1268 if (c == EOF)
1269 {
1270 Error ("Unexpected end of file.");
1271 }
1272
1273 if (isalpha(c) || isdigit(c) || c == (int) '_')
1274 {
1275 Stuff_Character_Fast(c);
1276 }
1277 else
1278 {
1279 Echo_ungetc(c);
1280
1281 break;
1282 }
1283 }
1284
1285 End_String_Fast();
1286
1287 if (Inside_Ifdef)
1288 {
1289 Token.Token_Id = IDENTIFIER_TOKEN;
1290 Token.is_array_elem = false;
1291
1292 return;
1293 }
1294
1295 /* If its a reserved keyword, write it and return */
1296 if ( (Temp_Entry = Find_Symbol(0,String)) != NULL)
1297 {
1298 Write_Token (Temp_Entry->Token_Number, Token.Token_Col_No);
1299 return;
1300 }
1301
1302 if (!Skipping)
1303 {
1304 /* Search tables from newest to oldest */
1305 for (Local_Index=Table_Index; Local_Index > 0; Local_Index--)
1306 {
1307 /* See if it's a previously declared identifier. */
1308 if ((Temp_Entry = Find_Symbol(Local_Index,String)) != NULL)
1309 {
1310 if ((Temp_Entry->Flags & (TF_DEPRECATED | TF_DEPRECATED_SHOWN)) == TF_DEPRECATED)
1311 {
1312 if ((Temp_Entry->Flags & TF_DEPRECATED_ONCE) != 0)
1313 Temp_Entry->Flags |= TF_DEPRECATED_SHOWN;
1314 Warning(0, "%s", Temp_Entry->Deprecation_Message);
1315 }
1316
1317 if (Temp_Entry->Token_Number==MACRO_ID_TOKEN)
1318 {
1319 Token.Data = Temp_Entry->Data;
1320 if (Ok_To_Declare)
1321 {
1322 Invoke_Macro();
1323 }
1324 else
1325 {
1326 Token.Token_Id=MACRO_ID_TOKEN;
1327 Token.is_array_elem = false;
1328 Token.NumberPtr = &(Temp_Entry->Token_Number);
1329 Token.DataPtr = &(Temp_Entry->Data);
1330 Write_Token (Token.Token_Id, Token.Token_Col_No);
1331
1332 Token.Table_Index = Local_Index;
1333 }
1334 return;
1335 }
1336
1337 Token.Token_Id = Temp_Entry->Token_Number;
1338 Token.is_array_elem = false;
1339 Token.NumberPtr = &(Temp_Entry->Token_Number);
1340 Token.DataPtr = &(Temp_Entry->Data);
1341
1342 while ((Token.Token_Id==PARAMETER_ID_TOKEN) ||
1343 (Token.Token_Id==ARRAY_ID_TOKEN))
1344 {
1345 if (Token.Token_Id==ARRAY_ID_TOKEN)
1346 {
1347 Skip_Spaces();
1348 c = Echo_getc();
1349 Echo_ungetc(c);
1350
1351 if (c!='[')
1352 {
1353 break;
1354 }
1355
1356 a = (POV_ARRAY *)(*(Token.DataPtr));
1357 j = 0;
1358
1359 for (i=0; i <= a->Dims; i++)
1360 {
1361 GET(LEFT_SQUARE_TOKEN)
1362 val=Parse_Float();
1363 k=(int)(val + EPSILON);
1364
1365 if ((k < 0) || (val < -EPSILON))
1366 {
1367 Error("Negative subscript");
1368 }
1369
1370 if (k >= a->Sizes[i])
1371 {
1372 Error("Array subscript out of range");
1373 }
1374 j += k * a->Mags[i];
1375 GET(RIGHT_SQUARE_TOKEN)
1376 }
1377
1378 Token.DataPtr = &(a->DataPtrs[j]);
1379 Token.NumberPtr = &(a->Type);
1380 Token.Token_Id = a->Type;
1381 Token.is_array_elem = true;
1382 if (!LValue_Ok)
1383 {
1384 if (*Token.DataPtr == NULL)
1385 Error("Attempt to access uninitialized array element.");
1386 }
1387 }
1388 else
1389 {
1390 Par = (POV_PARAM *)(Temp_Entry->Data);
1391 Token.Token_Id = *(Par->NumberPtr);
1392 Token.is_array_elem = false;
1393 Token.NumberPtr = Par->NumberPtr;
1394 Token.DataPtr = Par->DataPtr;
1395 }
1396 }
1397
1398 Write_Token (Token.Token_Id, Token.Token_Col_No);
1399
1400 Token.Data = *(Token.DataPtr);
1401 Token.Table_Index = Local_Index;
1402 return;
1403 }
1404 }
1405 }
1406
1407 Write_Token(IDENTIFIER_TOKEN, Token.Token_Col_No);
1408 }
1409
Write_Token(TOKEN Token_Id,int col)1410 inline void Parser::Write_Token (TOKEN Token_Id, int col)
1411 {
1412 Token.Token_File_Pos = Input_File->In_File->tellg();
1413 Token.Token_Col_No = col;
1414 Token.FileHandle = Input_File->In_File;
1415 Token.Token_String = String;
1416 Token.Data = NULL;
1417 Token.Token_Id = Conversion_Util_Table[Token_Id];
1418 Token.Function_Id = Token_Id;
1419 }
1420
1421
1422 /*****************************************************************************
1423 *
1424 * FUNCTION
1425 *
1426 * INPUT
1427 *
1428 * OUTPUT
1429 *
1430 * RETURNS
1431 *
1432 * AUTHOR
1433 *
1434 * DESCRIPTION
1435 *
1436 * CHANGES
1437 *
1438 ******************************************************************************/
1439
Get_Token_String(TOKEN Token_Id)1440 const char *Parser::Get_Token_String (TOKEN Token_Id)
1441 {
1442 int i;
1443
1444 for (i = 0 ; i < LAST_TOKEN ; i++)
1445 if (Reserved_Words[i].Token_Number == Token_Id)
1446 return (Reserved_Words[i].Token_Name);
1447 return ("");
1448 }
1449
1450
1451
1452
1453 /*****************************************************************************
1454 *
1455 * FUNCTION
1456 *
1457 * INPUT
1458 *
1459 * OUTPUT
1460 *
1461 * RETURNS
1462 *
1463 * AUTHOR
1464 *
1465 * DESCRIPTION
1466 *
1467 * Return a list of keywords seperated with a '\n'. The last keyword does not
1468 * have a LF after it. The caller is responsible for freeing the memory. This
1469 * function is intended to be used by GUI implementations that need a keyword
1470 * list for syntax-coloring edit windows.
1471 *
1472 * CHANGES
1473 *
1474 ******************************************************************************/
1475
Get_Reserved_Words(const char * additional_words)1476 char *Parser::Get_Reserved_Words (const char *additional_words)
1477 {
1478 int length = 0 ;
1479 int i ;
1480
1481 for (i = 0; i < LAST_TOKEN; i++)
1482 {
1483 if (!isalpha (Reserved_Words [i].Token_Name [0]))
1484 continue ;
1485 if (strchr (Reserved_Words [i].Token_Name, ' ') != NULL)
1486 continue ;
1487 length += (int)strlen (Reserved_Words[i].Token_Name) + 1 ;
1488 }
1489
1490 length += (int)strlen (additional_words) ;
1491
1492 char *result = (char *) POV_MALLOC (++length, "Keyword List") ;
1493 strcpy (result, additional_words) ;
1494 char *s = result + strlen (additional_words) ;
1495
1496 for (i = 0 ; i < LAST_TOKEN ; i++)
1497 {
1498 if (!isalpha (Reserved_Words [i].Token_Name [0]))
1499 continue ;
1500 if (strchr (Reserved_Words [i].Token_Name, ' ') != NULL)
1501 continue ;
1502 s += sprintf (s, "%s\n", Reserved_Words[i].Token_Name) ;
1503 }
1504 *--s = '\0' ;
1505
1506 return (result) ;
1507 }
1508
1509
1510 /*****************************************************************************
1511 *
1512 * FUNCTION
1513 *
1514 * INPUT
1515 *
1516 * OUTPUT
1517 *
1518 * RETURNS
1519 *
1520 * AUTHOR
1521 *
1522 * DESCRIPTION
1523 *
1524 * CHANGES
1525 *
1526 ******************************************************************************/
1527
Echo_getc()1528 int Parser::Echo_getc()
1529 {
1530 int c;
1531
1532 if((Input_File == NULL) || (Input_File->In_File == NULL) || (c = Input_File->In_File->getchar()) == EOF)
1533 {
1534 if (Got_EOF)
1535 return EOF;
1536 Got_EOF = true ;
1537 Echo_Indx = 0 ;
1538 return ('\n') ;
1539 }
1540
1541 Echo_Indx++;
1542 if(c == '\n')
1543 Echo_Indx = 0;
1544
1545 return c;
1546 }
1547
1548
1549
1550 /*****************************************************************************
1551 *
1552 * FUNCTION
1553 *
1554 * INPUT
1555 *
1556 * OUTPUT
1557 *
1558 * RETURNS
1559 *
1560 * AUTHOR
1561 *
1562 * DESCRIPTION
1563 *
1564 * CHANGES
1565 *
1566 ******************************************************************************/
1567
Echo_ungetc(int c)1568 void Parser::Echo_ungetc(int c)
1569 {
1570 if(Echo_Indx > 0)
1571 Echo_Indx--;
1572
1573 Input_File->In_File->ungetchar(c);
1574 }
1575
1576
1577 /*****************************************************************************
1578 *
1579 * FUNCTION
1580 *
1581 * INPUT
1582 *
1583 * OUTPUT
1584 *
1585 * RETURNS
1586 *
1587 * AUTHOR
1588 *
1589 * DESCRIPTION
1590 *
1591 * CHANGES
1592 *
1593 ******************************************************************************/
1594
Where_Error(POVMSObjectPtr msg)1595 void Parser::Where_Error(POVMSObjectPtr msg)
1596 {
1597 // return if no filename is specified
1598 if(Token.FileHandle == NULL)
1599 return;
1600
1601 (void)POVMSUtil_SetUCS2String(msg, kPOVAttrib_FileName, Token.FileHandle->name());
1602 (void)POVMSUtil_SetString(msg, kPOVAttrib_TokenName, Token.Token_String);
1603 (void)POVMSUtil_SetLong(msg, kPOVAttrib_Line, Token.Token_File_Pos.lineno);
1604 (void)POVMSUtil_SetInt(msg, kPOVAttrib_Column, Token.Token_Col_No);
1605 if(Token.FileHandle != NULL)
1606 (void)POVMSUtil_SetLong(msg, kPOVAttrib_FilePosition, Token.FileHandle->tellg().offset);
1607 }
1608
1609
1610 /*****************************************************************************
1611 *
1612 * FUNCTION
1613 *
1614 * INPUT
1615 *
1616 * OUTPUT
1617 *
1618 * RETURNS
1619 *
1620 * AUTHOR
1621 *
1622 * DESCRIPTION
1623 *
1624 * CHANGES
1625 *
1626 ******************************************************************************/
1627
Where_Warning(POVMSObjectPtr msg)1628 void Parser::Where_Warning(POVMSObjectPtr msg)
1629 {
1630 // return if no filename is specified
1631 if(Token.FileHandle == NULL)
1632 return;
1633
1634 (void)POVMSUtil_SetUCS2String(msg, kPOVAttrib_FileName, Token.FileHandle->name());
1635 (void)POVMSUtil_SetString(msg, kPOVAttrib_TokenName, Token.Token_String);
1636 (void)POVMSUtil_SetLong(msg, kPOVAttrib_Line, Token.Token_File_Pos.lineno);
1637 (void)POVMSUtil_SetInt(msg, kPOVAttrib_Column, Token.Token_Col_No);
1638 if(Token.FileHandle != NULL)
1639 (void)POVMSUtil_SetLong(msg, kPOVAttrib_FilePosition, Token.FileHandle->tellg().offset);
1640 }
1641
1642
1643
1644 /*****************************************************************************
1645 *
1646 * FUNCTION Parse_Directive
1647 *
1648 * INPUT
1649 *
1650 * OUTPUT
1651 *
1652 * RETURNS
1653 *
1654 * AUTHOR Chris Young
1655 *
1656 * DESCRIPTION
1657 *
1658 * CHANGES
1659 *
1660 ******************************************************************************/
1661
Parse_Directive(int After_Hash)1662 void Parser::Parse_Directive(int After_Hash)
1663 {
1664 DBL Value, Value2;
1665 int Flag;
1666 char *ts;
1667 POV_MACRO *PMac=NULL;
1668 COND_TYPE Curr_Type = Cond_Stack[CS_Index].Cond_Type;
1669 POV_LONG Hash_Loc = Input_File->In_File->tellg().offset;
1670
1671 if (Curr_Type == INVOKING_MACRO_COND)
1672 {
1673 if (Cond_Stack[CS_Index].PMac->Macro_End==Hash_Loc)
1674 {
1675 Return_From_Macro();
1676 if (--CS_Index < 0)
1677 {
1678 Error("Mis-matched '#end'.");
1679 }
1680 Token.Token_Id = END_OF_FILE_TOKEN;
1681 Token.is_array_elem = false;
1682
1683 return;
1684 }
1685 }
1686
1687 if (!Ok_To_Declare)
1688 {
1689 if (After_Hash)
1690 {
1691 Token.Token_Id=HASH_TOKEN;
1692 Token.is_array_elem = false;
1693 }
1694 Token.Unget_Token = false;
1695
1696 return;
1697 }
1698
1699 EXPECT
1700 CASE(IFDEF_TOKEN)
1701 Inc_CS_Index();
1702
1703 if (Skipping)
1704 {
1705 Cond_Stack[CS_Index].Cond_Type = SKIP_TIL_END_COND;
1706 Skip_Tokens(SKIP_TIL_END_COND);
1707 }
1708 else
1709 {
1710 if (Parse_Ifdef_Param())
1711 {
1712 Cond_Stack[CS_Index].Cond_Type=IF_TRUE_COND;
1713 }
1714 else
1715 {
1716 Cond_Stack[CS_Index].Cond_Type=IF_FALSE_COND;
1717 Skip_Tokens(IF_FALSE_COND);
1718 }
1719 }
1720 EXIT
1721 END_CASE
1722
1723 CASE(IFNDEF_TOKEN)
1724 Inc_CS_Index();
1725
1726 if (Skipping)
1727 {
1728 Cond_Stack[CS_Index].Cond_Type = SKIP_TIL_END_COND;
1729 Skip_Tokens(SKIP_TIL_END_COND);
1730 }
1731 else
1732 {
1733 if (Parse_Ifdef_Param())
1734 {
1735 Cond_Stack[CS_Index].Cond_Type=IF_FALSE_COND;
1736 Skip_Tokens(IF_FALSE_COND);
1737 }
1738 else
1739 {
1740 Cond_Stack[CS_Index].Cond_Type=IF_TRUE_COND;
1741 }
1742 }
1743 EXIT
1744 END_CASE
1745
1746 CASE(IF_TOKEN)
1747 Inc_CS_Index();
1748
1749 if (Skipping)
1750 {
1751 Cond_Stack[CS_Index].Cond_Type = SKIP_TIL_END_COND;
1752 Skip_Tokens(SKIP_TIL_END_COND);
1753 }
1754 else
1755 {
1756 Value=Parse_Cond_Param();
1757
1758 if (fabs(Value)>EPSILON)
1759 {
1760 Cond_Stack[CS_Index].Cond_Type=IF_TRUE_COND;
1761 }
1762 else
1763 {
1764 Cond_Stack[CS_Index].Cond_Type=IF_FALSE_COND;
1765 Skip_Tokens(IF_FALSE_COND);
1766 }
1767 }
1768 EXIT
1769 END_CASE
1770
1771 CASE(WHILE_TOKEN)
1772 Inc_CS_Index();
1773
1774 if (Skipping)
1775 {
1776 Cond_Stack[CS_Index].Cond_Type = SKIP_TIL_END_COND;
1777 Skip_Tokens(SKIP_TIL_END_COND);
1778 }
1779 else
1780 {
1781 Cond_Stack[CS_Index].Loop_File = Input_File->In_File;
1782 Cond_Stack[CS_Index].File_Pos = Input_File->In_File->tellg();
1783
1784 Value=Parse_Cond_Param();
1785
1786 if (fabs(Value)>EPSILON)
1787 {
1788 Cond_Stack[CS_Index].Cond_Type = WHILE_COND;
1789 }
1790 else
1791 {
1792 Cond_Stack[CS_Index].Cond_Type = SKIP_TIL_END_COND;
1793 Skip_Tokens(SKIP_TIL_END_COND);
1794 }
1795 }
1796 EXIT
1797 END_CASE
1798
1799 CASE(FOR_TOKEN)
1800 Inc_CS_Index();
1801
1802 if (Skipping)
1803 {
1804 Cond_Stack[CS_Index].Cond_Type = SKIP_TIL_END_COND;
1805 Skip_Tokens(SKIP_TIL_END_COND);
1806 }
1807 else
1808 {
1809 char* Identifier = NULL;
1810 DBL End, Step;
1811 if (Parse_For_Param (&Identifier, &End, &Step))
1812 {
1813 // execute loop
1814 Cond_Stack[CS_Index].Cond_Type = FOR_COND;
1815 Cond_Stack[CS_Index].Loop_File = Input_File->In_File;
1816 Cond_Stack[CS_Index].File_Pos = Input_File->In_File->tellg();
1817 Cond_Stack[CS_Index].Loop_Identifier = Identifier;
1818 Cond_Stack[CS_Index].For_Loop_End = End;
1819 Cond_Stack[CS_Index].For_Loop_Step = Step;
1820 }
1821 else
1822 {
1823 // terminate loop
1824 Cond_Stack[CS_Index].Cond_Type = SKIP_TIL_END_COND;
1825 Skip_Tokens(SKIP_TIL_END_COND);
1826 }
1827 }
1828 EXIT
1829 END_CASE
1830
1831 CASE(ELSE_TOKEN)
1832 switch (Curr_Type)
1833 {
1834 case IF_TRUE_COND:
1835 Cond_Stack[CS_Index].Cond_Type = SKIP_TIL_END_COND;
1836 Skip_Tokens(SKIP_TIL_END_COND);
1837 break;
1838
1839 case IF_FALSE_COND:
1840 Cond_Stack[CS_Index].Cond_Type = ELSE_COND;
1841 Token.Token_Id=HASH_TOKEN; /*insures Skip_Token takes notice*/
1842 Token.is_array_elem = false;
1843 UNGET
1844 break;
1845
1846 case CASE_TRUE_COND:
1847 case SKIP_TIL_END_COND:
1848 break;
1849
1850 case CASE_FALSE_COND:
1851 Cond_Stack[CS_Index].Cond_Type = CASE_TRUE_COND;
1852 if (Skipping)
1853 {
1854 Token.Token_Id=HASH_TOKEN; /*insures Skip_Token takes notice*/
1855 Token.is_array_elem = false;
1856 UNGET
1857 }
1858 break;
1859
1860 default:
1861 Error("Mis-matched '#else'.");
1862 }
1863 EXIT
1864 END_CASE
1865
1866 CASE(ELSEIF_TOKEN)
1867 switch (Curr_Type)
1868 {
1869 case IF_TRUE_COND:
1870 Cond_Stack[CS_Index].Cond_Type = SKIP_TIL_END_COND;
1871 Skip_Tokens(SKIP_TIL_END_COND);
1872 break;
1873
1874 case IF_FALSE_COND:
1875 Value=Parse_Cond_Param();
1876 if (fabs(Value)>EPSILON)
1877 {
1878 Cond_Stack[CS_Index].Cond_Type=IF_TRUE_COND;
1879 Token.Token_Id=HASH_TOKEN; /*insures Skip_Token takes notice*/
1880 Token.is_array_elem = false;
1881 UNGET
1882 }
1883 else
1884 {
1885 // nothing to do, we're staying in IF_FALSE_COND state.
1886 }
1887 break;
1888
1889 case SKIP_TIL_END_COND:
1890 break;
1891
1892 default:
1893 Error("Mis-matched '#elseif'.");
1894 }
1895 EXIT
1896 END_CASE
1897
1898 CASE(SWITCH_TOKEN)
1899 Inc_CS_Index();
1900
1901 if (Skipping)
1902 {
1903 Cond_Stack[CS_Index].Cond_Type = SKIP_TIL_END_COND;
1904 Skip_Tokens(SKIP_TIL_END_COND);
1905 }
1906 else
1907 {
1908 Cond_Stack[CS_Index].Switch_Value=Parse_Cond_Param();
1909 Cond_Stack[CS_Index].Cond_Type=SWITCH_COND;
1910 Cond_Stack[CS_Index].Switch_Case_Ok_Flag=false;
1911 EXPECT
1912 // NOTE: We actually expect a "#case" or "#range" here; however, this will trigger a nested call
1913 // to Parse_Directive, so we'll encounter that CASE_TOKEN or RANGE_TOKEN here only by courtesy of the
1914 // respective handler, which will UNGET the token and inform us via the Switch_Case_Ok_Flag
1915 // that the CASE_TOKEN or RANGE_TOKEN we encounter here was properly preceded with a hash ("#").
1916 CASE2(CASE_TOKEN,RANGE_TOKEN)
1917 if (!Cond_Stack[CS_Index].Switch_Case_Ok_Flag)
1918 Error("#switch not followed by #case or #range.");
1919
1920 if (Token.Token_Id==CASE_TOKEN)
1921 {
1922 Value=Parse_Cond_Param();
1923 Flag = (fabs(Value-Cond_Stack[CS_Index].Switch_Value)<EPSILON);
1924 }
1925 else
1926 {
1927 Parse_Cond_Param2(&Value,&Value2);
1928 Flag = ((Cond_Stack[CS_Index].Switch_Value >= Value) &&
1929 (Cond_Stack[CS_Index].Switch_Value <= Value2));
1930 }
1931
1932 if(Flag)
1933 {
1934 Cond_Stack[CS_Index].Cond_Type=CASE_TRUE_COND;
1935 }
1936 else
1937 {
1938 Cond_Stack[CS_Index].Cond_Type=CASE_FALSE_COND;
1939 Skip_Tokens(CASE_FALSE_COND);
1940 }
1941 EXIT
1942 END_CASE
1943
1944 OTHERWISE
1945 Error("#switch not followed by #case or #range.");
1946 END_CASE
1947 END_EXPECT
1948 }
1949 EXIT
1950 END_CASE
1951
1952 CASE(BREAK_TOKEN)
1953 if (!Skipping)
1954 Break();
1955 EXIT
1956 END_CASE
1957
1958 CASE2(CASE_TOKEN,RANGE_TOKEN)
1959 switch(Curr_Type)
1960 {
1961 case CASE_TRUE_COND:
1962 case CASE_FALSE_COND:
1963 if (Token.Token_Id==CASE_TOKEN)
1964 {
1965 Value=Parse_Cond_Param();
1966 Flag = (fabs(Value-Cond_Stack[CS_Index].Switch_Value)<EPSILON);
1967 }
1968 else
1969 {
1970 Parse_Cond_Param2(&Value,&Value2);
1971 Flag = ((Cond_Stack[CS_Index].Switch_Value >= Value) &&
1972 (Cond_Stack[CS_Index].Switch_Value <= Value2));
1973 }
1974
1975 if(Flag && (Curr_Type==CASE_FALSE_COND))
1976 {
1977 Cond_Stack[CS_Index].Cond_Type=CASE_TRUE_COND;
1978 if (Skipping)
1979 {
1980 Token.Token_Id=HASH_TOKEN; /*insures Skip_Token takes notice*/
1981 Token.is_array_elem = false;
1982 UNGET
1983 }
1984 }
1985 break;
1986
1987 case SWITCH_COND:
1988 Cond_Stack[CS_Index].Switch_Case_Ok_Flag=true;
1989 UNGET
1990 break;
1991
1992 case SKIP_TIL_END_COND:
1993 break;
1994
1995 default:
1996 Error("Mis-matched '#case' or '#range'.");
1997 }
1998 EXIT
1999 END_CASE
2000
2001 CASE(END_TOKEN)
2002 switch (Curr_Type)
2003 {
2004 case INVOKING_MACRO_COND:
2005 Return_From_Macro();
2006 if (--CS_Index < 0)
2007 {
2008 Error("Mis-matched '#end'.");
2009 }
2010 break;
2011
2012 case IF_FALSE_COND:
2013 Token.Token_Id=HASH_TOKEN; /*insures Skip_Token takes notice*/
2014 Token.is_array_elem = false;
2015 UNGET
2016 // FALLTHROUGH
2017 case IF_TRUE_COND:
2018 case ELSE_COND:
2019 case CASE_TRUE_COND:
2020 case CASE_FALSE_COND:
2021 case DECLARING_MACRO_COND:
2022 case SKIP_TIL_END_COND:
2023 if (Curr_Type==DECLARING_MACRO_COND)
2024 {
2025 if ((PMac=Cond_Stack[CS_Index].PMac)!=NULL)
2026 {
2027 PMac->Macro_End=Hash_Loc;
2028 }
2029 }
2030 if (--CS_Index < 0)
2031 {
2032 Error("Mis-matched '#end'.");
2033 }
2034 if (Skipping)
2035 {
2036 Token.Token_Id=HASH_TOKEN; /*insures Skip_Token takes notice*/
2037 Token.is_array_elem = false;
2038 UNGET
2039 }
2040 break;
2041
2042 case WHILE_COND:
2043 if (Cond_Stack[CS_Index].Loop_File != Input_File->In_File)
2044 {
2045 Error("#while loop did not end in file where it started.");
2046 }
2047
2048 Got_EOF=false;
2049 if (!Input_File->In_File->seekg(Cond_Stack[CS_Index].File_Pos))
2050 {
2051 Error("Unable to seek in input file for #while directive.");
2052 }
2053
2054 Value=Parse_Cond_Param();
2055
2056 if (fabs(Value)<EPSILON)
2057 {
2058 Cond_Stack[CS_Index].Cond_Type = SKIP_TIL_END_COND;
2059 Skip_Tokens(SKIP_TIL_END_COND);
2060 }
2061 break;
2062
2063 case FOR_COND:
2064 if (Cond_Stack[CS_Index].Loop_File != Input_File->In_File)
2065 {
2066 Error("#for loop did not end in file where it started.");
2067 }
2068
2069 Got_EOF=false;
2070 if (!Input_File->In_File->seekg(Cond_Stack[CS_Index].File_Pos))
2071 {
2072 Error("Unable to seek in input file for #for directive.");
2073 }
2074
2075 {
2076 SYM_ENTRY* Entry = Find_Symbol(Table_Index, Cond_Stack[CS_Index].Loop_Identifier);
2077 if ((Entry == NULL) || (Entry->Token_Number != FLOAT_ID_TOKEN))
2078 Error ("#for loop variable must remain defined and numerical during loop.");
2079
2080 DBL* CurrentPtr = (DBL*)Entry->Data;
2081 DBL End = Cond_Stack[CS_Index].For_Loop_End;
2082 DBL Step = Cond_Stack[CS_Index].For_Loop_Step;
2083
2084 *CurrentPtr = *CurrentPtr + Step;
2085
2086 if ( ((Step > 0) && (*CurrentPtr > End + EPSILON)) ||
2087 ((Step < 0) && (*CurrentPtr < End - EPSILON)) )
2088 {
2089 POV_FREE(Cond_Stack[CS_Index].Loop_Identifier);
2090 Cond_Stack[CS_Index].Cond_Type = SKIP_TIL_END_COND;
2091 Skip_Tokens(SKIP_TIL_END_COND);
2092 }
2093 }
2094 break;
2095
2096 default:
2097 Error("Mis-matched '#end'.");
2098 }
2099 EXIT
2100 END_CASE
2101
2102 CASE2 (DECLARE_TOKEN,LOCAL_TOKEN)
2103 if (Skipping)
2104 {
2105 UNGET
2106 EXIT
2107 }
2108 else
2109 {
2110 Parse_Declare(Token.Token_Id == LOCAL_TOKEN, After_Hash);
2111 Curr_Type = Cond_Stack[CS_Index].Cond_Type;
2112 if (Token.Unget_Token)
2113 {
2114 switch (Token.Token_Id)
2115 {
2116 case HASH_TOKEN:
2117 Token.Unget_Token=false;
2118 break;
2119
2120 case MACRO_ID_TOKEN:
2121 break;
2122
2123 default:
2124 EXIT
2125 }
2126 }
2127 else
2128 {
2129 EXIT
2130 }
2131 }
2132 END_CASE
2133
2134 CASE (DEFAULT_TOKEN)
2135 if ( Skipping )
2136 {
2137 UNGET
2138 }
2139 else
2140 {
2141 Parse_Default();
2142 }
2143 EXIT
2144 END_CASE
2145
2146 CASE (INCLUDE_TOKEN)
2147 if (Skipping)
2148 {
2149 UNGET
2150 }
2151 else
2152 {
2153 Open_Include();
2154 }
2155 EXIT
2156 END_CASE
2157
2158 CASE (FLOAT_FUNCT_TOKEN)
2159 if (Skipping)
2160 {
2161 UNGET
2162 EXIT
2163 }
2164 else
2165 {
2166 switch(Token.Function_Id)
2167 {
2168 case VERSION_TOKEN:
2169 if (sceneData->languageVersionSet == false && token_count > 1)
2170 sceneData->languageVersionLate = true;
2171 sceneData->languageVersionSet = true;
2172 Ok_To_Declare = false;
2173 Get_Token();
2174 if (pov_stricmp(Token.Token_String,"unofficial") == 0)
2175 {
2176 #if POV_RAY_IS_OFFICIAL == 1
2177 Get_Token();
2178 Error("This file was created for an unofficial version and\ncannot work as-is with this official version.");
2179 #else
2180 // PATCH AUTHORS - you should not enable any extra features unless the
2181 // 'unofficial' keyword is set in the scene file.
2182 #endif
2183 }
2184 else
2185 Unget_Token();
2186 sceneData->languageVersion = (int)(Parse_Float() * 100 + 0.5);
2187 messageFactory.SetLanguageVersion(sceneData->languageVersion);
2188 if (sceneData->explicitNoiseGenerator == false)
2189 sceneData->noiseGenerator = sceneData->languageVersion >= 350 ? 2 : 1;
2190 // [CLi] if assumed_gamma is not specified in a legacy (3.6.x or earlier) scene, gammaMode defaults to kPOVList_GammaMode_None;
2191 // this is enforced later anyway after parsing, but we may need this information /now/ during parsing already
2192 switch (sceneData->gammaMode)
2193 {
2194 case kPOVList_GammaMode_None:
2195 case kPOVList_GammaMode_AssumedGamma37Implied:
2196 if (sceneData->EffectiveLanguageVersion() < 370)
2197 sceneData->gammaMode = kPOVList_GammaMode_None;
2198 else
2199 sceneData->gammaMode = kPOVList_GammaMode_AssumedGamma37Implied;
2200 break;
2201 case kPOVList_GammaMode_AssumedGamma36:
2202 case kPOVList_GammaMode_AssumedGamma37:
2203 if (sceneData->EffectiveLanguageVersion() < 370)
2204 sceneData->gammaMode = kPOVList_GammaMode_AssumedGamma36;
2205 else
2206 sceneData->gammaMode = kPOVList_GammaMode_AssumedGamma37;
2207 break;
2208 }
2209 Parse_Semi_Colon(false);
2210
2211 if (sceneData->languageVersion > OFFICIAL_VERSION_NUMBER)
2212 {
2213 Error("Your scene file requires POV-Ray version %g or later!\n", (DBL)(sceneData->languageVersion / 100.0));
2214 }
2215
2216 Ok_To_Declare = true;
2217 Curr_Type = Cond_Stack[CS_Index].Cond_Type;
2218 if (Token.Unget_Token && (Token.Token_Id==HASH_TOKEN))
2219 {
2220 Token.Unget_Token=false;
2221 }
2222 else
2223 {
2224 EXIT
2225 }
2226 break;
2227
2228 default:
2229 UNGET
2230 Expectation_Error ("object or directive.");
2231 break;
2232 }
2233 }
2234 END_CASE
2235
2236 CASE(WARNING_TOKEN)
2237 if (Skipping)
2238 {
2239 UNGET
2240 }
2241 else
2242 {
2243 ts=Parse_C_String();
2244 if(strlen(ts) > 160) // intentional 160, not 128 [trf]
2245 {
2246 ts[124] = ts[125] = ts[126] = '.';
2247 ts[127] = 0;
2248 }
2249 Warning(0, "%s", ts);
2250 POV_FREE(ts);
2251 }
2252 EXIT
2253 END_CASE
2254
2255 CASE(ERROR_TOKEN)
2256 if (Skipping)
2257 {
2258 UNGET
2259 }
2260 else
2261 {
2262 ts=Parse_C_String();
2263 if(strlen(ts) > 160) // intentional 160, not 128 [trf]
2264 {
2265 ts[124] = ts[125] = ts[126] = '.';
2266 ts[127] = 0;
2267 }
2268 Error("Parse halted by #error directive: %s", ts);
2269 POV_FREE(ts);
2270 }
2271 EXIT
2272 END_CASE
2273
2274 /* Note: The new message driven output system does not support
2275 generic user output to the render and statistics streams.
2276 Both streams are now directed into the debug stream. */
2277 CASE(RENDER_TOKEN)
2278 CASE(STATISTICS_TOKEN)
2279 Warning(0, "#render and #statistics streams are no longer available.\nRedirecting output to #debug stream.");
2280 // Intentional, redirect output to debug stream.
2281 CASE(DEBUG_TOKEN)
2282 if (Skipping)
2283 {
2284 UNGET
2285 }
2286 else
2287 {
2288 ts=Parse_C_String();
2289 if(strlen(ts) > 200) // intentional 200, not 160
2290 {
2291 ts[156] = ts[157] = ts[158] = '.';
2292 ts[159] = 0;
2293 }
2294 Debug_Info("%s", ts);
2295 POV_FREE(ts);
2296 }
2297 EXIT
2298 END_CASE
2299
2300 CASE(FOPEN_TOKEN)
2301 if (Skipping)
2302 {
2303 UNGET
2304 }
2305 else
2306 {
2307 Parse_Fopen();
2308 }
2309 EXIT
2310 END_CASE
2311
2312 CASE(FCLOSE_TOKEN)
2313 if (Skipping)
2314 {
2315 UNGET
2316 }
2317 else
2318 {
2319 Parse_Fclose();
2320 }
2321 EXIT
2322 END_CASE
2323
2324 CASE(READ_TOKEN)
2325 if (Skipping)
2326 {
2327 UNGET
2328 }
2329 else
2330 {
2331 Parse_Read();
2332 }
2333 EXIT
2334 END_CASE
2335
2336 CASE(WRITE_TOKEN)
2337 if (Skipping)
2338 {
2339 UNGET
2340 }
2341 else
2342 {
2343 Parse_Write();
2344 }
2345 EXIT
2346 END_CASE
2347
2348 CASE(UNDEF_TOKEN)
2349 if (Skipping)
2350 {
2351 UNGET
2352 }
2353 else
2354 {
2355 Ok_To_Declare = false;
2356 EXPECT
2357 CASE (IDENTIFIER_TOKEN)
2358 Warning(0,"Attempt to undef unknown identifier");
2359 EXIT
2360 END_CASE
2361
2362 CASE2 (MACRO_ID_TOKEN, PARAMETER_ID_TOKEN)
2363 CASE3 (FILE_ID_TOKEN, FUNCT_ID_TOKEN, VECTFUNCT_ID_TOKEN)
2364 // These have to match Parse_Declare in parse.cpp! [trf]
2365 CASE4 (TNORMAL_ID_TOKEN, FINISH_ID_TOKEN, TEXTURE_ID_TOKEN, OBJECT_ID_TOKEN)
2366 CASE4 (COLOUR_MAP_ID_TOKEN, TRANSFORM_ID_TOKEN, CAMERA_ID_TOKEN, PIGMENT_ID_TOKEN)
2367 CASE4 (SLOPE_MAP_ID_TOKEN, NORMAL_MAP_ID_TOKEN, TEXTURE_MAP_ID_TOKEN, COLOUR_ID_TOKEN)
2368 CASE4 (PIGMENT_MAP_ID_TOKEN, MEDIA_ID_TOKEN, STRING_ID_TOKEN, INTERIOR_ID_TOKEN)
2369 CASE4 (DENSITY_ID_TOKEN, ARRAY_ID_TOKEN, DENSITY_MAP_ID_TOKEN, UV_ID_TOKEN)
2370 CASE4 (VECTOR_4D_ID_TOKEN, RAINBOW_ID_TOKEN, FOG_ID_TOKEN, SKYSPHERE_ID_TOKEN)
2371 CASE2 (MATERIAL_ID_TOKEN, SPLINE_ID_TOKEN)
2372 Remove_Symbol (Token.Table_Index, Token.Token_String, Token.is_array_elem, Token.DataPtr, Token.Token_Id);
2373 EXIT
2374 END_CASE
2375
2376 CASE2 (VECTOR_FUNCT_TOKEN, FLOAT_FUNCT_TOKEN)
2377 switch(Token.Function_Id)
2378 {
2379 case VECTOR_ID_TOKEN:
2380 case FLOAT_ID_TOKEN:
2381 Remove_Symbol (Token.Table_Index, Token.Token_String, Token.is_array_elem, Token.DataPtr, Token.Token_Id);
2382 break;
2383
2384 default:
2385 Parse_Error(IDENTIFIER_TOKEN);
2386 break;
2387 }
2388 EXIT
2389 END_CASE
2390
2391 OTHERWISE
2392 Parse_Error(IDENTIFIER_TOKEN);
2393 END_CASE
2394 END_EXPECT
2395 Ok_To_Declare = true;
2396 }
2397 EXIT
2398 END_CASE
2399
2400 CASE (MACRO_ID_TOKEN)
2401 if (Skipping)
2402 {
2403 UNGET
2404 }
2405 else
2406 {
2407 Invoke_Macro();
2408 }
2409 EXIT
2410 END_CASE
2411
2412 CASE (MACRO_TOKEN)
2413 if (!Skipping)
2414 {
2415 if (Inside_MacroDef)
2416 {
2417 Error("Cannot nest macro definitions");
2418 }
2419 Inside_MacroDef=true;
2420 PMac=Parse_Macro();
2421 Inside_MacroDef=false;
2422 }
2423 Inc_CS_Index();
2424 Cond_Stack[CS_Index].Cond_Type = DECLARING_MACRO_COND;
2425 Cond_Stack[CS_Index].PMac = PMac;
2426 Skip_Tokens(DECLARING_MACRO_COND);
2427 EXIT
2428 END_CASE
2429
2430 OTHERWISE
2431 UNGET
2432 EXIT
2433 END_CASE
2434 END_EXPECT
2435
2436 if (Token.Unget_Token)
2437 {
2438 Token.Unget_Token = false;
2439 }
2440 else
2441 {
2442 Token.Token_Id = END_OF_FILE_TOKEN;
2443 Token.is_array_elem = false;
2444 }
2445 }
2446
2447
2448 /*****************************************************************************
2449 *
2450 * FUNCTION
2451 *
2452 * INPUT
2453 *
2454 * OUTPUT
2455 *
2456 * RETURNS
2457 *
2458 * AUTHOR
2459 *
2460 * DESCRIPTION
2461 *
2462 * CHANGES
2463 *
2464 ******************************************************************************/
2465
Open_Include()2466 void Parser::Open_Include()
2467 {
2468 char *tempascii;
2469 UCS2String temp;
2470 UCS2String b;
2471
2472 if (Skip_Spaces () != true)
2473 Error ("Expecting a string after INCLUDE.");
2474
2475 tempascii = Parse_C_String(true);
2476 temp = ASCIItoUCS2String(tempascii);
2477 POV_FREE(tempascii);
2478
2479 Include_File_Index++;
2480
2481 if (Include_File_Index >= MAX_INCLUDE_FILES)
2482 {
2483 Include_File_Index--;
2484 Error ("Too many nested include files.");
2485 }
2486
2487 Echo_Indx = 0;
2488
2489 Input_File = &Include_Files[Include_File_Index];
2490
2491 // must set this to NULL in case it's uninitialized - if Locate_File throws an
2492 // exception (e.g. I/O restriction error), the parser shut-down code will attempt
2493 // to free In_File if it's not NULL.
2494 Input_File->In_File = NULL;
2495
2496 IStream *is = Locate_File(this, sceneData, temp, POV_File_Text_INC, b, true);
2497 if(is == NULL)
2498 {
2499 Input_File->In_File = NULL; /* Keeps from closing failed file. */
2500 Error ("Cannot open include file %s.", UCS2toASCIIString(temp).c_str());
2501 }
2502 else
2503 Input_File->In_File = new ITextStream(b.c_str(), is);
2504
2505 Input_File->R_Flag=false;
2506
2507 Add_Sym_Table();
2508
2509 Token.Token_Id = END_OF_FILE_TOKEN;
2510 Token.is_array_elem = false;
2511
2512 }
2513
2514
2515
2516 /*****************************************************************************
2517 *
2518 * FUNCTION
2519 *
2520 * INPUT
2521 *
2522 * OUTPUT
2523 *
2524 * RETURNS
2525 *
2526 * AUTHOR
2527 *
2528 * DESCRIPTION
2529 *
2530 * CHANGES
2531 *
2532 ******************************************************************************/
2533
Skip_Tokens(COND_TYPE cond)2534 void Parser::Skip_Tokens(COND_TYPE cond)
2535 {
2536 int Temp = CS_Index;
2537 int Prev_Skip = Skipping;
2538
2539 Skipping=true;
2540
2541 while ((CS_Index > Temp) || ((CS_Index == Temp) && (Cond_Stack[CS_Index].Cond_Type == cond)))
2542 {
2543 Get_Token();
2544 }
2545
2546 Skipping=Prev_Skip;
2547
2548 if (Token.Token_Id==HASH_TOKEN)
2549 {
2550 Token.Token_Id=END_OF_FILE_TOKEN;
2551 Token.is_array_elem = false;
2552 Token.Unget_Token=false;
2553 }
2554 else
2555 {
2556 UNGET
2557 }
2558 }
2559
2560
2561 /*****************************************************************************
2562 *
2563 * FUNCTION
2564 *
2565 * INPUT
2566 *
2567 * OUTPUT
2568 *
2569 * RETURNS
2570 *
2571 * AUTHOR
2572 *
2573 * DESCRIPTION
2574 *
2575 * CHANGES
2576 *
2577 ******************************************************************************/
2578
Break()2579 void Parser::Break()
2580 {
2581 int Prev_Skip = Skipping;
2582
2583 Skipping=true;
2584
2585 while ( (CS_Index > 0) &&
2586 (Cond_Stack[CS_Index].Cond_Type != WHILE_COND) &&
2587 (Cond_Stack[CS_Index].Cond_Type != FOR_COND) &&
2588 (Cond_Stack[CS_Index].Cond_Type != CASE_TRUE_COND) &&
2589 (Cond_Stack[CS_Index].Cond_Type != INVOKING_MACRO_COND) )
2590 {
2591 Get_Token();
2592 }
2593
2594 if (CS_Index == 0)
2595 Error ("Invalid context for #break");
2596
2597 if (Cond_Stack[CS_Index].Cond_Type == INVOKING_MACRO_COND)
2598 {
2599 Skipping=Prev_Skip;
2600 Return_From_Macro();
2601 --CS_Index;
2602 return;
2603 }
2604
2605 Cond_Stack[CS_Index].Cond_Type = SKIP_TIL_END_COND;
2606 Skip_Tokens (SKIP_TIL_END_COND);
2607
2608 Skipping=Prev_Skip;
2609
2610 if (Token.Token_Id==HASH_TOKEN)
2611 {
2612 Token.Token_Id=END_OF_FILE_TOKEN;
2613 Token.is_array_elem = false;
2614 Token.Unget_Token=false;
2615 }
2616 else
2617 {
2618 UNGET
2619 }
2620 }
2621
2622
2623 /*****************************************************************************
2624 *
2625 * FUNCTION
2626 *
2627 * get_hash_value
2628 *
2629 * INPUT
2630 *
2631 * OUTPUT
2632 *
2633 * RETURNS
2634 *
2635 * AUTHOR
2636 *
2637 * Dieter Bayer
2638 *
2639 * DESCRIPTION
2640 *
2641 * Calculate hash value for a given string.
2642 *
2643 * CHANGES
2644 *
2645 * Apr 1996 : Creation.
2646 *
2647 ******************************************************************************/
2648
get_hash_value(const char * s)2649 int Parser::get_hash_value(const char *s)
2650 {
2651 unsigned int i = 0;
2652
2653 while (*s)
2654 {
2655 i = (i << 1) ^ *s++;
2656 }
2657
2658 return((int)(i % SYM_TABLE_SIZE));
2659 }
2660
2661
2662
2663 /*****************************************************************************
2664 *
2665 * FUNCTION
2666 *
2667 * init_sym_tables
2668 *
2669 * INPUT
2670 *
2671 * OUTPUT
2672 *
2673 * RETURNS
2674 *
2675 * AUTHOR
2676 *
2677 * Chris Young
2678 *
2679 * DESCRIPTION
2680 *
2681 * CHANGES
2682 *
2683 ******************************************************************************/
2684
init_sym_tables()2685 void Parser::init_sym_tables()
2686 {
2687 int i;
2688
2689 Add_Sym_Table();
2690
2691 for (i = 0; i < LAST_TOKEN; i++)
2692 {
2693 Add_Symbol(0,Reserved_Words[i].Token_Name,Reserved_Words[i].Token_Number);
2694 }
2695
2696 Add_Sym_Table();
2697 }
2698
Add_Sym_Table()2699 void Parser::Add_Sym_Table()
2700 {
2701 int i;
2702
2703 SYM_TABLE *New;
2704
2705 if ((++Table_Index)==MAX_NUMBER_OF_TABLES)
2706 {
2707 Table_Index--;
2708 Error("Too many nested symbol tables");
2709 }
2710
2711 Tables[Table_Index]=New=(SYM_TABLE *)POV_MALLOC(sizeof(SYM_TABLE),"symbol table");
2712
2713 for (i = 0; i < SYM_TABLE_SIZE; i++)
2714 {
2715 New->Table[i] = NULL;
2716 }
2717
2718 }
2719
Destroy_Table(int index)2720 void Parser::Destroy_Table(int index)
2721 {
2722 int i;
2723 SYM_TABLE *Table = Tables[index];
2724 SYM_ENTRY *Entry;
2725
2726 for(i = SYM_TABLE_SIZE - 1; i >= 0; i--)
2727 {
2728 Entry = Table->Table[i];
2729
2730 while(Entry)
2731 {
2732 Entry = Destroy_Entry(index, Entry);
2733 }
2734
2735 Table->Table[i] = NULL;
2736 }
2737
2738 POV_FREE(Table);
2739
2740 }
2741
Create_Entry(int Index,const char * Name,TOKEN Number)2742 SYM_ENTRY *Parser::Create_Entry (int Index,const char *Name,TOKEN Number)
2743 {
2744 SYM_ENTRY *New;
2745
2746 New = (SYM_ENTRY *)POV_MALLOC(sizeof(SYM_ENTRY), "symbol table entry");
2747
2748 New->Token_Number = Number;
2749 New->Data = NULL;
2750 New->Flags = 0;
2751 New->Deprecation_Message = NULL;
2752 New->ref_count = 1;
2753 if (Index != 0)
2754 New->Token_Name = POV_STRDUP(Name);
2755 else
2756 New->Token_Name = const_cast<char*>(Name);
2757
2758 return(New);
2759 }
2760
Acquire_Entry_Reference(SYM_ENTRY * Entry)2761 void Parser::Acquire_Entry_Reference (SYM_ENTRY *Entry)
2762 {
2763 if (Entry == NULL)
2764 return;
2765 if (Entry->ref_count >= SYM_ENTRY_REF_MAX)
2766 Error("Too many unresolved references to symbol");
2767 Entry->ref_count ++;
2768 }
2769
Release_Entry_Reference(int Index,SYM_ENTRY * Entry)2770 void Parser::Release_Entry_Reference (int Index, SYM_ENTRY *Entry)
2771 {
2772 if (Entry == NULL)
2773 return;
2774 if (Entry->ref_count <= 0)
2775 Error("Internal error: Symbol reference counter underflow");
2776 Entry->ref_count --;
2777
2778 if (Entry->ref_count == 0)
2779 {
2780 if(Index != 0) // NB reserved words reference hard-coded token names in code segment, rather than allocated on heap
2781 {
2782 POV_FREE(Entry->Token_Name);
2783 Destroy_Ident_Data (Entry->Data, Entry->Token_Number); // TODO - shouldn't this be outside the if() block?
2784 }
2785 if (Entry->Deprecation_Message != NULL)
2786 POV_FREE(Entry->Deprecation_Message);
2787
2788 POV_FREE(Entry);
2789 }
2790 }
2791
Destroy_Entry(int Index,SYM_ENTRY * Entry)2792 SYM_ENTRY *Parser::Destroy_Entry (int Index, SYM_ENTRY *Entry)
2793 {
2794 SYM_ENTRY *Next;
2795
2796 if(Entry == NULL)
2797 return NULL;
2798
2799 // always unhook the entry from hash table (if it is still member of one)
2800 Next = Entry->next;
2801 Entry->next = NULL;
2802
2803 if (Entry->ref_count <= 0)
2804 Error("Internal error: Symbol reference counter underflow");
2805 Entry->ref_count --;
2806
2807 if (Entry->ref_count == 0)
2808 {
2809 if(Index != 0) // NB reserved words reference hard-coded token names in code segment, rather than allocated on heap
2810 {
2811 POV_FREE(Entry->Token_Name);
2812 Destroy_Ident_Data (Entry->Data, Entry->Token_Number); // TODO - shouldn't this be outside the if() block?
2813 }
2814 if (Entry->Deprecation_Message != NULL)
2815 POV_FREE(Entry->Deprecation_Message);
2816
2817 POV_FREE(Entry);
2818 }
2819
2820 return Next;
2821 }
2822
2823
Add_Entry(int Index,SYM_ENTRY * Table_Entry)2824 void Parser::Add_Entry (int Index,SYM_ENTRY *Table_Entry)
2825 {
2826 int i = get_hash_value(Table_Entry->Token_Name);
2827
2828 Table_Entry->next = Tables[Index]->Table[i];
2829 Tables[Index]->Table[i] = Table_Entry;
2830 }
2831
2832
Add_Symbol(int Index,const char * Name,TOKEN Number)2833 SYM_ENTRY *Parser::Add_Symbol (int Index,const char *Name,TOKEN Number)
2834 {
2835 SYM_ENTRY *New;
2836
2837 New = Create_Entry (Index,Name,Number);
2838 Add_Entry(Index,New);
2839
2840 return(New);
2841 }
2842
2843
Find_Symbol(int Index,const char * Name)2844 SYM_ENTRY *Parser::Find_Symbol(int Index,const char *Name)
2845 {
2846 SYM_ENTRY *Entry;
2847
2848 int i = get_hash_value(Name);
2849
2850 Entry = Tables[Index]->Table[i];
2851
2852 while (Entry)
2853 {
2854 if (strcmp(Name, Entry->Token_Name) == 0)
2855 {
2856 return(Entry);
2857 }
2858
2859 Entry = Entry->next;
2860 }
2861
2862 return(Entry);
2863 }
2864
2865
Remove_Symbol(int Index,const char * Name,bool is_array_elem,void ** DataPtr,int ttype)2866 void Parser::Remove_Symbol (int Index, const char *Name, bool is_array_elem, void **DataPtr, int ttype)
2867 {
2868 if(is_array_elem == true)
2869 {
2870 if(DataPtr == NULL)
2871 Error("Invalid array element!");
2872
2873 if(ttype == FLOAT_FUNCT_TOKEN)
2874 ttype = FLOAT_ID_TOKEN;
2875 else if(ttype == VECTOR_FUNCT_TOKEN)
2876 ttype = VECTOR_ID_TOKEN;
2877 else if(ttype == COLOUR_KEY_TOKEN)
2878 ttype = COLOUR_ID_TOKEN;
2879
2880 Destroy_Ident_Data (*DataPtr, ttype);
2881 *DataPtr = NULL;
2882 }
2883 else
2884 {
2885 SYM_ENTRY *Entry;
2886 SYM_ENTRY **EntryPtr;
2887
2888 int i = get_hash_value(Name);
2889
2890 EntryPtr = &(Tables[Index]->Table[i]);
2891 Entry = *EntryPtr;
2892
2893 while (Entry)
2894 {
2895 if (strcmp(Name, Entry->Token_Name) == 0)
2896 {
2897 *EntryPtr = Entry->next;
2898 Destroy_Entry(Index, Entry);
2899 return;
2900 }
2901
2902 EntryPtr = &(Entry->next);
2903 Entry = *EntryPtr;
2904 }
2905
2906 Error("Tried to free undefined symbol");
2907 }
2908 }
2909
Check_Macro_Vers(void)2910 void Parser::Check_Macro_Vers(void)
2911 {
2912 if (sceneData->languageVersion < 310)
2913 {
2914 Error("Macros require #version 3.1 or later but #version %x.%02d is set.",
2915 sceneData->languageVersion / 100, sceneData->languageVersion % 100);
2916 }
2917 }
2918
Parse_Macro()2919 Parser::POV_MACRO *Parser::Parse_Macro()
2920 {
2921 POV_MACRO *New;
2922 SYM_ENTRY *Table_Entry=NULL;
2923 int Old_Ok = Ok_To_Declare;
2924
2925 Check_Macro_Vers();
2926
2927 Ok_To_Declare = false;
2928
2929 EXPECT
2930 CASE (IDENTIFIER_TOKEN)
2931 Table_Entry = Add_Symbol (1,Token.Token_String,TEMPORARY_MACRO_ID_TOKEN);
2932 EXIT
2933 END_CASE
2934
2935 CASE (MACRO_ID_TOKEN)
2936 Remove_Symbol(1,Token.Token_String,false,NULL,0);
2937 Table_Entry = Add_Symbol (1,Token.Token_String,TEMPORARY_MACRO_ID_TOKEN);
2938 EXIT
2939 END_CASE
2940
2941 OTHERWISE
2942 Parse_Error(IDENTIFIER_TOKEN);
2943 END_CASE
2944 END_EXPECT
2945
2946 New=(POV_MACRO *)POV_MALLOC(sizeof(POV_MACRO),"macro");
2947
2948 Table_Entry->Data=(void *)New;
2949
2950 New->Macro_Filename = NULL;
2951 New->Num_Of_Pars=0;
2952 New->Macro_Name=POV_STRDUP(Token.Token_String);
2953
2954 EXPECT
2955 CASE (LEFT_PAREN_TOKEN )
2956 EXIT
2957 END_CASE
2958 CASE (TEMPORARY_MACRO_ID_TOKEN)
2959 Error( "Can't invoke a macro while declaring its parameters");
2960 END_CASE
2961
2962 OTHERWISE
2963 Expectation_Error ("identifier or expression.");
2964 END_CASE
2965 END_EXPECT
2966
2967 EXPECT
2968 CASE3 (MACRO_ID_TOKEN, IDENTIFIER_TOKEN, PARAMETER_ID_TOKEN)
2969 CASE3 (FILE_ID_TOKEN, FUNCT_ID_TOKEN, VECTFUNCT_ID_TOKEN)
2970 // These have to match Parse_Declare in parse.cpp! [trf]
2971 CASE4 (TNORMAL_ID_TOKEN, FINISH_ID_TOKEN, TEXTURE_ID_TOKEN, OBJECT_ID_TOKEN)
2972 CASE4 (COLOUR_MAP_ID_TOKEN, TRANSFORM_ID_TOKEN, CAMERA_ID_TOKEN, PIGMENT_ID_TOKEN)
2973 CASE4 (SLOPE_MAP_ID_TOKEN, NORMAL_MAP_ID_TOKEN, TEXTURE_MAP_ID_TOKEN, COLOUR_ID_TOKEN)
2974 CASE4 (PIGMENT_MAP_ID_TOKEN, MEDIA_ID_TOKEN, STRING_ID_TOKEN, INTERIOR_ID_TOKEN)
2975 CASE4 (DENSITY_ID_TOKEN, ARRAY_ID_TOKEN, DENSITY_MAP_ID_TOKEN, UV_ID_TOKEN)
2976 CASE4 (VECTOR_4D_ID_TOKEN, RAINBOW_ID_TOKEN, FOG_ID_TOKEN, SKYSPHERE_ID_TOKEN)
2977 CASE2 (MATERIAL_ID_TOKEN, SPLINE_ID_TOKEN)
2978 New->Par_Name[New->Num_Of_Pars] = POV_STRDUP(Token.Token_String);
2979 if (++(New->Num_Of_Pars) == MAX_PARAMETER_LIST)
2980 {
2981 Error("Too many parameters");
2982 }
2983 Parse_Comma();
2984 END_CASE
2985
2986 CASE2 (VECTOR_FUNCT_TOKEN, FLOAT_FUNCT_TOKEN)
2987 switch(Token.Function_Id)
2988 {
2989 case VECTOR_ID_TOKEN:
2990 case FLOAT_ID_TOKEN:
2991 New->Par_Name[New->Num_Of_Pars] = POV_STRDUP(Token.Token_String);
2992 if (++(New->Num_Of_Pars) == MAX_PARAMETER_LIST)
2993 {
2994 Error("Too many parameters");
2995 }
2996 Parse_Comma();
2997 break;
2998
2999 default:
3000 Expectation_Error ("identifier or expression.");
3001 break;
3002 }
3003 END_CASE
3004
3005 CASE(RIGHT_PAREN_TOKEN)
3006 UNGET
3007 EXIT
3008 END_CASE
3009
3010 CASE(TEMPORARY_MACRO_ID_TOKEN)
3011 Error( "Can't invoke a macro while declaring its parameters");
3012 END_CASE
3013
3014 OTHERWISE
3015 Expectation_Error ("identifier or expression.");
3016 END_CASE
3017 END_EXPECT
3018
3019 Ok_To_Declare = Old_Ok;
3020
3021 Table_Entry->Token_Number = MACRO_ID_TOKEN;
3022
3023 New->Macro_Filename = UCS2_strdup(Input_File->In_File->name());
3024 New->Macro_File_Pos = Input_File->In_File->tellg();
3025
3026 Check_Macro_Vers();
3027
3028 return (New);
3029 }
3030
3031
Invoke_Macro()3032 void Parser::Invoke_Macro()
3033 {
3034 POV_MACRO *PMac=(POV_MACRO *)Token.Data;
3035 SYM_ENTRY **Table_Entries=NULL;
3036 int i,Local_Index;
3037
3038 if(PMac == NULL)
3039 {
3040 if(Token.DataPtr!=NULL)
3041 PMac = (POV_MACRO*)(*(Token.DataPtr));
3042 else
3043 Error("Error in Invoke_Macro");
3044 }
3045
3046 Check_Macro_Vers();
3047
3048 GET(LEFT_PAREN_TOKEN);
3049
3050 if (PMac->Num_Of_Pars > 0)
3051 {
3052 Table_Entries = (SYM_ENTRY **)POV_MALLOC(sizeof(SYM_ENTRY *)*PMac->Num_Of_Pars,"parameters");
3053
3054 /* We must parse all parameters before adding new symbol table
3055 or adding entries. Otherwise recursion won't always work.
3056 */
3057
3058 Local_Index = Table_Index;
3059
3060 for (i=0; i<PMac->Num_Of_Pars; i++)
3061 {
3062 Table_Entries[i]=Create_Entry(1,PMac->Par_Name[i],IDENTIFIER_TOKEN);
3063 if (!Parse_RValue(IDENTIFIER_TOKEN, &(Table_Entries[i]->Token_Number), &(Table_Entries[i]->Data), NULL, true, false, true, true, Local_Index))
3064 {
3065 Error("Expected %d parameters but only %d found.",PMac->Num_Of_Pars,i);
3066 }
3067 Parse_Comma();
3068 }
3069 }
3070
3071 GET(RIGHT_PAREN_TOKEN);
3072
3073 Inc_CS_Index();
3074 Cond_Stack[CS_Index].Cond_Type = INVOKING_MACRO_COND;
3075
3076 Cond_Stack[CS_Index].File_Pos = Input_File->In_File->tellg();
3077 Cond_Stack[CS_Index].Macro_Return_Name = Input_File->In_File->name();
3078 Cond_Stack[CS_Index].PMac = PMac;
3079
3080 /* Gotta have new symbol table in case #local is used */
3081 Add_Sym_Table();
3082
3083 if (PMac->Num_Of_Pars > 0)
3084 {
3085 for (i=0; i<PMac->Num_Of_Pars; i++)
3086 {
3087 Add_Entry(Table_Index,Table_Entries[i]);
3088 }
3089
3090 POV_FREE(Table_Entries);
3091 }
3092
3093 if (UCS2_strcmp(PMac->Macro_Filename,Input_File->In_File->name()))
3094 {
3095 UCS2String ign;
3096 /* Not in same file */
3097 Cond_Stack[CS_Index].Macro_Same_Flag=false;
3098 Cond_Stack[CS_Index].Macro_File = Input_File->In_File ;
3099 // POV_DELETE(Input_File->In_File, IStream);
3100 Got_EOF=false;
3101 Input_File->R_Flag=false;
3102 IStream *is = Locate_File (this, sceneData, PMac->Macro_Filename, POV_File_Text_Macro, ign, true);
3103 if(is == NULL)
3104 {
3105 Input_File->In_File = NULL; /* Keeps from closing failed file. */
3106 Error ("Cannot open macro file '%s'.", UCS2toASCIIString(UCS2String(PMac->Macro_Filename)).c_str());
3107 }
3108 else
3109 Input_File->In_File = new ITextStream(PMac->Macro_Filename, is);
3110 }
3111 else
3112 {
3113 Cond_Stack[CS_Index].Macro_Same_Flag=true;
3114 }
3115
3116 Got_EOF=false;
3117 if (!Input_File->In_File->seekg(PMac->Macro_File_Pos))
3118 {
3119 Error("Unable to file seek in macro.");
3120 }
3121
3122 Token.Token_Id = END_OF_FILE_TOKEN;
3123 Token.is_array_elem = false;
3124
3125 Check_Macro_Vers();
3126
3127 }
3128
Return_From_Macro()3129 void Parser::Return_From_Macro()
3130 {
3131 Check_Macro_Vers();
3132
3133 if (!Cond_Stack[CS_Index].Macro_Same_Flag)
3134 {
3135 if (Token.FileHandle == Input_File->In_File)
3136 Token.FileHandle = NULL;
3137 delete Input_File->In_File;
3138 Input_File->R_Flag=false;
3139 Input_File->In_File = Cond_Stack[CS_Index].Macro_File ;
3140 if (Token.FileHandle == NULL)
3141 Token.FileHandle = Input_File->In_File;
3142 }
3143
3144 Got_EOF=false;
3145
3146 if (!Input_File->In_File->seekg(Cond_Stack[CS_Index].File_Pos))
3147 {
3148 Error("Unable to file seek in return from macro.");
3149 }
3150
3151 // Always destroy macro locals
3152 Destroy_Table(Table_Index--);
3153 }
3154
Destroy_Macro(POV_MACRO * PMac)3155 void Parser::Destroy_Macro(POV_MACRO *PMac)
3156 {
3157 int i;
3158 if (PMac==NULL)
3159 {
3160 return;
3161 }
3162
3163 POV_FREE(PMac->Macro_Name);
3164 if (PMac->Macro_Filename!=NULL)
3165 {
3166 POV_FREE(PMac->Macro_Filename);
3167 }
3168
3169 for (i=0; i < PMac->Num_Of_Pars; i++)
3170 {
3171 POV_FREE(PMac->Par_Name[i]);
3172 }
3173
3174 POV_FREE(PMac);
3175 }
3176
Parse_Array_Declare(void)3177 Parser::POV_ARRAY *Parser::Parse_Array_Declare (void)
3178 {
3179 POV_ARRAY *New;
3180 int i,j;
3181
3182 New=(POV_ARRAY *)POV_MALLOC(sizeof(POV_ARRAY),"array");
3183
3184 i=0;
3185 j=1;
3186
3187 Ok_To_Declare = false;
3188
3189 EXPECT
3190 CASE (LEFT_SQUARE_TOKEN)
3191 if (i>4)
3192 {
3193 Error("Too many array dimensions");
3194 }
3195 New->Sizes[i]=(int)(Parse_Float() + EPSILON);
3196 j *= New->Sizes[i];
3197 if ( j <= 0) {
3198 Error("Invalid dimension size for an array");
3199 }
3200 i++;
3201 GET(RIGHT_SQUARE_TOKEN)
3202 END_CASE
3203
3204 OTHERWISE
3205 UNGET
3206 EXIT
3207 END_CASE
3208 END_EXPECT
3209
3210 if ( i < 1 ) {
3211 Error( "An array declaration must have at least one dimension");
3212 }
3213
3214 New->Dims = i-1;
3215 New->Total = j;
3216 New->Type = EMPTY_ARRAY_TOKEN;
3217 New->DataPtrs = (void **)POV_MALLOC(sizeof(void *)*j,"array");
3218
3219 j = 1;
3220
3221 for(i = New->Dims; i>=0; i--)
3222 {
3223 New->Mags[i] = j;
3224 j *= New->Sizes[i];
3225 }
3226
3227 for (i=0; i<New->Total; i++)
3228 {
3229 New->DataPtrs[i] = NULL;
3230 }
3231
3232 EXPECT
3233 CASE(LEFT_CURLY_TOKEN)
3234 UNGET
3235 Parse_Initalizer(0,0,New);
3236 EXIT
3237 END_CASE
3238
3239 OTHERWISE
3240 UNGET
3241 EXIT
3242 END_CASE
3243 END_EXPECT
3244
3245 Ok_To_Declare = true;
3246 return(New);
3247
3248 };
3249
Parse_Initalizer(int Sub,int Base,POV_ARRAY * a)3250 void Parser::Parse_Initalizer (int Sub, int Base, POV_ARRAY *a)
3251 {
3252 int i;
3253
3254 Parse_Begin();
3255 if (Sub < a->Dims)
3256 {
3257 for(i=0; i < a->Sizes[Sub]; i++)
3258 {
3259 Parse_Initalizer(Sub+1,i*a->Mags[Sub]+Base,a);
3260 }
3261 }
3262 else
3263 {
3264 for(i=0; i < a->Sizes[Sub]; i++)
3265 {
3266 if (!Parse_RValue (a->Type, &(a->Type), &(a->DataPtrs[Base+i]), NULL, false, false, true, false, MAX_NUMBER_OF_TABLES))
3267 {
3268 Error("Insufficent number of initializers");
3269 }
3270 Parse_Comma();
3271 }
3272 }
3273 Parse_End();
3274 Parse_Comma();
3275 };
3276
Parse_Fopen(void)3277 void Parser::Parse_Fopen(void)
3278 {
3279 IStream *rfile = NULL;
3280 OStream *wfile = NULL;
3281 DATA_FILE *New;
3282 char *asciitemp;
3283 UCS2String temp;
3284 UCS2String ign;
3285 SYM_ENTRY *Entry;
3286
3287 New=(DATA_FILE *)POV_MALLOC(sizeof(DATA_FILE),"user file");
3288 New->In_File=NULL;
3289 New->Out_File=NULL;
3290
3291 GET(IDENTIFIER_TOKEN)
3292 Entry = Add_Symbol (1,Token.Token_String,FILE_ID_TOKEN);
3293 Entry->Data=(void *)New;
3294
3295 asciitemp = Parse_C_String(true);
3296 temp = ASCIItoUCS2String(asciitemp);
3297 POV_FREE(asciitemp);
3298
3299 EXPECT
3300 CASE(READ_TOKEN)
3301 New->R_Flag = true;
3302 rfile = Locate_File(this, sceneData, temp.c_str(), POV_File_Text_User, ign, true);
3303 if(rfile != NULL)
3304 New->In_File = new ITextStream(temp.c_str(), rfile);
3305 else
3306 New->In_File = NULL;
3307
3308 if(New->In_File == NULL)
3309 Error ("Cannot open user file %s (read).", UCS2toASCIIString(temp).c_str());
3310 EXIT
3311 END_CASE
3312
3313 CASE(WRITE_TOKEN)
3314 New->R_Flag = false;
3315 wfile = sceneData->CreateFile(GetPOVMSContext(), temp.c_str(), POV_File_Text_User, false);
3316 if(wfile != NULL)
3317 New->Out_File= new OTextStream(temp.c_str(), wfile);
3318 else
3319 New->Out_File = NULL;
3320
3321 if(New->Out_File == NULL)
3322 Error ("Cannot open user file %s (write).", UCS2toASCIIString(temp).c_str());
3323 EXIT
3324 END_CASE
3325
3326 CASE(APPEND_TOKEN)
3327 New->R_Flag = false;
3328 wfile = sceneData->CreateFile(GetPOVMSContext(), temp.c_str(), POV_File_Text_User, true);
3329 if(wfile != NULL)
3330 New->Out_File= new OTextStream(temp.c_str(), wfile);
3331 else
3332 New->Out_File = NULL;
3333
3334 if(New->Out_File == NULL)
3335 Error ("Cannot open user file %s (append).", UCS2toASCIIString(temp).c_str());
3336 EXIT
3337 END_CASE
3338
3339 OTHERWISE
3340 Expectation_Error("read or write");
3341 END_CASE
3342 END_EXPECT
3343 }
3344
Parse_Fclose(void)3345 void Parser::Parse_Fclose(void)
3346 {
3347 DATA_FILE *Data;
3348
3349 EXPECT
3350 CASE(FILE_ID_TOKEN)
3351 Data=(DATA_FILE *)Token.Data;
3352 if(Data->In_File != NULL)
3353 delete Data->In_File;
3354 if(Data->Out_File != NULL)
3355 delete Data->Out_File;
3356 Got_EOF=false;
3357 Data->In_File = NULL;
3358 Data->Out_File = NULL;
3359 Remove_Symbol (1,Token.Token_String,false,NULL,0);
3360 EXIT
3361 END_CASE
3362
3363 OTHERWISE
3364 EXIT
3365 END_CASE
3366 END_EXPECT
3367 }
3368
Parse_Read()3369 void Parser::Parse_Read()
3370 {
3371 DATA_FILE *User_File;
3372 SYM_ENTRY *Temp_Entry;
3373 int End_File=false;
3374 char *File_Id;
3375
3376 GET(LEFT_PAREN_TOKEN)
3377
3378 GET(FILE_ID_TOKEN)
3379 User_File=(DATA_FILE *)Token.Data;
3380 File_Id=POV_STRDUP(Token.Token_String);
3381 if(User_File->In_File == NULL)
3382 Error("Cannot read from file %s because the file is open for writing only.", UCS2toASCIIString(UCS2String(User_File->Out_File->name())).c_str());
3383
3384 Parse_Comma(); /* Scene file comma between File_Id and 1st data ident */
3385
3386 LValue_Ok = true;
3387
3388 EXPECT
3389 CASE (IDENTIFIER_TOKEN)
3390 if (!End_File)
3391 {
3392 Temp_Entry = Add_Symbol (1,Token.Token_String,IDENTIFIER_TOKEN);
3393 End_File=Parse_Read_Value (User_File,Token.Token_Id, &(Temp_Entry->Token_Number), &(Temp_Entry->Data));
3394 Token.is_array_elem = false;
3395 Parse_Comma(); /* Scene file comma between 2 idents */
3396 }
3397 END_CASE
3398
3399 CASE (STRING_ID_TOKEN)
3400 if (!End_File)
3401 {
3402 End_File=Parse_Read_Value (User_File,Token.Token_Id,Token.NumberPtr,Token.DataPtr);
3403 Token.is_array_elem = false;
3404 Parse_Comma(); /* Scene file comma between 2 idents */
3405 }
3406 END_CASE
3407
3408 CASE2 (VECTOR_FUNCT_TOKEN,FLOAT_FUNCT_TOKEN)
3409 switch(Token.Function_Id)
3410 {
3411 case VECTOR_ID_TOKEN:
3412 case FLOAT_ID_TOKEN:
3413 if (!End_File)
3414 {
3415 End_File=Parse_Read_Value (User_File,Token.Function_Id,Token.NumberPtr,Token.DataPtr);
3416 Parse_Comma(); /* Scene file comma between 2 idents */
3417 }
3418 break;
3419
3420 default:
3421 Parse_Error(IDENTIFIER_TOKEN);
3422 break;
3423 }
3424 END_CASE
3425
3426 CASE(COMMA_TOKEN)
3427 if (!End_File)
3428 {
3429 Parse_Error(IDENTIFIER_TOKEN);
3430 }
3431 END_CASE
3432
3433 CASE(RIGHT_PAREN_TOKEN)
3434 EXIT
3435 END_CASE
3436
3437 OTHERWISE
3438 Parse_Error(IDENTIFIER_TOKEN);
3439 END_CASE
3440 END_EXPECT
3441
3442 LValue_Ok = false;
3443
3444 if (End_File)
3445 {
3446 delete User_File->In_File;
3447 Got_EOF=false;
3448 User_File->In_File = NULL;
3449 Remove_Symbol (1,File_Id,false,NULL,0);
3450 }
3451 POV_FREE(File_Id);
3452 }
3453
Parse_Read_Value(DATA_FILE * User_File,int Previous,int * NumberPtr,void ** DataPtr)3454 int Parser::Parse_Read_Value(DATA_FILE *User_File,int Previous,int *NumberPtr,void **DataPtr)
3455 {
3456 pov_base::ITextStream *Temp;
3457 bool Temp_R_Flag;
3458 DBL Val;
3459 int End_File=false;
3460 int i;
3461 EXPRESS Express;
3462
3463 Temp = Input_File->In_File;
3464 Temp_R_Flag = Input_File->R_Flag;
3465 Input_File->In_File = User_File->In_File;
3466 Input_File->R_Flag = User_File->R_Flag;
3467 if(User_File->In_File == NULL)
3468 Error("Cannot read from file '%s' because the file is open for writing only.", UCS2toASCIIString(UCS2String(User_File->Out_File->name())).c_str());
3469 User_File->In_File = NULL; // take control over pointer
3470
3471 try
3472 {
3473 EXPECT
3474 CASE3 (PLUS_TOKEN,DASH_TOKEN,FLOAT_FUNCT_TOKEN)
3475 UNGET
3476 Val=Parse_Signed_Float();
3477 *NumberPtr = FLOAT_ID_TOKEN;
3478 Test_Redefine(Previous,NumberPtr,*DataPtr);
3479 *DataPtr = (void *) Create_Float();
3480 *((DBL *)*DataPtr) = Val;
3481 Parse_Comma(); /* data file comma between 2 data items */
3482 EXIT
3483 END_CASE
3484
3485 CASE (LEFT_ANGLE_TOKEN)
3486 i=1;
3487 Express[X]=Parse_Signed_Float(); Parse_Comma();
3488 Express[Y]=Parse_Signed_Float(); Parse_Comma();
3489
3490 EXPECT
3491 CASE3 (PLUS_TOKEN,DASH_TOKEN,FLOAT_FUNCT_TOKEN)
3492 UNGET
3493 if (++i>4)
3494 {
3495 Error("Vector data too long");
3496 }
3497 Express[i]=Parse_Signed_Float(); Parse_Comma();
3498 END_CASE
3499
3500 CASE (RIGHT_ANGLE_TOKEN)
3501 EXIT
3502 END_CASE
3503
3504 OTHERWISE
3505 Expectation_Error("vector");
3506 END_CASE
3507 END_EXPECT
3508
3509 switch(i)
3510 {
3511 case 1:
3512 *NumberPtr = UV_ID_TOKEN;
3513 Test_Redefine(Previous,NumberPtr,*DataPtr);
3514 *DataPtr = (void *) Create_UV_Vect();
3515 Assign_UV_Vect((DBL *)*DataPtr, Express);
3516 break;
3517
3518 case 2:
3519 *NumberPtr = VECTOR_ID_TOKEN;
3520 Test_Redefine(Previous,NumberPtr,*DataPtr);
3521 *DataPtr = (void *) Create_Vector();
3522 Assign_Vector((DBL *)*DataPtr, Express);
3523 break;
3524
3525 case 3:
3526 *NumberPtr = VECTOR_4D_ID_TOKEN;
3527 Test_Redefine(Previous,NumberPtr,*DataPtr);
3528 *DataPtr = (void *) Create_Vector_4D();
3529 Assign_Vector_4D((DBL *)*DataPtr, Express);
3530 break;
3531
3532 case 4:
3533 *NumberPtr = COLOUR_ID_TOKEN;
3534 Test_Redefine(Previous,NumberPtr,*DataPtr);
3535 *DataPtr = (void *) Create_Colour();
3536 Assign_Colour_Express((COLC*)(*DataPtr), Express); /* NK fix assign_colour bug */
3537 break;
3538 }
3539
3540 Parse_Comma(); // data file comma between 2 data items
3541 EXIT
3542 END_CASE
3543
3544 CASE(STRING_LITERAL_TOKEN)
3545 *NumberPtr = STRING_ID_TOKEN;
3546 Test_Redefine(Previous,NumberPtr,*DataPtr);
3547 *DataPtr = String_To_UCS2(Token.Token_String, false);
3548 Parse_Comma(); // data file comma between 2 data items
3549 EXIT
3550 END_CASE
3551
3552 CASE (END_OF_FILE_TOKEN)
3553 EXIT
3554 END_CASE
3555
3556 OTHERWISE
3557 Expectation_Error ("float, vector, or string literal");
3558 END_CASE
3559 END_EXPECT
3560 }
3561 catch (...)
3562 {
3563 // re-assign the file pointers so that they are properly disposed of later on
3564 User_File->In_File = Input_File->In_File;
3565 Input_File->In_File = Temp;
3566 Input_File->R_Flag = Temp_R_Flag;
3567 throw;
3568 }
3569
3570 if (Token.Token_Id==END_OF_FILE_TOKEN)
3571 End_File = true;
3572
3573 Token.End_Of_File = false;
3574 Token.Unget_Token = false;
3575 Got_EOF = false;
3576 User_File->In_File = Input_File->In_File; // return control over pointer
3577 Input_File->In_File = Temp;
3578 Input_File->R_Flag = Temp_R_Flag;
3579
3580 return End_File ;
3581 }
3582
Parse_Write(void)3583 void Parser::Parse_Write(void)
3584 {
3585 char *temp;
3586 DATA_FILE *User_File;
3587 EXPRESS Express;
3588 int Terms;
3589
3590 GET(LEFT_PAREN_TOKEN)
3591 GET(FILE_ID_TOKEN)
3592
3593 User_File=(DATA_FILE *)Token.Data;
3594 if(User_File->Out_File == NULL)
3595 Error("Cannot write to file %s because the file is open for reading only.", UCS2toASCIIString(UCS2String(User_File->In_File->name())).c_str());
3596
3597 Parse_Comma();
3598
3599 EXPECT
3600 CASE5 (SINT8_TOKEN,SINT16BE_TOKEN,SINT16LE_TOKEN,SINT32BE_TOKEN,SINT32LE_TOKEN)
3601 CASE3 (UINT8_TOKEN,UINT16BE_TOKEN,UINT16LE_TOKEN)
3602 {
3603 signed long val_min;
3604 signed long val_max;
3605 int num_bytes;
3606 bool big_endian = false;
3607 switch (Token.Token_Id)
3608 {
3609 case SINT8_TOKEN: val_min = -128; val_max = 127; num_bytes = 1; break; // -2^7 to 2^7-1
3610 case UINT8_TOKEN: val_min = 0; val_max = 255; num_bytes = 1; break; // 0 to 2^8-1
3611 case SINT16BE_TOKEN: big_endian = true; // FALLTHROUGH
3612 case SINT16LE_TOKEN: val_min = -32768; val_max = 32767; num_bytes = 2; break; // -2^15 to 2^15-1
3613 case UINT16BE_TOKEN: big_endian = true; // FALLTHROUGH
3614 case UINT16LE_TOKEN: val_min = 0; val_max = 65535; num_bytes = 2; break; // 0 to 2^16-1
3615 case SINT32BE_TOKEN: big_endian = true; // FALLTHROUGH
3616 case SINT32LE_TOKEN: val_min = (-2147483647-1); val_max = 2147483647; num_bytes = 4; break; // -2^31 to 2^31-1 (using unconventional notation to avoid a warning with some compiler)
3617 }
3618 EXPECT
3619 CASE_VECTOR
3620 Terms = Parse_Unknown_Vector (Express);
3621 if ((Terms >= 1) && (Terms <= 5))
3622 {
3623 for (int i = 0; i < Terms; i ++)
3624 {
3625 signed long val;
3626 if (Express[i] <= val_min)
3627 val = val_min; // TODO - maybe we should warn the user
3628 else if (Express[i] >= val_max)
3629 val = val_max; // TODO - maybe we should warn the user
3630 else
3631 val = (signed long)(floor(Express[i]+0.5));
3632 for (int j = 0; j < num_bytes; j ++)
3633 {
3634 int bitShift = (big_endian? (num_bytes-1)-j : j) * 8;
3635 User_File->Out_File->putraw((val >> bitShift) & 0xFF);
3636 }
3637 }
3638 }
3639 else
3640 {
3641 Expectation_Error("expression");
3642 }
3643 END_CASE
3644 CASE (RIGHT_PAREN_TOKEN)
3645 UNGET
3646 EXIT
3647 END_CASE
3648 CASE (COMMA_TOKEN)
3649 UNGET
3650 EXIT
3651 END_CASE
3652 OTHERWISE
3653 Expectation_Error("expression");
3654 END_CASE
3655 END_EXPECT
3656 }
3657 END_CASE
3658
3659 CASE5 (STRING_LITERAL_TOKEN,CHR_TOKEN,SUBSTR_TOKEN,STR_TOKEN,VSTR_TOKEN)
3660 CASE5 (CONCAT_TOKEN,STRUPR_TOKEN,STRLWR_TOKEN,DATETIME_TOKEN,STRING_ID_TOKEN)
3661 UNGET
3662 temp=Parse_C_String();
3663 if(strlen(temp) > 512)
3664 {
3665 for(char *ptr = temp; *ptr != 0; ptr++)
3666 User_File->Out_File->printf("%c", *ptr);
3667 }
3668 else
3669 User_File->Out_File->printf("%s", temp);
3670 POV_FREE(temp);
3671 END_CASE
3672
3673 CASE_VECTOR
3674 Terms = Parse_Unknown_Vector (Express);
3675 switch (Terms)
3676 {
3677 case 1:
3678 User_File->Out_File->printf("%g",Express[X]);
3679 break;
3680
3681 case 2:
3682 User_File->Out_File->printf("<%g,%g> ",Express[U],Express[V]);
3683 break;
3684
3685 case 3:
3686 User_File->Out_File->printf("<%g,%g,%g> ",Express[X],Express[Y],Express[Z]);
3687 break;
3688
3689 case 4:
3690 User_File->Out_File->printf("<%g,%g,%g,%g> ",Express[X],Express[Y],Express[Z],Express[T]);
3691 break;
3692
3693 case 5:
3694 User_File->Out_File->printf("<%g,%g,%g,%g,%g> ",Express[X],Express[Y],Express[Z],Express[3],Express[4]);
3695 break;
3696
3697 default:
3698 Expectation_Error("expression");
3699 }
3700 END_CASE
3701
3702 CASE (RIGHT_PAREN_TOKEN)
3703 EXIT
3704 END_CASE
3705
3706 CASE (COMMA_TOKEN)
3707 END_CASE
3708
3709 OTHERWISE
3710 Expectation_Error("string");
3711 END_CASE
3712 END_EXPECT
3713 }
3714
Parse_Cond_Param(void)3715 DBL Parser::Parse_Cond_Param(void)
3716 {
3717 int Old_Ok = Ok_To_Declare;
3718 int Old_Sk = Skipping;
3719 DBL Val;
3720
3721 Ok_To_Declare = false;
3722 Skipping = false;
3723
3724 Val=Parse_Float_Param();
3725
3726 Ok_To_Declare = Old_Ok;
3727 Skipping = Old_Sk;
3728
3729 return(Val);
3730 }
3731
Parse_Cond_Param2(DBL * V1,DBL * V2)3732 void Parser::Parse_Cond_Param2(DBL *V1,DBL *V2)
3733 {
3734 int Old_Ok = Ok_To_Declare;
3735 int Old_Sk = Skipping;
3736
3737 Ok_To_Declare = false;
3738 Skipping = false;
3739
3740 Parse_Float_Param2(V1,V2);
3741
3742 Ok_To_Declare = Old_Ok;
3743 Skipping = Old_Sk;
3744 }
3745
Inc_CS_Index(void)3746 void Parser::Inc_CS_Index(void)
3747 {
3748 if (++CS_Index >= COND_STACK_SIZE)
3749 {
3750 Error("Too many nested conditionals or macros.");
3751 }
3752 Cond_Stack[CS_Index].Macro_File = NULL;
3753 Cond_Stack[CS_Index].Macro_Return_Name = NULL;
3754 Cond_Stack[CS_Index].PMac = NULL;
3755 Cond_Stack[CS_Index].Loop_File = NULL;
3756 Cond_Stack[CS_Index].Loop_Identifier = NULL;
3757 }
3758
Parse_Ifdef_Param(void)3759 int Parser::Parse_Ifdef_Param (void)
3760 {
3761 int Local_Index;
3762 SYM_ENTRY *Entry;
3763 int retval = false;
3764 int i,j,k;
3765 int c;
3766 DBL val;
3767 POV_ARRAY *a;
3768
3769 GET(LEFT_PAREN_TOKEN)
3770 Inside_Ifdef=true;
3771 Get_Token();
3772 String2 = POV_STRDUP(String);
3773 Inside_Ifdef=false;
3774
3775 /* Search tables from newest to oldest */
3776 for (Local_Index=Table_Index; Local_Index > 0; Local_Index--)
3777 {
3778 Entry = Find_Symbol(Local_Index,String2);
3779 if ( Entry != NULL)
3780 {
3781 Token.Token_Id = Entry->Token_Number;
3782 Token.is_array_elem = false;
3783 Token.NumberPtr = &(Entry->Token_Number);
3784 Token.DataPtr = &(Entry->Data);
3785
3786 if ( Token.Token_Id == PARAMETER_ID_TOKEN )
3787 {
3788 Token.NumberPtr = ((POV_PARAM *)(Entry->Data))->NumberPtr;
3789 Token.DataPtr = ((POV_PARAM *)(Entry->Data))->DataPtr;
3790 }
3791
3792 if (Token.NumberPtr && *(Token.NumberPtr)==ARRAY_ID_TOKEN)
3793 {
3794 Skip_Spaces();
3795 c = Echo_getc();
3796 Echo_ungetc(c);
3797
3798 if (c!='[')
3799 {
3800 retval = true;
3801 break;
3802 }
3803
3804 a = (POV_ARRAY *)(*(Token.DataPtr));
3805 j = 0;
3806
3807 for (i=0; i <= a->Dims; i++)
3808 {
3809 GET(LEFT_SQUARE_TOKEN)
3810 val=Parse_Float();
3811
3812 k=(int)(val + EPSILON);
3813
3814 if (k<0.0)
3815 {
3816 Error("Negative subscript");
3817 }
3818
3819 if (k>=a->Sizes[i])
3820 {
3821 Error("Array subscript out of range");
3822 }
3823 j += k * a->Mags[i];
3824 GET(RIGHT_SQUARE_TOKEN)
3825 }
3826
3827 Token.DataPtr = &(a->DataPtrs[j]);
3828 Token.NumberPtr = &(a->Type);
3829 Token.Token_Id = a->Type;
3830 Token.is_array_elem = true;
3831
3832 retval = (*Token.DataPtr != NULL);
3833 break;
3834 }
3835 else
3836 {
3837 retval = true;
3838 break;
3839 }
3840 }
3841 }
3842
3843 GET(RIGHT_PAREN_TOKEN)
3844
3845 POV_FREE(String2);
3846 String2 = NULL;
3847
3848 return retval;
3849 }
3850
Parse_For_Param(char ** IdentifierPtr,DBL * EndPtr,DBL * StepPtr)3851 int Parser::Parse_For_Param (char** IdentifierPtr, DBL* EndPtr, DBL* StepPtr)
3852 {
3853 int Previous=-1;
3854 SYM_ENTRY *Temp_Entry = NULL;
3855
3856 GET(LEFT_PAREN_TOKEN)
3857
3858 LValue_Ok = true;
3859
3860 EXPECT_ONE
3861 CASE (IDENTIFIER_TOKEN)
3862 if (Token.is_array_elem)
3863 Error("#for loop variable must not be an array element");
3864 Temp_Entry = Add_Symbol (Table_Index,Token.Token_String,IDENTIFIER_TOKEN);
3865 Token.NumberPtr = &(Temp_Entry->Token_Number);
3866 Token.DataPtr = &(Temp_Entry->Data);
3867 Previous = Token.Token_Id;
3868 END_CASE
3869
3870 CASE2 (FUNCT_ID_TOKEN, VECTFUNCT_ID_TOKEN)
3871 if (Token.is_array_elem)
3872 Error("#for loop variable must not be an array element");
3873 if((!Token.is_array_elem) || (*(Token.DataPtr) != NULL))
3874 Error("Redeclaring functions is not allowed - #undef the function first!");
3875 // fall through
3876
3877 // These have to match Parse_Declare in parse.cpp!
3878 CASE4 (TNORMAL_ID_TOKEN, FINISH_ID_TOKEN, TEXTURE_ID_TOKEN, OBJECT_ID_TOKEN)
3879 CASE4 (COLOUR_MAP_ID_TOKEN, TRANSFORM_ID_TOKEN, CAMERA_ID_TOKEN, PIGMENT_ID_TOKEN)
3880 CASE4 (SLOPE_MAP_ID_TOKEN, NORMAL_MAP_ID_TOKEN, TEXTURE_MAP_ID_TOKEN, COLOUR_ID_TOKEN)
3881 CASE4 (PIGMENT_MAP_ID_TOKEN, MEDIA_ID_TOKEN, STRING_ID_TOKEN, INTERIOR_ID_TOKEN)
3882 CASE4 (DENSITY_MAP_ID_TOKEN, ARRAY_ID_TOKEN, DENSITY_ID_TOKEN, UV_ID_TOKEN)
3883 CASE4 (VECTOR_4D_ID_TOKEN, RAINBOW_ID_TOKEN, FOG_ID_TOKEN, SKYSPHERE_ID_TOKEN)
3884 CASE2 (MATERIAL_ID_TOKEN, SPLINE_ID_TOKEN )
3885 if (Token.is_array_elem)
3886 Error("#for loop variable must not be an array element");
3887 if (Token.Table_Index != Table_Index)
3888 {
3889 Temp_Entry = Add_Symbol (Table_Index,Token.Token_String,IDENTIFIER_TOKEN);
3890 Token.NumberPtr = &(Temp_Entry->Token_Number);
3891 Token.DataPtr = &(Temp_Entry->Data);
3892 Previous = IDENTIFIER_TOKEN;
3893 }
3894 else
3895 {
3896 Previous = Token.Token_Id;
3897 }
3898 END_CASE
3899
3900 CASE (EMPTY_ARRAY_TOKEN)
3901 if (Token.is_array_elem)
3902 Error("#for loop variable must not be an array element");
3903 Previous = Token.Token_Id;
3904 END_CASE
3905
3906 CASE2 (VECTOR_FUNCT_TOKEN, FLOAT_FUNCT_TOKEN)
3907 if (Token.is_array_elem)
3908 Error("#for loop variable must not be an array element");
3909 switch(Token.Function_Id)
3910 {
3911 case VECTOR_ID_TOKEN:
3912 case FLOAT_ID_TOKEN:
3913 if (Token.Table_Index != Table_Index)
3914 {
3915 Temp_Entry = Add_Symbol (Table_Index,Token.Token_String,IDENTIFIER_TOKEN);
3916 Token.NumberPtr = &(Temp_Entry->Token_Number);
3917 Token.DataPtr = &(Temp_Entry->Data);
3918 }
3919 Previous = Token.Function_Id;
3920 break;
3921
3922 default:
3923 Parse_Error(IDENTIFIER_TOKEN);
3924 break;
3925 }
3926 END_CASE
3927
3928 OTHERWISE
3929 if (Token.is_array_elem)
3930 Error("#for loop variable must not be an array element");
3931 Parse_Error(IDENTIFIER_TOKEN);
3932 END_CASE
3933 END_EXPECT
3934
3935 LValue_Ok = false;
3936
3937 *Token.NumberPtr = FLOAT_ID_TOKEN;
3938 Test_Redefine(Previous,Token.NumberPtr,*Token.DataPtr, true);
3939 *Token.DataPtr = (void *) Create_Float();
3940 DBL* CurrentPtr = ((DBL *)*Token.DataPtr);
3941
3942 size_t len = strlen(Token.Token_String)+1;
3943 *IdentifierPtr = (char*)POV_MALLOC(len, "loop identifier");
3944 memcpy(*IdentifierPtr, Token.Token_String, len);
3945
3946 Parse_Comma();
3947 *CurrentPtr = Parse_Float();
3948 Parse_Comma();
3949 *EndPtr = Parse_Float();
3950 Parse_Comma();
3951 *StepPtr = Allow_Float(1.0);
3952
3953 if (fabs(*StepPtr) < EPSILON)
3954 Error ("#for loop increment must be non-zero.");
3955
3956 GET(RIGHT_PAREN_TOKEN)
3957
3958 return ((*StepPtr > 0) && (*CurrentPtr < *EndPtr + EPSILON)) ||
3959 ((*StepPtr < 0) && (*CurrentPtr > *EndPtr - EPSILON));
3960 }
3961
3962 /*****************************************************************************
3963 *
3964 * FUNCTION
3965 *
3966 * INPUT
3967 *
3968 * OUTPUT
3969 *
3970 * RETURNS
3971 *
3972 * AUTHOR
3973 *
3974 * DESCRIPTION
3975 *
3976 * CHANGES
3977 *
3978 ******************************************************************************/
3979
IncludeHeader(const UCS2String & temp)3980 void Parser::IncludeHeader(const UCS2String& temp)
3981 {
3982 UCS2String b;
3983
3984 if (temp.empty())
3985 return;
3986
3987 if (++Include_File_Index >= MAX_INCLUDE_FILES)
3988 {
3989 Include_File_Index--;
3990 Error ("Too many nested include files.");
3991 }
3992
3993 Echo_Indx = 0;
3994
3995 Input_File = &Include_Files[Include_File_Index];
3996 Input_File->In_File = NULL;
3997 IStream *is = Locate_File (this, sceneData, temp.c_str(),POV_File_Text_INC,b,true);
3998 if(is == NULL)
3999 {
4000 Input_File->In_File = NULL; /* Keeps from closing failed file. */
4001 Error ("Cannot open include header file %s.", UCS2toASCIIString(temp).c_str());
4002 }
4003 else
4004 Input_File->In_File = new ITextStream(b.c_str(), is);
4005
4006 Input_File->R_Flag=false;
4007
4008 Add_Sym_Table();
4009
4010 Token.Token_Id = END_OF_FILE_TOKEN;
4011 Token.is_array_elem = false;
4012 }
4013
4014 }
4015