home *** CD-ROM | disk | FTP | other *** search
/ Fish 'n' More 2 / fishmore-publicdomainlibraryvol.ii1991xetec.iso / fish / graphics / applications / dkbtrace / src / tokenize.c < prev    next >
C/C++ Source or Header  |  1990-08-26  |  17KB  |  697 lines

  1. /*****************************************************************************
  2. *
  3. *                                     tokenize.c
  4. *
  5. *   from DKBTrace (c) 1990  David Buck
  6. *
  7. *  This module implements the first part of a two part parser for the scene
  8. *  description files.  This phase changes the input file into tokens.
  9. *
  10. * This software is freely distributable. The source and/or object code may be
  11. * copied or uploaded to communications services so long as this notice remains
  12. * at the top of each file.  If any changes are made to the program, you must
  13. * clearly indicate in the documentation and in the programs startup message
  14. * who it was who made the changes. The documentation should also describe what
  15. * those changes were. This software may not be included in whole or in
  16. * part into any commercial package without the express written consent of the
  17. * author.  It may, however, be included in other public domain or freely
  18. * distributed software so long as the proper credit for the software is given.
  19. *
  20. * This software is provided as is without any guarantees or warranty. Although
  21. * the author has attempted to find and correct any bugs in the software, he
  22. * is not responsible for any damage caused by the use of the software.  The
  23. * author is under no obligation to provide service, corrections, or upgrades
  24. * to this package.
  25. *
  26. * Despite all the legal stuff above, if you do find bugs, I would like to hear
  27. * about them.  Also, if you have any comments or questions, you may contact me
  28. * at the following address:
  29. *
  30. *     David Buck
  31. *     22C Sonnet Cres.
  32. *     Nepean Ontario
  33. *     Canada, K2H 8W7
  34. *
  35. *  I can also be reached on the following bulleton boards:
  36. *
  37. *     ATX              (613) 526-4141
  38. *     OMX              (613) 731-3419
  39. *     Mystic           (613) 731-0088 or (613) 731-6698
  40. *
  41. *  Fidonet:   1:163/109.9
  42. *  Internet:  David_Buck@Carleton.CA
  43. *
  44. *  IBM Port by Aaron A. Collins. Aaron may be reached on the following BBS'es:
  45. *
  46. *     Lattice BBS                      (708) 916-1200
  47. *     The Information Exchange BBS     (708) 945-5575
  48. *     Stillwaters BBS                  (708) 403-2826
  49. *
  50. *****************************************************************************/
  51.  
  52. #include <ctype.h>
  53. #include "frame.h"
  54. #include "dkbproto.h"
  55.  
  56. /* This module tokenizes the input file to create a token file to be read
  57. by the parser (the second stage). Tokens written to the file contain a
  58. token ID, the line number of the token, and if necessary, some data for
  59. the token.  */
  60.  
  61. #define MAX_STRING_INDEX 20
  62. char String[MAX_STRING_INDEX];
  63. int String_Index;
  64. int Line_Number = 1;
  65.  
  66. /* Here are the reserved words.  If you need to add new words, be sure
  67. to declare them in frame.h */
  68.  
  69. struct Reserved_Word_Struct Reserved_Words [LAST_TOKEN] = {
  70. AGATE_TOKEN, "AGATE",
  71. ALPHA_TOKEN, "ALPHA",
  72. AMBIENT_TOKEN, "AMBIENT",
  73. AMPERSAND_TOKEN, "&",
  74. AT_TOKEN, "@",
  75. BACK_QUOTE_TOKEN, "`",
  76. BACK_SLASH_TOKEN, "\\",
  77. BAR_TOKEN, "|",
  78. BLUE_TOKEN, "BLUE",
  79. BRILLIANCE_TOKEN, "BRILLIANCE",
  80. BOZO_TOKEN, "BOZO",
  81. BOUNDED_TOKEN, "BOUNDED_BY",
  82. BUMPS_TOKEN, "BUMPS",
  83. CHECKER_TOKEN, "CHECKER",
  84. COLON_TOKEN, ":",
  85. COLOR_TOKEN, "COLOR",
  86. COLOUR_TOKEN, "COLOUR",
  87. COLOR_MAP_TOKEN, "COLOR_MAP",
  88. COLOUR_MAP_TOKEN, "COLOUR_MAP",
  89. COMMA_TOKEN, ",",
  90. COMPOSITE_TOKEN, "COMPOSITE",
  91. DASH_TOKEN, "-",
  92. DECLARE_TOKEN, "DECLARE",
  93. DENTS_TOKEN, "DENTS",
  94. DIFFERENCE_TOKEN, "DIFFERENCE",
  95. DIFFUSE_TOKEN, "DIFFUSE",
  96. DIRECTION_TOKEN, "DIRECTION",
  97. DOLLAR_TOKEN, "$",
  98. END_BOUNDED_TOKEN, "END_BOUND",
  99. END_COLOR_MAP_TOKEN, "END_COLOR_MAP",
  100. END_COLOUR_MAP_TOKEN, "END_COLOUR_MAP",
  101. END_COMPOSITE_TOKEN, "END_COMPOSITE",
  102. END_DIFFERENCE_TOKEN, "END_DIFFERENCE",
  103. END_FOG_TOKEN, "END_FOG",
  104. END_INTERSECTION_TOKEN, "END_INTERSECTION",
  105. END_OBJECT_TOKEN, "END_OBJECT",
  106. END_OF_FILE_TOKEN, "End of File",
  107. END_PLANE_TOKEN, "END_PLANE",
  108. END_POINTS_TOKEN, "END_POINTS",
  109. END_POLYGON_TOKEN, "END_POLYGON",
  110. END_QUADRIC_TOKEN, "END_QUADRIC",
  111. END_SHAPE_TOKEN, "END_SHAPE",
  112. END_SPHERE_TOKEN, "END_SPHERE",
  113. END_TEXTURE_TOKEN, "END_TEXTURE",
  114. END_TRIANGLE_TOKEN, "END_TRIANGLE",
  115. END_UNION_TOKEN, "END_UNION",
  116. END_VIEW_POINT_TOKEN, "END_VIEW_POINT",
  117. EQUALS_TOKEN, "=",
  118. EXCLAMATION_TOKEN, "!",
  119. FLOAT_TOKEN, "FLOAT",
  120. FOG_TOKEN, "FOG",
  121. FREQUENCY_TOKEN, "FREQUENCY",
  122. GIF_TOKEN, "GIF",
  123. GRANITE_TOKEN, "GRANITE",
  124. GRADIENT_TOKEN, "GRADIENT",
  125. GREEN_TOKEN, "GREEN",
  126. HASH_TOKEN, "#",
  127. HAT_TOKEN, "^",
  128. IDENTIFIER_TOKEN, "IDENTIFIER",
  129. IFF_TOKEN, "IFF",
  130. IMAGEMAP_TOKEN, "IMAGEMAP",
  131. INCLUDE_TOKEN, "INCLUDE",
  132. INTERSECTION_TOKEN, "INTERSECTION",
  133. INVERSE_TOKEN, "INVERSE",
  134. IOR_TOKEN, "IOR",
  135. LEFT_ANGLE_TOKEN, "<",
  136. LEFT_BRACKET_TOKEN, "{",
  137. LEFT_SQUARE_TOKEN, "[",
  138. LIGHT_SOURCE_TOKEN, "LIGHT_SOURCE",
  139. LOCATION_TOKEN, "LOCATION",
  140. LOOK_AT_TOKEN, "LOOK_AT",
  141. MARBLE_TOKEN, "MARBLE",
  142. OBJECT_TOKEN, "OBJECT",
  143. ONCE_TOKEN, "ONCE",
  144. PERCENT_TOKEN, "%",
  145. PHASE_TOKEN, "PHASE",
  146. PHONG_TOKEN, "PHONG",
  147. PHONGSIZE_TOKEN, "PHONGSIZE",
  148. PLANE_TOKEN, "PLANE",
  149. PLUS_TOKEN, "+",
  150. POINTS_TOKEN, "POINTS",
  151. POLYGON_TOKEN, "POLYGON",
  152. QUADRIC_TOKEN, "QUADRIC",
  153. QUESTION_TOKEN, "?",
  154. RAW_TOKEN, "RAW",
  155. RED_TOKEN, "RED",
  156. REFLECTION_TOKEN, "REFLECTION",
  157. REFRACTION_TOKEN, "REFRACTION",
  158. REVOLVE_TOKEN, "REVOLVE",
  159. RIGHT_TOKEN, "RIGHT",
  160. RIGHT_ANGLE_TOKEN, ">",
  161. RIGHT_BRACKET_TOKEN, ")",
  162. RIGHT_SQUARE_TOKEN, "]",
  163. RIPPLES_TOKEN, "RIPPLES",
  164. ROTATE_TOKEN, "ROTATE",
  165. ROUGHNESS_TOKEN, "ROUGHNESS",
  166. SCALE_TOKEN, "SCALE",
  167. SEMI_COLON_TOKEN, ";",
  168. SHAPE_TOKEN, "SHAPE",
  169. SKY_TOKEN, "SKY",
  170. SINGLE_QUOTE_TOKEN, "'",
  171. SIZE_TOKEN, "SIZE",
  172. SLASH_TOKEN, "/",
  173. SMOOTH_TRIANGLE_TOKEN, "SMOOTH_TRIANGLE",
  174. SPECULAR_TOKEN, "SPECULAR",
  175. SPHERE_TOKEN, "SPHERE",
  176. SPOTTED_TOKEN, "SPOTTED",
  177. STAR_TOKEN, "*",
  178. STRING_TOKEN, "STRING",
  179. TEXTURE_TOKEN, "TEXTURE",
  180. TILDE_TOKEN, "~",
  181. TRANSLATE_TOKEN, "TRANSLATE",
  182. TRIANGLE_TOKEN, "TRIANGLE",
  183. TURBULENCE_TOKEN, "TURBULENCE",
  184. UNION_TOKEN, "UNION",
  185. UP_TOKEN, "UP",
  186. VIEW_POINT_TOKEN, "VIEW_POINT",
  187. WAVES_TOKEN, "WAVES",
  188. WOOD_TOKEN, "WOOD",
  189. WRINKLES_TOKEN, "WRINKLES"
  190.   };
  191.  
  192. /* Make a table for user-defined symbols.  200 symbols should be more
  193. than enough. */
  194.  
  195. #define MAX_SYMBOLS 200
  196.  
  197. /* Hard code symbols to be a maximum of 40 characters long */
  198. char Symbol_Table[MAX_SYMBOLS][40];
  199. int Number_Of_Symbols;
  200.  
  201. char File_Name[FILE_NAME_LENGTH];
  202.  
  203. extern FILE *Data_File, *Token_File, *Symbol_File;
  204. #define CALL(x) { if (!(x)) return (FALSE); }
  205.  
  206. /* The main tokenizing routine.  Set up the files and continue parsing
  207. until the end of file */
  208.  
  209. void Tokenize (name, in, symbol, out)
  210.   char *name;
  211.   FILE *in, *symbol, *out;
  212.   {
  213. /* Keep track of the file name so we don't get confused when we
  214.     return from INCLUDE files */
  215.  
  216.   strcpy (File_Name, name);
  217.   Data_File = in;
  218.   Token_File = out;
  219.   Symbol_File = symbol;
  220.   Number_Of_Symbols = 0;
  221.  
  222. /* Let the parser know the name of the file we are tokenizing */
  223.   strcpy (String, name);
  224.   Write_Token (INCLUDE_TOKEN);
  225.  
  226.   while (Process_Token()) ;
  227.   }
  228.  
  229. /* This function performs most of the work involved in tokenizing.  It
  230.    reads the first character of the token and decides which function to
  231.    call to tokenize the rest.  For simple tokens, it simply writes them
  232.    out to the token file.  */
  233.  
  234. int Process_Token ()
  235.   {
  236.   register int c;
  237.  
  238.   Skip_Spaces ();
  239.  
  240.   c = getc(Data_File);
  241.   if (c == EOF)
  242.     return (FALSE);
  243.  
  244.   String[0] = '\0';
  245.  
  246.   switch (c)
  247.     {
  248.     case '\n': Line_Number++;
  249.                break;
  250.  
  251.     case '{' : Parse_Comments();
  252.                break;
  253.  
  254.     case '@' : Write_Token (AT_TOKEN);
  255.                break;
  256.  
  257.     case '&' : Write_Token (AMPERSAND_TOKEN);
  258.                break;
  259.  
  260.     case '`' : Write_Token (BACK_QUOTE_TOKEN);
  261.                break;
  262.  
  263.     case '\\': Write_Token (BACK_SLASH_TOKEN);
  264.                break;
  265.  
  266.     case '|' : Write_Token (BAR_TOKEN);
  267.                break;
  268.  
  269.     case ':' : Write_Token (COLON_TOKEN);
  270.                break;
  271.  
  272.     case ',' : Write_Token (COMMA_TOKEN);
  273.                break;
  274.  
  275.     case '-' : Write_Token (DASH_TOKEN);
  276.                break;
  277.  
  278.     case '$' : Write_Token (DOLLAR_TOKEN);
  279.                break;
  280.  
  281.     case '=' : Write_Token (EQUALS_TOKEN);
  282.                break;
  283.  
  284.     case '!' : Write_Token (EXCLAMATION_TOKEN);
  285.                break;
  286.  
  287.     case '#' : Write_Token (HASH_TOKEN);
  288.                break;
  289.  
  290.     case '^' : Write_Token (HAT_TOKEN);
  291.                break;
  292.  
  293.     case '<' : Write_Token (LEFT_ANGLE_TOKEN);
  294.                break;
  295.  
  296.     case '(' : Write_Token (LEFT_BRACKET_TOKEN);
  297.                break;
  298.  
  299.     case '[' : Write_Token (LEFT_SQUARE_TOKEN);
  300.                break;
  301.  
  302.     case '%' :  Write_Token (PERCENT_TOKEN);
  303.                break;
  304.  
  305.     case '+' : Write_Token (PLUS_TOKEN);
  306.                break;
  307.  
  308.     case '?' : Write_Token (QUESTION_TOKEN);
  309.                break;
  310.  
  311.     case '>' : Write_Token (RIGHT_ANGLE_TOKEN);
  312.                break;
  313.  
  314.     case ')' : Write_Token (RIGHT_BRACKET_TOKEN);
  315.                break;
  316.  
  317.     case ']' : Write_Token (RIGHT_SQUARE_TOKEN);
  318.                break;
  319.  
  320.     case ';' : Write_Token (SEMI_COLON_TOKEN);
  321.                break;
  322.  
  323.     case '\'': Write_Token (SINGLE_QUOTE_TOKEN);
  324.                break;
  325.  
  326.     case '/' : Write_Token (SLASH_TOKEN);
  327.                break;
  328.  
  329.     case '*' : Write_Token (STAR_TOKEN);
  330.                break;
  331.  
  332.     case '~' : Write_Token (TILDE_TOKEN);
  333.                break;
  334.  
  335.     case '"' : Parse_String ();
  336.                break;
  337.  
  338.     case '0':   case '1':   case '2':   case '3':   case '4':   case '5':
  339.     case '6':   case '7':   case '8':   case '9':
  340.                ungetc (c, Data_File);
  341.                CALL (Read_Float ());
  342.                break;
  343.  
  344.     case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
  345.     case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
  346.     case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
  347.     case 'v': case 'w': case 'x': case 'y': case 'z':
  348.     case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
  349.     case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
  350.     case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
  351.     case 'V': case 'W': case 'X': case 'Y': case 'Z': case '_':
  352.                ungetc (c, Data_File);
  353.                CALL (Read_Symbol ());
  354.                break;
  355.  
  356.     default:
  357.       printf ("Error on line %d\n", Line_Number);
  358.       printf ("Illegal character in input file, value is %02x\n", c);
  359.       break;
  360.     }
  361.   return (TRUE);
  362.   }
  363.  
  364.  
  365. /* Skip over spaces in the input file */
  366.  
  367. int Skip_Spaces ()
  368.   {
  369.   register int c;
  370.  
  371.   while (TRUE)
  372.     {
  373.     c = getc(Data_File);
  374.     if (c == EOF)
  375.       return (FALSE);
  376.  
  377.     if (!isspace(c))
  378.       break;
  379.  
  380.     if (c == '\n')
  381.        Line_Number++;
  382.     }
  383.  
  384.   ungetc (c, Data_File);
  385.   return (TRUE);
  386.   }
  387.  
  388. /* Comments start with an open brace ({) and end with a close brace (}).
  389.    The open brace has been read already.  Continue reading until a close
  390.    brace is encountered. Be sure to count the lines while you're at it.
  391.    Incidently, nested comments are supported (in case you do such esoteric
  392.    things) */
  393.  
  394. int Parse_Comments ()
  395.   {
  396.   register int c;
  397.   int End_Of_Comment;
  398.   
  399.   End_Of_Comment = FALSE;
  400.   while (!End_Of_Comment)
  401.     {
  402.     c = getc (Data_File);
  403.     if (c == EOF)
  404.       {
  405.       Token_Error ("No closing comment found");
  406.       return (FALSE);
  407.       }
  408.  
  409.     if (c == (int) '\n')
  410.       Line_Number++;
  411.  
  412.     if (c == (int) '{')
  413.       CALL (Parse_Comments())
  414.     else
  415.       End_Of_Comment = (c == (int) '}');
  416.     }
  417.  
  418.   return (TRUE);
  419.   }
  420.  
  421. /* The following routines make it easier to handle strings.  They stuff
  422.    characters into a string buffer one at a time making all the proper
  423.    range checks.  Call Begin_String to start, Stuff_Character to put
  424.    characters in, and End_String to finish.  The String variable contains
  425.    the final string. */
  426.  
  427. void Begin_String()
  428.   {
  429.   String_Index = 0;
  430.   }
  431.  
  432. void Stuff_Character (c)
  433.   char c;
  434.   {
  435.   if (String_Index < MAX_STRING_INDEX)
  436.     {
  437.     String [String_Index++] = c;
  438.     if (String_Index >= MAX_STRING_INDEX)
  439.       {
  440.       Token_Error ("String too long");
  441.       String [String_Index-1] = '\0';
  442.       }
  443.     }
  444.   }
  445.  
  446. void End_String ()
  447.   {
  448.   Stuff_Character ('\0');
  449.   }
  450.  
  451. /* Read a float from the input file and tokenize it as one token. The phase
  452.    variable is 0 for the first character, 1 for all subsequent characters
  453.    up to the decimal point, and 2 for all characters after the decimal
  454.    point.  This helps to insure that the number is formatted properly. */
  455.  
  456. int Read_Float()
  457.   {
  458.   register int c, Finished, Phase;
  459.  
  460.   Finished = FALSE;
  461.   Phase = 0;
  462.  
  463.   Begin_String();
  464.   while (!Finished)
  465.     {
  466.     c = getc(Data_File);
  467.     if (c == EOF)
  468.       {
  469.       Token_Error ("Unexpected end of file");
  470.       return (FALSE);
  471.       }
  472.  
  473.     switch (Phase)
  474.       {
  475.       case 0: if (isdigit(c))
  476.                 Stuff_Character((char) c);
  477.               else
  478.                 Token_Error ("Error in decimal number");
  479.               Phase = 1;
  480.               break;
  481.      
  482.       case 1: if (isdigit(c))
  483.                 Stuff_Character((char) c);
  484.               else if (c == (int) '.')
  485.                 {
  486.                 Stuff_Character((char) c);
  487.                 Phase = 2;
  488.                 }
  489.               else
  490.                 Finished = TRUE;
  491.               break;
  492.  
  493.       case 2: if (isdigit(c))
  494.                 Stuff_Character((char) c);
  495.               else
  496.                 Finished = TRUE;
  497.               break;
  498.       }
  499.     }
  500.  
  501.   ungetc (c, Data_File);
  502.   End_String();
  503.  
  504.   Write_Token (FLOAT_TOKEN);
  505.   return (TRUE);
  506.   }
  507.  
  508. /* Parse a string from the input file into a token. */
  509. int Parse_String ()
  510.   {
  511.   register int c;
  512.  
  513.   Begin_String();
  514.   while (TRUE)
  515.     {
  516.     c = getc(Data_File);
  517.     if (c == EOF)
  518.       {
  519.       Token_Error ("No end quote for string");
  520.       return (FALSE);
  521.       }
  522.  
  523.     if (c != (int) '"')
  524.       Stuff_Character ((char) c);
  525.     else
  526.       break;
  527.     }
  528.   End_String();
  529.  
  530.   Write_Token (STRING_TOKEN);
  531.  
  532.   return (TRUE);
  533.   }
  534.  
  535. /* Read an include file.  This can be a bit tricky.  The old files are saved
  536.    in local variables while the include file is being read.  We have to
  537.    write out an INCLUDE token when we start to tell the parser the name of
  538.    the file we're in.  We have to write another INCLUDE token when we finish
  539.    to tell the parser that we're back.  */
  540.  
  541. int Read_Include ()
  542.   {
  543.   register int c;
  544.   FILE *new_file, *original_file;
  545.   register int Old_Line_Number;
  546.   char Old_File_Name[FILE_NAME_LENGTH];
  547.  
  548.   Skip_Spaces();
  549.   if (getc(Data_File) != (int) '\"') {
  550.      printf ("Start quote expected\n");
  551.      exit (0);
  552.      }
  553.  
  554.   Begin_String();
  555.   while (TRUE)
  556.     {
  557.     c = getc(Data_File);
  558.     if (c == EOF)
  559.       {
  560.       Token_Error ("No end quote for string");
  561.       return (FALSE);
  562.       }
  563.  
  564.     if (c != (int) '"')
  565.       Stuff_Character ((char) c);
  566.     else
  567.       break;
  568.     }
  569.   End_String();
  570.  
  571.   if ((new_file = fopen (String, "r")) == NULL) {
  572.      printf ("Cannot open include file %s\n", String);
  573.      close_all();
  574.      exit(1);
  575.      }
  576.  
  577.   Write_Token (INCLUDE_TOKEN);
  578.   Old_Line_Number = Line_Number;
  579.   Line_Number = 1;
  580.   original_file = Data_File;
  581.   strcpy (Old_File_Name, File_Name);
  582.  
  583.   Tokenize (String, new_file, Symbol_File, Token_File);
  584.  
  585.   fclose (new_file);
  586.   Data_File = original_file;
  587.   Line_Number = Old_Line_Number;
  588.   strcpy (File_Name, Old_File_Name);
  589.   strcpy (String, Old_File_Name);
  590.   Write_Token (INCLUDE_TOKEN);
  591.   return (TRUE);
  592.   }
  593.  
  594. /* Read    in a symbol from the input file.  Check to see if it is a reserved
  595.    word.  If it is, write out the appropriate token.  Otherwise, write the
  596.    symbol out to the Symbol file and write out an IDENTIFIER token. An
  597.    Identifier token is a token whose token number is greater than the
  598.    highest reserved word. */
  599.  
  600. int Read_Symbol ()
  601.   {
  602.   register int c, Symbol_Id;
  603.  
  604.   Begin_String();
  605.   while (TRUE)
  606.     {
  607.     c = getc(Data_File);
  608.     if (c == EOF)
  609.       {
  610.       Token_Error ("Unexpected end of file");
  611.       return (FALSE);
  612.       }
  613.  
  614.     if (isalpha(c) || isdigit(c) || c == (int) '_')
  615.       Stuff_Character ((char) c);
  616.     else
  617.       {
  618.       ungetc (c, Data_File);
  619.       break;
  620.       }
  621.     }
  622.   End_String();
  623.  
  624.   if ((Symbol_Id = Find_Reserved()) != -1)
  625.  
  626. /* INCLUDE is a reserved word, but we want to handle it separately */
  627.  
  628.     if (Symbol_Id == INCLUDE_TOKEN)
  629.        Read_Include();
  630.     else
  631.        Write_Token (Symbol_Id);
  632.   else
  633.     {
  634.     if ((Symbol_Id = Find_Symbol()) == -1)
  635.       if (++Number_Of_Symbols < MAX_SYMBOLS)
  636.         {
  637.         strncpy (&Symbol_Table[Number_Of_Symbols][0], &String[0], 39);
  638.     Symbol_Table[Number_Of_Symbols][39] = '\0';
  639.         fprintf (Symbol_File, "%s%\n", &String[0]);
  640.         Symbol_Id = Number_Of_Symbols;
  641.         }
  642.       else
  643.         {
  644.         printf ("\nToo many symbols\n");
  645.         exit(0);
  646.         }
  647.  
  648.     Write_Token (LAST_TOKEN + Symbol_Id);
  649.     }
  650.  
  651.   return (TRUE);
  652.   }
  653.  
  654. /* Return the index the token in the reserved words table or -1 if it
  655.    isn't there. */
  656.  
  657. int Find_Reserved ()
  658.   {
  659.   register int i;
  660.  
  661.   for (i = 0 ; i < LAST_TOKEN ; i++)
  662.     if (strcmp (Reserved_Words[i].Token_Name, &(String[0])) == 0)
  663.       return (Reserved_Words[i].Token_Number);
  664.  
  665.   return (-1);
  666.   }
  667.  
  668. /* Check to see if a symbol already exists with this name.  If so, return
  669.     its symbol ID. */
  670.  
  671. int Find_Symbol ()
  672.   {
  673.   register int i;
  674.  
  675.   for (i = 1 ; i <= Number_Of_Symbols ; i++)
  676.     if (strcmp (&Symbol_Table[i][0], &(String[0])) == 0)
  677.       return (i);
  678.  
  679.   return (-1);
  680.   }
  681.  
  682. /* Write a token out to the token file */
  683. void Write_Token (Token_Id)
  684.   TOKEN Token_Id;
  685.   {
  686.   fprintf (Token_File, "%d %d %s\n", Token_Id, Line_Number, String);
  687.   }                    /* Was (long) Token_Id... */
  688.  
  689. /* Report an error */
  690. void Token_Error (str)
  691.   char *str;
  692.   {
  693.   printf ("Error on line %d\n", Line_Number);
  694.   puts(str);
  695.   puts("\n\n");
  696.   }
  697.