home *** CD-ROM | disk | FTP | other *** search
/ Chestnut's Multimedia Mania / MM_MANIA.ISO / graphics / povsrc20 / tokenize.c < prev    next >
C/C++ Source or Header  |  1993-09-20  |  26KB  |  1,050 lines

  1. /****************************************************************************
  2. *                tokenize.c
  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. *  from Persistence of Vision Raytracer
  8. *  Copyright 1993 Persistence of Vision Team
  9. *---------------------------------------------------------------------------
  10. *  NOTICE: This source code file is provided so that users may experiment
  11. *  with enhancements to POV-Ray and to port the software to platforms other 
  12. *  than those supported by the POV-Ray Team.  There are strict rules under
  13. *  which you are permitted to use this file.  The rules are in the file
  14. *  named POVLEGAL.DOC which should be distributed with this file. If 
  15. *  POVLEGAL.DOC is not available or for more info please contact the POV-Ray
  16. *  Team Coordinator by leaving a message in CompuServe's Graphics Developer's
  17. *  Forum.  The latest version of POV-Ray may be found there as well.
  18. *
  19. * This program is based on the popular DKB raytracer version 2.12.
  20. * DKBTrace was originally written by David K. Buck.
  21. * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
  22. *
  23. *****************************************************************************/
  24.  
  25. #include <ctype.h>
  26. #include "frame.h"
  27. #include "povproto.h"
  28. #include "parse.h"
  29.  
  30. /* This module tokenizes the input file and sends the tokens created
  31. to the parser (the second stage).  Tokens sent to the parser contain a
  32. token ID, the line number of the token, and if necessary, some data for
  33. the token.  */
  34.  
  35. char String[MAX_STRING_INDEX];
  36. int String_Index;
  37. extern char Library_Path[];
  38. extern int Stop_Flag;
  39. static int pov_stricmp PARAMS ((char *s1,char *s2));
  40.  
  41. /* Here are the reserved words.  If you need to add new words, be sure
  42. to declare them in frame.h */
  43.  
  44.   struct Reserved_Word_Struct Reserved_Words [LAST_TOKEN] = {
  45.   ADAPTIVE_TOKEN, "adaptive",
  46.   AGATE_TOKEN, "agate",
  47.   AGATE_TURB_TOKEN, "agate_turb",
  48.   ALL_TOKEN, "all",
  49.   ALPHA_TOKEN, "alpha",
  50.   AMBIENT_TOKEN, "ambient",
  51.   AMPERSAND_TOKEN, "&",
  52.   AREA_LIGHT_TOKEN, "area_light",
  53.   AT_TOKEN, "@",
  54.   BACKGROUND_TOKEN, "background",
  55.   BACK_QUOTE_TOKEN, "`",
  56.   BACK_SLASH_TOKEN, "\\",
  57.   BAR_TOKEN, "|",
  58.   BICUBIC_PATCH_TOKEN, "bicubic_patch",
  59.   BLOB_TOKEN, "blob",
  60.   BLUE_TOKEN, "blue",
  61.   BOUNDED_BY_TOKEN, "bounded_by",
  62.   BOX_TOKEN, "box",
  63.   BOZO_TOKEN, "bozo",
  64.   BRICK_TOKEN, "brick",
  65.   BRILLIANCE_TOKEN, "brilliance",
  66.   BUMPS_TOKEN, "bumps",
  67.   BUMPY1_TOKEN, "bumpy1",
  68.   BUMPY2_TOKEN, "bumpy2",
  69.   BUMPY3_TOKEN, "bumpy3",
  70.   BUMP_MAP_TOKEN, "bump_map",
  71.   BUMP_SIZE_TOKEN, "bump_size",
  72.   CAMERA_ID_TOKEN, "camera identifier",
  73.   CAMERA_TOKEN, "camera",
  74.   CHECKER_TOKEN, "checker",
  75.   CLIPPED_BY_TOKEN, "clipped_by",
  76.   CLOCK_TOKEN,"clock",
  77.   COLON_TOKEN, ":",
  78.   COLOUR_ID_TOKEN, "colour identifier", 
  79.   COLOUR_MAP_ID_TOKEN, "colour map identifier",
  80.   COLOUR_MAP_TOKEN, "color_map",
  81.   COLOUR_MAP_TOKEN, "colour_map",
  82.   COLOUR_TOKEN, "color",
  83.   COLOUR_TOKEN, "colour",
  84.   COMMA_TOKEN, ",",
  85.   COMPONENT_TOKEN, "component",
  86.   COMPOSITE_TOKEN, "composite",
  87.   CONE_TOKEN, "cone",
  88.   CRAND_TOKEN, "crand",
  89.   CUBIC_TOKEN, "cubic",
  90.   CYLINDER_TOKEN, "cylinder",
  91.   DASH_TOKEN, "-",
  92.   DECLARE_TOKEN, "declare",
  93.   DEFAULT_TOKEN, "default",
  94.   DENTS_TOKEN, "dents",
  95.   DIFFERENCE_TOKEN, "difference",
  96.   DIFFUSE_TOKEN, "diffuse",
  97.   DIRECTION_TOKEN, "direction",
  98.   DISC_TOKEN, "disc",
  99.   DISTANCE_TOKEN, "distance",
  100.   DOLLAR_TOKEN, "$",
  101.   DUMP_TOKEN, "dump",
  102.   END_OF_FILE_TOKEN, "End of File",
  103.   EQUALS_TOKEN, "=",
  104.   EXCLAMATION_TOKEN, "!",
  105.   FALLOFF_TOKEN, "falloff",
  106.   FILTER_TOKEN, "filter",
  107.   FINISH_ID_TOKEN, "finish identifier",
  108.   FINISH_TOKEN, "finish",
  109.   FLATNESS_TOKEN, "flatness",
  110.   FLOAT_ID_TOKEN, "float identifier",
  111.   FLOAT_TOKEN, "float constant",
  112.   FOG_TOKEN, "fog",
  113.   FREQUENCY_TOKEN, "frequency",
  114.   GIF_TOKEN, "gif",
  115.   GRADIENT_TOKEN, "gradient",
  116.   GRANITE_TOKEN, "granite",
  117.   GREEN_TOKEN, "green",
  118.   HASH_TOKEN, "#",
  119.   HAT_TOKEN, "^",
  120.   HEIGHT_FIELD_TOKEN, "height_field",
  121.   HEXAGON_TOKEN, "hexagon",
  122.   IDENTIFIER_TOKEN, "undeclared identifier",
  123.   IFF_TOKEN, "iff",
  124.   IMAGE_MAP_TOKEN, "image_map",
  125.   INCLUDE_TOKEN, "include",
  126.   INTERPOLATE_TOKEN, "interpolate",
  127.   INTERSECTION_TOKEN, "intersection",
  128.   INVERSE_TOKEN, "inverse",
  129.   IOR_TOKEN, "ior",
  130.   JITTER_TOKEN, "jitter",
  131.   LAMBDA_TOKEN, "lambda",
  132.   LEFT_ANGLE_TOKEN, "<",
  133.   LEFT_CURLY_TOKEN, "{",
  134.   LEFT_PAREN_TOKEN, "(",
  135.   LEFT_SQUARE_TOKEN, "[",
  136.   LEOPARD_TOKEN, "leopard",
  137.   LIGHT_SOURCE_TOKEN, "light_source",
  138.   LOCATION_TOKEN, "location",
  139.   LOOKS_LIKE_TOKEN, "looks_like",
  140.   LOOK_AT_TOKEN, "look_at",
  141.   MANDEL_TOKEN,"mandel",
  142.   MAP_TYPE_TOKEN, "map_type",
  143.   MARBLE_TOKEN, "marble",
  144.   MATERIAL_MAP_TOKEN, "material_map",
  145.   MAX_INTERSECTIONS, "max_intersections",
  146.   MAX_TRACE_LEVEL_TOKEN, "max_trace_level",
  147.   MERGE_TOKEN,"merge",
  148.   METALLIC_TOKEN, "metallic",
  149.   MORTAR_TOKEN, "mortar",
  150.   NO_SHADOW_TOKEN, "no_shadow",
  151.   OBJECT_ID_TOKEN, "object identifier",
  152.   OBJECT_TOKEN, "object",
  153.   OCTAVES_TOKEN, "octaves",
  154.   OMEGA_TOKEN, "omega",
  155.   ONCE_TOKEN, "once",
  156.   ONION_TOKEN, "onion",
  157.   OPEN_TOKEN, "open",
  158.   PAINTED1_TOKEN, "painted1",
  159.   PAINTED2_TOKEN, "painted2",
  160.   PAINTED3_TOKEN, "painted3",
  161.   PERCENT_TOKEN, "%",
  162.   PHASE_TOKEN, "phase",
  163.   PHONG_SIZE_TOKEN, "phong_size",
  164.   PHONG_TOKEN, "phong",
  165.   PIGMENT_ID_TOKEN, "pigment identifier",
  166.   PIGMENT_TOKEN, "pigment",
  167.   PLANE_TOKEN, "plane",
  168.   PLUS_TOKEN, "+",
  169.   POINT_AT_TOKEN, "point_at",
  170.   POLY_TOKEN, "poly",
  171.   POT_TOKEN, "pot",
  172.   QUADRIC_TOKEN, "quadric",
  173.   QUARTIC_TOKEN, "quartic",
  174.   QUESTION_TOKEN, "?",
  175.   QUICK_COLOUR_TOKEN,"quick_color",
  176.   QUICK_COLOUR_TOKEN,"quick_colour",
  177.   RADIAL_TOKEN, "radial",
  178.   RADIUS_TOKEN, "radius",
  179.   RAW_TOKEN, "raw",
  180.   RED_TOKEN, "red",
  181.   REFLECTION_TOKEN, "reflection",
  182.   REFRACTION_TOKEN, "refraction",
  183.   RGBF_TOKEN,"rgbf",
  184.   RGB_TOKEN,"rgb",
  185.   RIGHT_ANGLE_TOKEN, ">",
  186.   RIGHT_CURLY_TOKEN, "}",
  187.   RIGHT_PAREN_TOKEN, ")",
  188.   RIGHT_SQUARE_TOKEN, "]",
  189.   RIGHT_TOKEN, "right",
  190.   RIPPLES_TOKEN, "ripples",
  191.   ROTATE_TOKEN, "rotate",
  192.   ROUGHNESS_TOKEN, "roughness",
  193.   SCALE_TOKEN, "scale",
  194.   SEMI_COLON_TOKEN, ";",
  195.   SINGLE_QUOTE_TOKEN, "'",
  196.   SKY_TOKEN, "sky",
  197.   SLASH_TOKEN, "/",
  198.   SMOOTH_TOKEN,"smooth",
  199.   SMOOTH_TRIANGLE_TOKEN, "smooth_triangle",
  200.   SPECULAR_TOKEN, "specular",
  201.   SPHERE_TOKEN, "sphere",
  202.   SPOTLIGHT_TOKEN, "spotlight",
  203.   SPOTTED_TOKEN, "spotted",
  204.   STAR_TOKEN, "*",
  205.   STRING_TOKEN, "string",
  206.   STURM_TOKEN, "sturm",
  207.   TEXTURE_ID_TOKEN, "texture identifier",
  208.   TEXTURE_TOKEN, "texture",
  209.   TGA_TOKEN, "tga",
  210.   THRESHOLD_TOKEN, "threshold",
  211.   TIGHTNESS_TOKEN, "tightness",
  212.   TILDE_TOKEN, "~",
  213.   TILE2_TOKEN, "tile2",
  214.   TILES_TOKEN, "tiles",
  215.   TNORMAL_ID_TOKEN, "normal identifier",
  216.   TNORMAL_TOKEN, "normal",
  217.   TORUS_TOKEN, "torus",
  218.   TRACK_TOKEN, "track",
  219.   TRANSFORM_ID_TOKEN, "transform identifier",
  220.   TRANSFORM_TOKEN, "transform",
  221.   TRANSLATE_TOKEN, "translate",
  222.   TRIANGLE_TOKEN, "triangle",
  223.   TURBULENCE_TOKEN, "turbulence",
  224.   TYPE_TOKEN, "type",
  225.   UNION_TOKEN, "union",
  226.   UP_TOKEN, "up",
  227.   USE_COLOUR_TOKEN,"use_color",
  228.   USE_COLOUR_TOKEN,"use_colour",
  229.   USE_INDEX_TOKEN,"use_index",
  230.   U_STEPS_TOKEN, "u_steps",
  231.   VECTOR_ID_TOKEN, "vector identifier",
  232.   VERSION_TOKEN, "version",
  233.   V_STEPS_TOKEN, "v_steps",
  234.   WATER_LEVEL_TOKEN, "water_level",
  235.   WAVES_TOKEN, "waves",
  236.   WOOD_TOKEN, "wood",
  237.   WRINKLES_TOKEN, "wrinkles",
  238.   X_TOKEN,"x",
  239.   Y_TOKEN,"y",
  240.   Z_TOKEN,"z"
  241.   };
  242.  
  243. /* Make a table for user-defined symbols.  500 symbols should be more
  244. than enough. */
  245.  
  246. /* Now defined in POVRAY.c */
  247. /* #define MAX_SYMBOLS 500 */
  248. extern int Max_Symbols;
  249.  
  250. int token_count = 0, line_count = 10; /* moved here to allow reinitialization */
  251.  
  252. char **Symbol_Table;
  253. int Number_Of_Symbols;
  254. extern int Case_Sensitive_Flag; /* defined & init in pvray.c */
  255. extern unsigned int Options;
  256.  
  257. #define MAX_INCLUDE_FILES 10
  258.  
  259. DATA_FILE Include_Files[MAX_INCLUDE_FILES];
  260. int Include_File_Index;
  261. DATA_FILE *Data_File;
  262.  
  263. struct Token_Struct Token;
  264.  
  265. #define CALL(x) { if (!(x)) return (FALSE); }
  266.  
  267. void Initialize_Tokenizer(filename)
  268. char *filename;
  269.   {
  270.   Symbol_Table = NULL;
  271.   Data_File = NULL;
  272.  
  273.   Include_File_Index = 0;
  274.   Data_File = &Include_Files[0];
  275.  
  276.   Data_File->File = Locate_File (filename, "r");
  277.   if (Data_File->File == NULL)
  278.     {
  279.     fprintf (stderr, "Cannot open input file\n");
  280.     exit(1);
  281.     }
  282.  
  283.   Data_File->Filename = malloc(strlen(filename) + 1);
  284.   strcpy (Data_File->Filename, filename);
  285.   Data_File->Line_Number = 0;
  286.  
  287.   if ((Symbol_Table = (char **) malloc (Max_Symbols * sizeof (char *))) == NULL) 
  288.     MAError("symbol table");
  289.  
  290.   Token.Token_Line_No = 0;
  291.   Token.Token_String  = NULL;
  292.   Token.Unget_Token   = FALSE;
  293.   Token.End_Of_File   = FALSE;
  294.   Token.Filename      = NULL;
  295.   Token.Constant_Data = NULL;
  296.  
  297.   Number_Of_Symbols = 0;
  298.   }
  299.  
  300.  
  301. void Terminate_Tokenizer()
  302.   {
  303.   int i;
  304.  
  305.   if (Symbol_Table != NULL)
  306.     {
  307.     for (i = 1 ; i < Number_Of_Symbols ; i++)
  308.       free(Symbol_Table[i]);
  309.     free (Symbol_Table);
  310.     }
  311.  
  312.   if (Data_File != NULL)
  313.     {
  314.     fclose (Data_File->File);
  315.     free (Data_File->Filename);
  316.     }
  317.   }
  318.  
  319. /* The main tokenizing routine.  Set up the files and continue parsing
  320. until the end of file */
  321.  
  322. /* This function performs most of the work involved in tokenizing.  It
  323.    reads the first character of the token and decides which function to
  324.    call to tokenize the rest.  For simple tokens, it simply writes them
  325.    out to the token buffer.  */
  326.  
  327. /* Read a token from the input file and store it in the Token variable.
  328. If the token is an INCLUDE token, then set the include file name and
  329. read another token. */
  330.  
  331. void Get_Token ()
  332.   {
  333.   register int c,c2;
  334.  
  335.   if (Token.Unget_Token)
  336.     {
  337.     Token.Unget_Token = FALSE;
  338.     return;
  339.     }
  340.  
  341.   if (Token.End_Of_File)
  342.     return;
  343.  
  344.  
  345.   Token.Token_Id = END_OF_FILE_TOKEN;
  346.  
  347.   while (Token.Token_Id == END_OF_FILE_TOKEN)
  348.     {
  349.     Skip_Spaces (Data_File);
  350.  
  351.     c = getc(Data_File->File);
  352.     if (c == EOF)
  353.       {
  354.       if (Include_File_Index == 0)
  355.         {
  356.         Token.Token_Id = END_OF_FILE_TOKEN;
  357.         Token.End_Of_File = TRUE;
  358.         /*putchar ('\n');*/
  359.         fprintf (stderr,"\n");
  360.         return;
  361.         }
  362.       fclose(Data_File->File); /* added to fix open file buildup JLN 12/91 */
  363.       Data_File = &Include_Files[--Include_File_Index];
  364.       continue;
  365.       }
  366.  
  367.     String[0] = '\0';
  368.     String_Index  = 0;
  369.  
  370.     switch (c)
  371.     {
  372.     case '\n': 
  373.       Data_File->Line_Number++;
  374.       COOPERATE
  375.       break;
  376.  
  377.     case '{' : 
  378.       Write_Token (LEFT_CURLY_TOKEN, Data_File);
  379.       break;
  380.  
  381.     case '}' : 
  382.       Write_Token (RIGHT_CURLY_TOKEN, Data_File);
  383.       break;
  384.  
  385.     case '@' : 
  386.       Write_Token (AT_TOKEN, Data_File);
  387.       break;
  388.  
  389.     case '&' : 
  390.       Write_Token (AMPERSAND_TOKEN, Data_File);
  391.       break;
  392.  
  393.     case '`' : 
  394.       Write_Token (BACK_QUOTE_TOKEN, Data_File);
  395.       break;
  396.  
  397.     case '\\': 
  398.       Write_Token (BACK_SLASH_TOKEN, Data_File);
  399.       break;
  400.  
  401.     case '|' : 
  402.       Write_Token (BAR_TOKEN, Data_File);
  403.       break;
  404.  
  405.     case ':' : 
  406.       Write_Token (COLON_TOKEN, Data_File);
  407.       break;
  408.  
  409.     case ',' : 
  410.       Write_Token (COMMA_TOKEN, Data_File);
  411.       break;
  412.  
  413.     case '-' : 
  414.       Write_Token (DASH_TOKEN, Data_File);
  415.       break;
  416.  
  417.     case '$' : 
  418.       Write_Token (DOLLAR_TOKEN, Data_File);
  419.       break;
  420.  
  421.     case '=' : 
  422.       Write_Token (EQUALS_TOKEN, Data_File);
  423.       break;
  424.  
  425.     case '!' : 
  426.       Write_Token (EXCLAMATION_TOKEN, Data_File);
  427.       break;
  428.  
  429.     case '#' : /* Parser doesn't use it, so let's ignore it */
  430.       /* Write_Token (HASH_TOKEN, Data_File); */
  431.       break;
  432.  
  433.     case '^' : 
  434.       Write_Token (HAT_TOKEN, Data_File);
  435.       break;
  436.  
  437.     case '<' : 
  438.       Write_Token (LEFT_ANGLE_TOKEN, Data_File);
  439.       break;
  440.  
  441.     case '(' : 
  442.       Write_Token (LEFT_PAREN_TOKEN, Data_File);
  443.       break;
  444.  
  445.     case '[' : 
  446.       Write_Token (LEFT_SQUARE_TOKEN, Data_File);
  447.       break;
  448.  
  449.     case '%' : 
  450.       Write_Token (PERCENT_TOKEN, Data_File);
  451.       break;
  452.  
  453.     case '+' : 
  454.       Write_Token (PLUS_TOKEN, Data_File);
  455.       break;
  456.  
  457.     case '?' : 
  458.       Write_Token (QUESTION_TOKEN, Data_File);
  459.       break;
  460.  
  461.     case '>' : 
  462.       Write_Token (RIGHT_ANGLE_TOKEN, Data_File);
  463.       break;
  464.  
  465.     case ')' : 
  466.       Write_Token (RIGHT_PAREN_TOKEN, Data_File);
  467.       break;
  468.  
  469.     case ']' : 
  470.       Write_Token (RIGHT_SQUARE_TOKEN, Data_File);
  471.       break;
  472.  
  473.     case ';' : /* Parser doesn't use it, so let's ignore it */
  474.       /* Write_Token (SEMI_COLON_TOKEN, Data_File); */
  475.       break;
  476.  
  477.     case '\'': 
  478.       Write_Token (SINGLE_QUOTE_TOKEN, Data_File);
  479.       break;
  480.  
  481.       /* enable C++ style commenting */
  482.     case '/' :
  483.       c2 = getc(Data_File->File);
  484.       if(c2 != (int) '/' && c2 != (int) '*')
  485.         {
  486.         ungetc(c2,Data_File->File);
  487.         Write_Token (SLASH_TOKEN, Data_File);
  488.         break;
  489.         }          
  490.       if(c2 == (int)'*')
  491.         {
  492.         Parse_C_Comments(Data_File);
  493.         break;
  494.         }           
  495.       while(c2 != (int)'\n')
  496.         {
  497.         c2=getc(Data_File->File);
  498.         if(c2==EOF)
  499.           {
  500.           ungetc(c2,Data_File->File);
  501.           break;
  502.           }
  503.         }
  504.       Data_File->Line_Number++;
  505.       COOPERATE
  506.       break;
  507.  
  508.     case '*' : 
  509.       Write_Token (STAR_TOKEN, Data_File);
  510.       break;
  511.  
  512.     case '~' : 
  513.       Write_Token (TILDE_TOKEN, Data_File);
  514.       break;
  515.  
  516.     case '"' : 
  517.       Parse_String (Data_File);
  518.       break;
  519.  
  520.     case '0':   
  521.     case '1':   
  522.     case '2':   
  523.     case '3':   
  524.     case '4':   
  525.     case '5':
  526.     case '6':   
  527.     case '7':   
  528.     case '8':   
  529.     case '9':   
  530.     case '.':
  531.       ungetc (c, Data_File->File);
  532.       if (Read_Float (Data_File) != TRUE)
  533.         return;
  534.       break;
  535.  
  536.     case 'a': 
  537.     case 'b': 
  538.     case 'c': 
  539.     case 'd': 
  540.     case 'e': 
  541.     case 'f': 
  542.     case 'g':
  543.     case 'h': 
  544.     case 'i': 
  545.     case 'j': 
  546.     case 'k': 
  547.     case 'l': 
  548.     case 'm': 
  549.     case 'n':
  550.     case 'o': 
  551.     case 'p': 
  552.     case 'q': 
  553.     case 'r': 
  554.     case 's': 
  555.     case 't': 
  556.     case 'u':
  557.     case 'v': 
  558.     case 'w': 
  559.     case 'x': 
  560.     case 'y': 
  561.     case 'z':
  562.  
  563.     case 'A': 
  564.     case 'B': 
  565.     case 'C': 
  566.     case 'D': 
  567.     case 'E': 
  568.     case 'F': 
  569.     case 'G':
  570.     case 'H': 
  571.     case 'I': 
  572.     case 'J': 
  573.     case 'K': 
  574.     case 'L': 
  575.     case 'M': 
  576.     case 'N':
  577.     case 'O': 
  578.     case 'P': 
  579.     case 'Q': 
  580.     case 'R': 
  581.     case 'S': 
  582.     case 'T': 
  583.     case 'U':
  584.     case 'V': 
  585.     case 'W': 
  586.     case 'X': 
  587.     case 'Y': 
  588.     case 'Z': 
  589.     case '_':
  590.       ungetc (c, Data_File->File);
  591.       if (Read_Symbol (Data_File) != TRUE)
  592.         return;
  593.       break;
  594.     case '\t':
  595.     case '\r':
  596.     case '\032':   /* Control Z - EOF on many systems */
  597.     case '\0': 
  598.       break;
  599.  
  600.     default:
  601.       fprintf (stderr, "Error in %s line %d\n", Data_File->Filename, Data_File->Line_Number+1);
  602.       fprintf (stderr, "Illegal character in input file, value is %02x\n", c);
  603.       break;
  604.     }
  605.  
  606.     if (Token.Token_Id == INCLUDE_TOKEN)
  607.       {
  608.       if (Skip_Spaces (Data_File) != TRUE)
  609.         Token_Error (Data_File, "Expecting a string after INCLUDE\n");
  610.  
  611.       if ((c = getc(Data_File->File)) != '"')
  612.         Token_Error (Data_File, "Expecting a string after INCLUDE\n");
  613.  
  614.       Parse_String(Data_File);
  615.       Include_File_Index++;
  616.       if (Include_File_Index > MAX_INCLUDE_FILES)
  617.         Token_Error (Data_File, "Too many nested include files\n");
  618.  
  619.       Data_File = &Include_Files[Include_File_Index];
  620.       Data_File->Line_Number = 0;
  621.  
  622.       Data_File->Filename = malloc(strlen(Token.Token_String) + 1);
  623.       if (Data_File->Filename == NULL) 
  624.         MAError("opening include file");
  625.  
  626.       strcpy (Data_File->Filename, Token.Token_String);
  627.  
  628.       if ((Data_File->File = Locate_File (Token.Token_String, "r")) == NULL) 
  629.         {
  630.         fprintf (stderr, "Cannot open include file: %s\n", Token.Token_String);
  631.         exit(1);
  632.         }
  633.       Token.Token_Id = END_OF_FILE_TOKEN;
  634.       }
  635.  
  636.     }
  637.  
  638.   /*   fprintf(stderr," %s ",Token.Token_String); */
  639.   token_count++;
  640.   if (token_count > 1000)
  641.     {
  642.     token_count = 0;
  643.     COOPERATE
  644.     Check_User_Abort(0);
  645.     fprintf(stderr,".");
  646.     fflush(stderr);
  647.     line_count++;
  648.     if (line_count > 78)
  649.       {
  650.       line_count = 0;
  651.       fprintf (stderr,"\n");
  652.       }
  653.     }
  654.   return;
  655.   }
  656.  
  657.  
  658. /* Mark that the token has been put back into the input stream.  The next
  659. call to Get_Token will return the last-read token instead of reading a
  660. new one from the file. */
  661.  
  662. void Unget_Token ()
  663.   {
  664.   Token.Unget_Token = TRUE;
  665.   }
  666.  
  667. /* Skip over spaces in the input file */
  668.  
  669. int Skip_Spaces (Data_File)
  670. DATA_FILE *Data_File;
  671.   {
  672.   register int c;
  673.  
  674.   while (TRUE)
  675.     {
  676.     c = getc(Data_File->File);
  677.     if (c == EOF)
  678.       return (FALSE);
  679.  
  680.     if (!(isspace(c) || c == 0x0A))
  681.       break;
  682.  
  683.     if (c == '\n')
  684.       {
  685.        Data_File->Line_Number++;
  686.        COOPERATE
  687.       }
  688.     }
  689.  
  690.   ungetc (c, Data_File->File);
  691.   return (TRUE);
  692.   }
  693.  
  694. /* C style comments with asterik and slash - CdW 8/91 */
  695.  
  696. int Parse_C_Comments (Data_File)
  697. DATA_FILE *Data_File;
  698.   {
  699.   register int c,c2;
  700.   int End_Of_Comment;
  701.  
  702.   End_Of_Comment = FALSE;
  703.   while (!End_Of_Comment)
  704.     {
  705.     c = getc (Data_File->File);
  706.     if (c == EOF)
  707.       {
  708.       Token_Error (Data_File, "No */ closing comment found");
  709.       return (FALSE);
  710.       }
  711.  
  712.     if (c == (int) '\n')
  713.       {
  714.        Data_File->Line_Number++;
  715.        COOPERATE
  716.       }
  717.  
  718.     if (c == (int) '*')
  719.       {
  720.       c2= getc(Data_File->File);
  721.       if(c2 != (int) '/')
  722.         ungetc(c2,Data_File->File);
  723.       else
  724.         End_Of_Comment = TRUE;
  725.       }
  726.  
  727.     /* Check for and handle nested comments */
  728.     if (c == (int) '/')
  729.       {
  730.       c2= getc(Data_File->File);
  731.       if(c2 != (int) '*')
  732.         ungetc(c2,Data_File->File);
  733.       else 
  734.         Parse_C_Comments(Data_File);
  735.       }
  736.     }
  737.  
  738.   return (TRUE);
  739.   }
  740.  
  741. /* The following routines make it easier to handle strings.  They stuff
  742.    characters into a string buffer one at a time making all the proper
  743.    range checks.  Call Begin_String to start, Stuff_Character to put
  744.    characters in, and End_String to finish.  The String variable contains
  745.    the final string. */
  746.  
  747. void Begin_String()
  748.   {
  749.   String_Index = 0;
  750.   }
  751.  
  752. void Stuff_Character (c, Data_File)
  753. int c;
  754. DATA_FILE *Data_File;
  755.   {
  756.   if (String_Index < MAX_STRING_INDEX)
  757.     {
  758.     String [String_Index++] = (char) c;
  759.     if (String_Index >= MAX_STRING_INDEX)
  760.       {
  761.       Token_Error (Data_File, "String too long");
  762.       String [String_Index-1] = '\0';
  763.       }
  764.     }
  765.   }
  766.  
  767. void End_String (Data_File)
  768. DATA_FILE *Data_File;
  769.   {
  770.   Stuff_Character ((int) '\0', Data_File);
  771.   }
  772.  
  773. /* Read a float from the input file and tokenize it as one token. The phase
  774.    variable is 0 for the first character, 1 for all subsequent characters
  775.    up to the decimal point, 2 for all characters after the decimal
  776.    point, 3 for the E+/- and 4 for the exponent.  This helps to insure
  777.    that the number is formatted properly. E format added 9/91 CEY */
  778.  
  779. int Read_Float(Data_File)
  780. DATA_FILE *Data_File;
  781.   {
  782.   register int c, Finished, Phase;
  783.  
  784.   Finished = FALSE;
  785.   Phase = 0;
  786.  
  787.   Begin_String();
  788.   while (!Finished)
  789.     {
  790.     c = getc(Data_File->File);
  791.     if (c == EOF)
  792.       {
  793.       Token_Error (Data_File, "Unexpected end of file");
  794.       return (FALSE);
  795.       }
  796.  
  797.     switch (Phase)
  798.     {
  799.     case 0: 
  800.       if (isdigit(c))
  801.         Stuff_Character(c, Data_File);
  802.       else
  803.         if (c == '.') 
  804.         {
  805.         Stuff_Character('0', Data_File);
  806.         ungetc (c, Data_File->File);
  807.         }
  808.         else
  809.           Token_Error (Data_File, "Error in decimal number");
  810.       Phase = 1;
  811.       break;
  812.  
  813.     case 1: 
  814.       if (isdigit(c))
  815.         Stuff_Character(c, Data_File);
  816.       else if (c == (int) '.')
  817.         {
  818.         Stuff_Character(c, Data_File); Phase = 2;
  819.         }
  820.       else
  821.         if ((c == 'e') || (c == 'E'))
  822.           {
  823.           Stuff_Character(c, Data_File); Phase = 3;
  824.           }
  825.         else Finished = TRUE;
  826.       break;
  827.  
  828.       case 2: 
  829.         if (isdigit(c))
  830.           Stuff_Character(c, Data_File);
  831.         else if ((c == 'e') || (c == 'E'))
  832.           {
  833.           Stuff_Character(c, Data_File); Phase = 3;
  834.           }
  835.         else Finished = TRUE;
  836.       break;
  837.  
  838.       case 3: 
  839.         if (isdigit(c) || (c == '+') || (c == '-'))
  840.           {
  841.           Stuff_Character(c, Data_File); Phase = 4;
  842.           }
  843.         else Finished = TRUE;
  844.       break;
  845.  
  846.       case 4: 
  847.         if (isdigit(c))
  848.           Stuff_Character(c, Data_File);
  849.         else Finished = TRUE;
  850.       break;
  851.     }
  852.     }
  853.  
  854.     ungetc (c, Data_File->File);
  855.   End_String(Data_File);
  856.  
  857.   Write_Token (FLOAT_TOKEN, Data_File);
  858.   if (sscanf (String, DBL_FORMAT_STRING, &Token.Token_Float) == 0)
  859.     return (FALSE);
  860.  
  861.   return (TRUE);
  862.   }
  863.  
  864. /* Parse a string from the input file into a token. */
  865. void Parse_String (Data_File)
  866. DATA_FILE *Data_File;
  867.   {
  868.   register int c;
  869.  
  870.   Begin_String();
  871.   while (TRUE)
  872.     {
  873.     c = getc(Data_File->File);
  874.     if (c == EOF)
  875.       Token_Error (Data_File, "No end quote for string");
  876.  
  877.     if (c != (int) '"')
  878.       Stuff_Character (c, Data_File);
  879.     else
  880.       break;
  881.     }
  882.   End_String(Data_File);
  883.  
  884.   Write_Token (STRING_TOKEN, Data_File);
  885.   Token.Token_String = String;
  886.   }
  887.  
  888. /* Read in a symbol from the input file.  Check to see if it is a reserved
  889.    word.  If it is, write out the appropriate token.  Otherwise, write the
  890.    symbol out to the Symbol file and write out an IDENTIFIER token. An
  891.    Identifier token is a token whose token number is greater than the
  892.    highest reserved word. */
  893.  
  894. int Read_Symbol (Data_File)
  895. DATA_FILE *Data_File;
  896.   {
  897.   register int c, Symbol_Id;
  898.  
  899.   Begin_String();
  900.   while (TRUE)
  901.     {
  902.     c = getc(Data_File->File);
  903.     if (c == EOF)
  904.       {
  905.       Token_Error (Data_File, "Unexpected end of file");
  906.       return (FALSE);
  907.       }
  908.  
  909.     if (isalpha(c) || isdigit(c) || c == (int) '_')
  910.       Stuff_Character (c, Data_File);
  911.     else
  912.       {
  913.       ungetc (c, Data_File->File);
  914.       break;
  915.       }
  916.     }
  917.   End_String(Data_File);
  918.  
  919.   /* Ignore the symbol if it was meant for the tokenizer (-2) */
  920.   if ((Symbol_Id = Find_Reserved()) != -1 && Symbol_Id != -2)
  921.     Write_Token (Symbol_Id, Data_File);
  922.   else
  923.     {
  924.     /* Ignore the symbol if it was meant for the tokenizer (-2) */
  925.     if (Symbol_Id==-2)
  926.       return(TRUE);
  927.  
  928.     if ((Symbol_Id = Find_Symbol()) == -1)
  929.       if (++Number_Of_Symbols < Max_Symbols)
  930.         {
  931.         if ((Symbol_Table[Number_Of_Symbols] =
  932.           malloc (strlen(String)+1)) == NULL)
  933.           Token_Error (Data_File, "Out of Memory. Cannot allocate space for identifier");
  934.  
  935.         strcpy (Symbol_Table[Number_Of_Symbols], String);
  936.         Symbol_Id = Number_Of_Symbols;
  937.         }
  938.       else
  939.         {
  940.         fprintf (stderr, "\nToo many symbols. Use +ms### option to raise Max_Symbols\n");
  941.         exit(1);
  942.         }
  943.  
  944.     Write_Token (LAST_TOKEN + Symbol_Id, Data_File);
  945.     }
  946.  
  947.   return (TRUE);
  948.   }
  949.  
  950. /* Return the index the token in the reserved words table or -1 if it
  951.    isn't there. */
  952.  
  953. int Find_Reserved ()
  954.   {
  955.   register int i;
  956.  
  957.   if (pov_stricmp ("case_sensitive_yes", &(String[0])) == 0)
  958.     {
  959.     Case_Sensitive_Flag = 0;
  960.     return (-2);
  961.     }
  962.   else
  963.     if (pov_stricmp ("case_sensitive_no", &(String[0])) == 0)
  964.       {
  965.       Case_Sensitive_Flag = 1;
  966.       return (-2);
  967.       }
  968.   /* The optional case sensitive option only checks keywords
  969.              unsensitive.  Symbols can be upper/lower, but not be the
  970.              same as a keyword */
  971.     else
  972.       if (pov_stricmp ("case_sensitive_opt", &(String[0])) == 0)
  973.         {
  974.         Case_Sensitive_Flag = 2;
  975.         return (-2);
  976.         }
  977.  
  978.   for (i = 0 ; i < LAST_TOKEN ; i++)
  979.     if(Case_Sensitive_Flag==0)
  980.       {
  981.       if (strcmp (Reserved_Words[i].Token_Name, &(String[0])) == 0)
  982.         return (Reserved_Words[i].Token_Number);
  983.       }
  984.     else
  985.       if (pov_stricmp (Reserved_Words[i].Token_Name, &(String[0])) == 0)
  986.         return (Reserved_Words[i].Token_Number);
  987.  
  988.   return (-1);
  989.   }
  990.  
  991. /* Check to see if a symbol already exists with this name.  If so, return
  992.     its symbol ID. */
  993.  
  994. int Find_Symbol ()
  995.   {
  996.   register int i;
  997.  
  998.   for (i = 1 ; i <= Number_Of_Symbols ; i++)
  999.     if(Case_Sensitive_Flag == 0 || Case_Sensitive_Flag == 2)
  1000.       if (strcmp (Symbol_Table[i], String) == 0)
  1001.         return (i);
  1002.       else if (Case_Sensitive_Flag == 1)
  1003.         if (pov_stricmp (Symbol_Table[i], String) == 0)
  1004.           return (i);
  1005.  
  1006.   return (-1);
  1007.   }
  1008.  
  1009. /* Report an error */
  1010. void Token_Error (Data_File, str)
  1011. DATA_FILE *Data_File;
  1012. char *str;
  1013.   {
  1014.   fprintf(stderr, "Error in %s line %d\n", Data_File->Filename, Data_File->Line_Number);
  1015.   fputs(str, stderr);
  1016.   fputs("\n\n", stderr);
  1017.   exit(1);
  1018.   }
  1019.  
  1020. /* Since the stricmp function isn't available on all systems, we've
  1021.    provided a simplified version of it here. */
  1022.  
  1023. static int pov_stricmp (s1, s2)
  1024. char *s1, *s2;
  1025.   {
  1026.   char c1, c2;
  1027.  
  1028.   while ((*s1 != '\0') && (*s2 != '\0')) 
  1029.     {
  1030.     c1 = *s1++;
  1031.     c2 = *s2++;
  1032.     if (islower(c1))
  1033.       c1 = (char) toupper(c1);
  1034.     if (islower(c2))
  1035.       c2 = (char) toupper(c2);
  1036.     if (c1 < c2)
  1037.       return (-1);
  1038.     if (c1 > c2)
  1039.       return (1);
  1040.     }
  1041.  
  1042.   if (*s1 == '\0')
  1043.     if (*s2 == '\0')
  1044.       return (0);
  1045.     else
  1046.       return (-1);
  1047.   else
  1048.     return (1);
  1049.   }
  1050.