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