home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pascal.zip / lexical / lexical.c < prev    next >
Text File  |  1995-10-29  |  21KB  |  615 lines

  1. /*
  2.  *        C . A . P .   L E X I C A L   A N A L Y Z E R
  3.  *
  4.  *        C O R E   P R O C E D U R E S
  5.  *
  6.  *        Stéphane Charette @ C.A.P. Services
  7.  *
  8.  *        Last modified:  Stéphane Charette, 1995 October 29
  9.  *
  10.  *****************************************************************************
  11.  *
  12.  *        Project:    BILL
  13.  *        Group:    lexical analyzer
  14.  *        File:        lexical\lexical.c
  15.  *        Version:    0.1.4
  16.  *
  17.  *        This file contains all of the source code that makes up the lexical
  18.  *        analyzer portion of the interpreter BILL.
  19.  */
  20.  
  21.  
  22.  
  23. /*
  24.  *    Versions:
  25.  *
  26.  *    0.0.1    - design of structure and implementation, Stéphane Charette, 94Feb26-Mar1
  27.  *    0.1.0    - first working version, SC, 94Mar2
  28.  *    0.1.1    - added debug information, SC, 94Mar2-3
  29.  *    0.1.2    - added set of illegal characters, SC, 94Mar24
  30.  *    0.1.2    - added more comments, optimized debug, SC, 94Mar27-Apr10
  31.  *    0.1.3    - fixed bug while detecting comments, SC, 94Mar13
  32.  *    0.1.3    - fixed bug while detecting not-equal "<>" symbol, SC, 94Mar14
  33.  *    0.1.4    - ported to OS/2, SC, 94Apr23-27
  34.  * 0.1.4 - changed text formatting, SC, 95Oct29
  35.  */
  36.  #define _LEX_VERSION "Lexical analyzer v0.1.4, Stéphane Charette, 95Oct29\n"
  37.  
  38.  
  39. /*
  40.  *    Includes
  41.  */
  42.     #include "..\lexical\lexical.hi"        // internal lexical analyzer include file
  43.  
  44.  
  45.  
  46. /*
  47.  *    FUNCTION:  InitLex
  48.  */
  49. ERR InitLex( UCHAR path[] )
  50. {
  51.     ERR RC = ERR_OK;
  52.  
  53.     #if( _LEX_DEBUG )
  54.     Lex_Debug.ScreenOutput = FALSE;        // pre-initialize debug value
  55.     Lex_Debug.SourceOutput = FALSE;        // pre-initialize debug value
  56.     Lex_Debug.TokenOutput = FALSE;        // pre-initialize debug value
  57.     Lex_Debug.MixOutput = FALSE;            // pre-initialize debug value
  58.     #endif
  59.  
  60.     Lex_State.InComment = FALSE;            // are we in a comment?
  61.     Lex_State.InString = FALSE;            // are we in a string?
  62.     Lex_State.LineNumber = 0;                // current line number
  63.     Lex_State.CharOffset = 0;                // character offset into current line
  64.     Lex_State.Error = ERR_OK;                // last error
  65.     Lex_State.TokenID = TOK_NO_ID;         // ID of found token
  66.     Lex_State.LexemeID = LEX_NO_ID;        // Actual lexeme if ID is generic
  67.     Lex_State.VarID = 0;                        // variable reference
  68.     strcpy( Lex_State.Token, "" );        // Actual token
  69.  
  70.     // open the source file
  71.     if( strlen( path ) > LEX_MAX_PATH_LEN ) LexError( ERR_LEX_PATH_TOO_LONG );                        //    is the path valid?
  72.     strcpy( FileName, path );                                                                        //    save the path of file
  73.     if( ( FilePtr = fopen( FileName, "r" ) ) == NULL ) LexError( ERR_LEX_CANNOT_OPEN_FILE );        //    open the file
  74.  
  75.     // initialize the look-ahead buffer
  76.     strcpy( Buffer, " \n" );            // set the previous and current character to <SPACE><NEWLINE>
  77.     if( ! fread( &( Buffer[ 2 ] ), 1, LEX_MAX_BUFFER_LEN - 2, FilePtr ) ) LexError( ERR_LEX_CANNOT_READ_FILE );    // read file
  78.  
  79.     return RC;
  80. }
  81.  
  82.  
  83.  
  84. /*
  85.  *    FUNCTION:  ResetLex
  86.  */
  87. ERR ResetLex( )
  88. {
  89.     ERR RC = ERR_OK;
  90.  
  91.     if( fclose( FilePtr ) ) RC = ERR_LEX_CANNOT_CLOSE_FILE;
  92.  
  93.     return RC;
  94. }
  95.  
  96.  
  97.  
  98. /*
  99.  *    FUNCTION:  LexError
  100.  */
  101. void LexError( ERR error_code )
  102. {
  103.     Lex_State.Error = error_code;
  104.  
  105.     printf( "\nError encountered in lex:  %i\n\a", Lex_State.Error );
  106.  
  107.     ResetLex( );                                // perform shutdown procedures
  108.  
  109.     ExitCode( error_code );                    // return to operating system
  110. }
  111.  
  112.  
  113.  
  114. /*
  115.  *    FUNCTION:  GetNextCharacter
  116.  */
  117. ERR GetNextCharacter( )
  118. {
  119.     ERR RC = ERR_OK;
  120.  
  121.     strncpy( Buffer, &( Buffer[ 1 ] ), ( LEX_MAX_BUFFER_LEN - 1 ) );        // shift the buffer down by one
  122.  
  123.     fread( &( Buffer[ LEX_MAX_BUFFER_LEN - 1 ] ), 1, 1, FilePtr );            // read the next character
  124.  
  125.     // find out if an EOF occurred
  126.     if( feof( FilePtr ) )
  127.     {
  128.         // could not read character, so use a space instead
  129.         Buffer[ LEX_MAX_BUFFER_LEN - 1 ] = ' ';
  130.  
  131.         RC = Lex_State.Error = ERR_LEX_END_OF_FILE;    // indicate that the eof was reached
  132.     }
  133.  
  134.     // find out if a file error occurred
  135.     if( ferror( FilePtr ) )
  136.     {
  137.         // could not read character, so use a space instead
  138.         Buffer[ LEX_MAX_BUFFER_LEN - 1 ] = ' ';
  139.  
  140.         RC = Lex_State.Error = ERR_LEX_CANNOT_READ_FILE;    // indicate that an actual file read error occurred
  141.     }
  142.  
  143.     if( ( Buffer[ 0 ] == '\r' ) || ( Buffer[ 0 ] == '\n' ) )
  144.     {                                        // if the previous character read was an EOL character...
  145.         Lex_State.LineNumber ++;    // ...then increase the line counter by one,
  146.         Lex_State.CharOffset = 1;    // ...and reset the character counter to the start of the line
  147.         #if( _LEX_DEBUG )
  148.         LexDebugWrite( "\n(%3i) ", Lex_State.LineNumber );
  149.         #endif
  150.     }
  151.     else
  152.     {                                        // ...else...
  153.         Lex_State.CharOffset ++;    // ...increase the character offset into this line
  154.         #if( _LEX_DEBUG )
  155.         if( Lex_Debug.ScreenOutput ) printf( "%c", Buffer[ 0 ] );
  156.         if( Lex_Debug.SourceOutput ) fprintf( LexDebugSourceFilePtr, "%c", Buffer[ 0 ] );
  157.         if( Lex_Debug.MixOutput ) fprintf( LexDebugMixFilePtr, "%c", Buffer[ 0 ] );
  158.         #endif
  159.     }
  160.  
  161.     return RC;
  162. }
  163.  
  164.  
  165.  
  166. /*
  167.  *    FUNCTION:  GetNextToken
  168.  */
  169. ERR GetNextToken( )
  170. {
  171.     ERR RC = ERR_OK;
  172.  
  173.     Lex_State.TokenID = TOK_NO_ID;
  174.     Lex_State.LexemeID = LEX_NO_ID;
  175.     Lex_State.VarID = SYM_NO_ID;
  176.     strcpy( Lex_State.Token, "" );
  177.  
  178.     // skip the white space - if any - at the current position in Buffer
  179.     if( isspace( Buffer[ 1 ] ) ) RC = SkipWhiteSpace( );
  180.  
  181.     while( Lex_State.TokenID == TOK_NO_ID )
  182.     {
  183.         if( ( ( ( Lex_State.InString == FALSE ) && ( Lex_State.InComment == FALSE ) ) &&
  184.             ( strchr( SET_OF_TOKEN_DELIMITERS, Buffer[ 1 ] ) || strchr( SET_OF_ILLEGAL_CHARS, Buffer[ 1 ] ) ) ) ||
  185.             ( ( Lex_State.InComment == TRUE ) && ( Buffer[ 1 ] == '}' ) ) ||
  186.             ( ( Lex_State.InString == TRUE ) && ( Buffer[ 1 ] == '\'' ) ) )
  187.         {
  188.             // token delimiter found - now try and recognize the token
  189.  
  190.             // is this a single character delimiter, or does this indicate the end of a previous token?
  191.             if( Lex_State.Token[ 0 ] == '\0' )
  192.             {
  193.                 // this indicates we've just read a single character delimiter
  194.                 switch( Buffer[ 1 ] )
  195.                 {
  196.                     case '{':    // don't do anything with these - the next step will
  197.                     case '}':    // take care of handling them correctly
  198.                         break;
  199.                     case ';':
  200.                         Lex_State.TokenID = TOK_SEMICOLON_ID;    // semicolon recognized
  201.                         strcpy( Lex_State.Token, ";" );            // make a copy of the token
  202.                         RC = GetNextCharacter( );                    // get next character
  203.                         break;
  204.                     case ',':
  205.                         Lex_State.TokenID = TOK_COMMA_ID;        // comma recognized
  206.                         strcpy( Lex_State.Token, "," );            // make a copy of the token
  207.                         RC = GetNextCharacter( );                    // get next character
  208.                         break;
  209.                     case '.':
  210.                         Lex_State.TokenID = TOK_PERIOD_ID;        // period recognized
  211.                         strcpy( Lex_State.Token, "." );            // make a copy of the token
  212.                         RC = GetNextCharacter( );                    // get next character
  213.                         if( RC = ERR_LEX_END_OF_FILE ) RC = ERR_OK;    // give the guy a break...  :)
  214.                         break;
  215.                     case '+':
  216.                         Lex_State.TokenID = TOK_PLUS_ID;            // plus recognized
  217.                         strcpy( Lex_State.Token, "+" );            // make a copy of the token
  218.                         RC = GetNextCharacter( );                    // get next character
  219.                         break;
  220.                     case '-':
  221.                         Lex_State.TokenID = TOK_MINUS_ID;        // minus recognized
  222.                         strcpy( Lex_State.Token, "-" );            // make a copy of the token
  223.                         RC = GetNextCharacter( );                    // get next character
  224.                         break;
  225.                     case '*':
  226.                         Lex_State.TokenID = TOK_MULT_ID;            // multiply recognized
  227.                         strcpy( Lex_State.Token, "*" );            // make a copy of the token
  228.                         RC = GetNextCharacter( );                    // get next character
  229.                         break;
  230.                     case '/':
  231.                         Lex_State.TokenID = TOK_DIV_ID;            // divide recognized
  232.                         strcpy( Lex_State.Token, "/" );            // make a copy of the token
  233.                         RC = GetNextCharacter( );                    // get next character
  234.                         break;
  235.                     case '(':
  236.                         Lex_State.TokenID = TOK_PO_ID;            // parenteses open recognized
  237.                         strcpy( Lex_State.Token, "(" );            // make a copy of the token
  238.                         RC = GetNextCharacter( );                    // get next character
  239.                         break;
  240.                     case ')':
  241.                         Lex_State.TokenID = TOK_PC_ID;            // parenteses close recognized
  242.                         strcpy( Lex_State.Token, ")" );            // make a copy of the token
  243.                         RC = GetNextCharacter( );                    // get next character
  244.                         break;
  245.                     case '\'':
  246.                         break;                                            // pass on the single quotes
  247.                     case '<':
  248.                         if( Buffer[ 2 ] == '=' )
  249.                         {
  250.                             Lex_State.TokenID = TOK_RELOP_ID;    // relational operator recognized
  251.                             Lex_State.LexemeID = LEX_LE_ID;        // less_than_or_equal_to lexeme recognized
  252.                             strcpy( Lex_State.Token, "<=" );        // make a copy of the token
  253.                             // move ahead two characters since this is a two-char token
  254.                             if( ( RC = GetNextCharacter( ) ) == ERR_OK ) RC = GetNextCharacter( );
  255.                         }
  256.                         else
  257.                         {
  258.                             if( Buffer[ 2 ] == '>' )
  259.                             {
  260.                                 Lex_State.TokenID = TOK_RELOP_ID;
  261.                                 Lex_State.LexemeID = LEX_NE_ID;
  262.                                 strcpy( Lex_State.Token, "<>" );
  263.                                 if( ( RC = GetNextCharacter( ) ) == ERR_OK ) RC = GetNextCharacter( );
  264.                             }
  265.                             else
  266.                             {
  267.                                 Lex_State.TokenID = TOK_RELOP_ID;    // relational operator recognized
  268.                                 Lex_State.LexemeID = LEX_LT_ID;    // less_than lexeme recognized
  269.                                 strcpy( Lex_State.Token, "<" );    // make a copy of the token
  270.                                 RC = GetNextCharacter( );            // get next character
  271.                             }
  272.                         }
  273.                         break;
  274.                     case '>':
  275.                         if( Buffer[ 2 ] == '=' )
  276.                         {
  277.                             Lex_State.TokenID = TOK_RELOP_ID;    // relational operator recognized
  278.                             Lex_State.LexemeID = LEX_GE_ID;        // greater_than_or_equal_to lexeme recognized
  279.                             strcpy( Lex_State.Token, ">=" );        // make a copy of the token
  280.                             // move ahead two characters since this is a two-char token
  281.                             if( ( RC = GetNextCharacter( ) ) == ERR_OK ) RC = GetNextCharacter( );
  282.                         }
  283.                         else
  284.                         {
  285.                             Lex_State.TokenID = TOK_RELOP_ID;    // relational operator recognized
  286.                             Lex_State.LexemeID = LEX_GT_ID;        // greater_than lexeme recognized
  287.                             strcpy( Lex_State.Token, ">" );        // make a copy of the token
  288.                             RC = GetNextCharacter( );                // get next character
  289.                         }
  290.                         break;
  291.                     case ':':
  292.                         if( Buffer[ 2 ] == '=' )
  293.                         {
  294.                             Lex_State.TokenID = TOK_ASSIGNMENT_ID;    // assignment recognized
  295.                             strcpy( Lex_State.Token, ":=" );         // make a copy of the token
  296.                             // move ahead two characters since this is a two-char token
  297.                             if( ( RC = GetNextCharacter( ) ) == ERR_OK ) RC = GetNextCharacter( );
  298.                         }
  299.                         else
  300.                         {
  301.                             RC = Lex_State.Error = ERR_LEX_UNRECOGNIZED_CHAR;
  302.                             Lex_State.TokenID = TOK_ERROR_ID;
  303.                             strcpy( Lex_State.Token, ":" );        // make a copy of the token
  304.                         }
  305.                         break;
  306.                     case '=':
  307.                         Lex_State.TokenID = TOK_RELOP_ID;        // relational operator recognized
  308.                         Lex_State.LexemeID = LEX_EQ_ID;            // equal lexeme recognized
  309.                         strcpy( Lex_State.Token, "=" );            // make a copy of the token
  310.                         RC = GetNextCharacter( );                    // get next character
  311.                         break;
  312.                     default:
  313.                         RC = Lex_State.Error = ERR_LEX_UNRECOGNIZED_CHAR;    // set an error flag
  314.                         Lex_State.TokenID = TOK_ERROR_ID;        // set an error flag
  315.                         Lex_State.Token[ 0 ] = Buffer[ 1 ];        // make a copy of the unrecognized character
  316.                         Lex_State.Token[ 1 ] = '\0';
  317.                         break;
  318.                 }
  319.             }
  320.  
  321.             // was our token one of the previous single-character tokens?
  322.             if( Lex_State.TokenID == TOK_NO_ID )
  323.             {    // no...
  324.                 // ...then see if it's a special delimiter, such as ' (quote) or {} (curly braces)
  325.                 switch( Buffer[ 1 ] )
  326.                 {
  327.                     case '\'':                                            // string delimiter found...
  328.                         if( Lex_State.InString )
  329.                         {
  330.                             Lex_State.InString = FALSE;            // ...clear string flag
  331.                             Lex_State.TokenID = TOK_STRING_ID;    // set the token to "string"
  332.                             Lex_State.LexemeID = LEX_VALUE_ID;    // set the lexeme to "string"
  333.                             GetNextCharacter( );                        // ...get next character
  334.                             break;
  335.                         }
  336.                         else
  337.                         {
  338.                             Lex_State.InString = TRUE;                // ...set string flag
  339.                             GetNextCharacter( );                        // ...get next character
  340.                             break;
  341.                         }
  342.                     case '{':                                            // start of comment block found...
  343.                         Lex_State.InComment ++;                        // ...increase comment block counter
  344.                         break;
  345.                     case '}':                                            // end of comment block found...
  346.                         Lex_State.InComment --;                        // ...decrease comment block counter
  347.                         if( Lex_State.InComment < 0 ) LexError( ERR_LEX_CLOSE_COMMENT_BLOCK );    // comment close without open
  348.                         // skip the white space - if any - after the end of the comment
  349.                         if( isspace( Buffer[ 2 ] ) )
  350.                         {
  351.                             RC = GetNextCharacter( );
  352.                             SkipWhiteSpace( );
  353.                         }
  354.                         break;
  355.                     default:
  356.                         // since it wasn't a special token, now try and recongnize it as a reserved word
  357.                         if( strcmp( Lex_State.Token, "program" ) == 0 ) Lex_State.TokenID = TOK_PROGRAM_ID;
  358.                         if( strcmp( Lex_State.Token, "const" ) == 0 ) Lex_State.TokenID = TOK_CONST_ID;
  359.                         if( strcmp( Lex_State.Token, "var" ) == 0 ) Lex_State.TokenID = TOK_VAR_ID;
  360.                         if( strcmp( Lex_State.Token, "begin" ) == 0 ) Lex_State.TokenID = TOK_BEGIN_ID;
  361.                         if( strcmp( Lex_State.Token, "end" ) == 0 ) Lex_State.TokenID = TOK_END_ID;
  362.                         if( strcmp( Lex_State.Token, "if" ) == 0 ) Lex_State.TokenID = TOK_IF_ID;
  363.                         if( strcmp( Lex_State.Token, "then" ) == 0 ) Lex_State.TokenID = TOK_THEN_ID;
  364.                         if( strcmp( Lex_State.Token, "while" ) == 0 ) Lex_State.TokenID = TOK_WHILE_ID;
  365.                         if( strcmp( Lex_State.Token, "do" ) == 0 ) Lex_State.TokenID = TOK_DO_ID;
  366.                         if( strcmp( Lex_State.Token, "write" ) == 0 ) Lex_State.TokenID = TOK_WRITE_ID;
  367.                         if( strcmp( Lex_State.Token, "read" ) == 0 ) Lex_State.TokenID = TOK_READ_ID;
  368.                         if( strcmp( Lex_State.Token, "odd" ) == 0 ) Lex_State.TokenID = TOK_ODD_ID;
  369.                         if( Lex_State.TokenID == TOK_NO_ID )
  370.                         {
  371.                             // token was not recognized as a reserved work
  372.                             if( isdigit( Lex_State.Token[ 0 ] ) )
  373.                             {
  374.                                 // token recognized as a numerical value
  375.                                 Lex_State.TokenID = TOK_IDENTIFIER_ID;
  376.                                 Lex_State.LexemeID = LEX_VALUE_ID;
  377.                                 sscanf( Lex_State.Token, "%i", &( Lex_State.VarID ) );
  378.                             }
  379.                             else
  380.                             {
  381.                                 // token must be a variable name
  382.                                 Lex_State.TokenID = TOK_IDENTIFIER_ID;
  383.                                 Lex_State.LexemeID = LEX_VAR_ID;
  384.                                 Lex_State.VarID = SYM_NO_ID;
  385.                             }
  386.                         }
  387.                         break;
  388.                 }
  389.             }
  390.         }
  391.         else        // ...no delimiter found yet...
  392.         {
  393.             if( ! Lex_State.InComment )                            // if we aren't in the middle of a comment, then...
  394.             {
  395.                 UCHAR tmpbuffer[ 2 ] = " ";                        // temporary buffer
  396.                 tmpbuffer[ 0 ] = Buffer[ 1 ];                        // hold current character in temporary buffer
  397.  
  398.                 // convert to lowercase if not currently analyzing string
  399.                 if( ! Lex_State.InString ) tmpbuffer[ 0 ] = (UCHAR)tolower( tmpbuffer[ 0 ] );
  400.  
  401.                 // append the current character to the token
  402.                 if( strlen( Lex_State.Token ) == LEX_MAX_TOKEN_LEN )
  403.                 {
  404.                     // token is too long to fit in Lex_State.Token[] - generate error
  405.                     Lex_State.Error = ERR_LEX_TOKEN_TOO_LONG;
  406.                     break;
  407.                 }
  408.                 else
  409.                 {
  410.                     // add the new character to Lex_State.Token[]
  411.                     strcat( Lex_State.Token, tmpbuffer );
  412.                 }
  413.  
  414.             }
  415.  
  416.             GetNextCharacter( );                // get a new character
  417.  
  418.             if( ( Lex_State.Error == ERR_LEX_END_OF_FILE ) &&
  419.                 ( ( Lex_State.InComment && ( Buffer[ 1 ] != '}' ) ) ||
  420.                     ( Lex_State.InString && ( Buffer[ 1 ] != '\'' ) ) ) )
  421.             {
  422.                 // this most likely means unbalanced comments or strings
  423.                 Lex_State.Error = ERR_LEX_UNEXPECTED_EOF;
  424.                 break;
  425.             }
  426.         }
  427.     }
  428.  
  429.     // we've just found a token - return to calling programme
  430.  
  431.     #if( _LEX_DEBUG )
  432.     if( Lex_State.TokenID == TOK_ERROR_ID )
  433.     {    // if there's an error, print the offending character
  434.         if( Lex_Debug.ScreenOutput ) printf( "%c", Buffer[ 1 ] );
  435.         if( Lex_Debug.SourceOutput ) fprintf( LexDebugSourceFilePtr, "%c", Buffer[ 1 ] );
  436.         if( Lex_Debug.MixOutput ) fprintf( LexDebugMixFilePtr, "%c", Buffer[ 1 ] );
  437.     }
  438.     if( ( Lex_Debug.TokenOutput ) || ( Lex_Debug.ScreenOutput ) )
  439.     {
  440.         //if( Lex_Debug.ScreenOutput ) printf( "[T%i", Lex_State.TokenID );
  441.         if( Lex_Debug.TokenOutput ) fprintf( LexDebugTokenFilePtr, "[T%i", Lex_State.TokenID );
  442.         if( Lex_Debug.MixOutput ) fprintf( LexDebugMixFilePtr, "[T%i", Lex_State.TokenID );
  443.  
  444.         if( Lex_State.TokenID == TOK_IDENTIFIER_ID )
  445.         {    // token is a variable
  446.             if( Lex_State.LexemeID == LEX_VAR_ID )
  447.             {    // token is a symbol table entry
  448.                 //if( Lex_Debug.ScreenOutput ) printf( ":L%i:S%i]", Lex_State.LexemeID, Lex_State.VarID );
  449.                 if( Lex_Debug.TokenOutput ) fprintf( LexDebugTokenFilePtr, ":L%i:S%i]", Lex_State.LexemeID, Lex_State.VarID );
  450.                 if( Lex_Debug.MixOutput ) fprintf( LexDebugMixFilePtr, ":L%i:S%i]", Lex_State.LexemeID, Lex_State.VarID );
  451.             }
  452.             else
  453.             {    // token is a numeric value
  454.                 //if( Lex_Debug.ScreenOutput ) printf( ":L%i:Val%i]", Lex_State.LexemeID, Lex_State.VarID );
  455.                 if( Lex_Debug.TokenOutput ) fprintf( LexDebugTokenFilePtr, ":L%i:Val%i]", Lex_State.LexemeID, Lex_State.VarID );
  456.                 if( Lex_Debug.MixOutput ) fprintf( LexDebugMixFilePtr, ":L%i:Val%i]", Lex_State.LexemeID, Lex_State.VarID );
  457.             }
  458.         }
  459.         else
  460.         {    // token is a string, reserved word or operator
  461.             if( Lex_State.LexemeID )
  462.             {    // token is an operator
  463.                 //if( Lex_Debug.ScreenOutput ) printf( ":L%i]", Lex_State.LexemeID );
  464.                 if( Lex_Debug.TokenOutput ) fprintf( LexDebugTokenFilePtr, ":L%i]", Lex_State.LexemeID );
  465.                 if( Lex_Debug.MixOutput ) fprintf( LexDebugMixFilePtr, ":L%i]", Lex_State.LexemeID );
  466.             }
  467.             else
  468.             {    // token is a reserved word
  469.                 //if( Lex_Debug.ScreenOutput ) printf( "]" );
  470.                 if( Lex_Debug.TokenOutput ) fprintf( LexDebugTokenFilePtr, "]" );
  471.                 if( Lex_Debug.MixOutput ) fprintf( LexDebugMixFilePtr, "]" );
  472.             }
  473.         }
  474.     }
  475.     #endif
  476.  
  477.     return RC;
  478.  
  479. }
  480.  
  481.  
  482.  
  483. /*
  484.  *
  485.  */
  486. ERR SkipWhiteSpace( )
  487. {
  488.     ERR RC = ERR_OK;
  489.  
  490.     while( isspace( Buffer[ 1 ] ) )
  491.     {
  492.         // find the next non-white character
  493.         GetNextCharacter( );
  494.         if( Lex_State.Error )
  495.         {
  496.             if( Lex_State.Error != ERR_LEX_END_OF_FILE )
  497.             {
  498.                 LexError( Lex_State.Error );
  499.             }
  500.             else
  501.             {
  502.                 // eof was reached, so stop looking for non-white characters
  503.                 Lex_State.TokenID = TOK_END_OF_FILE_ID;
  504.                 break;
  505.             }
  506.         }
  507.     }
  508.     return RC;
  509. }
  510.  
  511.  
  512.  
  513. #if( _LEX_DEBUG )
  514. /*
  515.  *    FUNCTIN:  InitLexDebug
  516.  */
  517. ERR InitLexDebug( BOOL screen, BOOL source, BOOL token, BOOL mix )
  518. {
  519.     ERR RC = ERR_OK;
  520.  
  521.     Lex_Debug.ScreenOutput = screen;
  522.     Lex_Debug.SourceOutput = source;
  523.     Lex_Debug.TokenOutput = token;
  524.     Lex_Debug.MixOutput = mix;
  525.  
  526.     if( Lex_Debug.SourceOutput )
  527.     {
  528.         if( ! ( LexDebugSourceFilePtr = fopen( LEX_DEBUG_SOURCE_FILENAME, "wt" ) ) ) LexError( ERR_LEX_DEBUG_FILE_ERROR );
  529.     }
  530.  
  531.     if( Lex_Debug.TokenOutput )
  532.     {
  533.         if( ! ( LexDebugTokenFilePtr = fopen( LEX_DEBUG_TOKEN_FILENAME, "wt" ) ) ) LexError( ERR_LEX_DEBUG_FILE_ERROR );
  534.     }
  535.  
  536.     if( Lex_Debug.MixOutput )
  537.     {
  538.         if( ! ( LexDebugMixFilePtr = fopen( LEX_DEBUG_MIX_FILENAME, "wt" ) ) ) LexError( ERR_LEX_DEBUG_FILE_ERROR );
  539.     }
  540.  
  541.     LexDebugWrite( "\n%s\n", _LEX_VERSION );
  542.     if( Lex_Debug.ScreenOutput ) LexDebugWrite( "=> screen output enabled.\n" );
  543.         else LexDebugWrite( "=> screen output disabled.\n" );
  544.     if( Lex_Debug.SourceOutput ) LexDebugWrite( "=> source output to file \"%s\" enabled.\n", LEX_DEBUG_SOURCE_FILENAME );
  545.         else LexDebugWrite( "=> source output to file disabled.\n" );
  546.     if( Lex_Debug.TokenOutput ) LexDebugWrite( "=> token output to file \"%s\" enabled.\n", LEX_DEBUG_TOKEN_FILENAME );
  547.         else LexDebugWrite( "=> token output to file disabled.\n" );
  548.     if( Lex_Debug.MixOutput ) LexDebugWrite( "=> mix output to file \"%s\" enabled.\n", LEX_DEBUG_MIX_FILENAME );
  549.         else LexDebugWrite( "=> mix output to file disabled.\n" );
  550.  
  551.     return RC;
  552. }
  553. #endif
  554.  
  555.  
  556.  
  557. #if( _LEX_DEBUG )
  558. /*
  559.  *    FUNCTION:  ResetLexDebug
  560.  */
  561. ERR ResetLexDebug( )
  562. {
  563.     ERR RC = ERR_OK;
  564.  
  565.     if( Lex_State.Error != ERR_LEX_END_OF_FILE )
  566.     {
  567.         LexDebugWrite( "\nSource file:  %s\n", FileName );
  568.         LexDebugWrite( "Line number:  %i\n", Lex_State.LineNumber );
  569.         LexDebugWrite( "Char offset:  %i\n", Lex_State.CharOffset );
  570.     }
  571.     else
  572.     {
  573.         LexDebugWrite( "\n\nFinished reading file %s\n", FileName );
  574.     }
  575.  
  576.     if( Lex_Debug.SourceOutput ) fclose( LexDebugSourceFilePtr );
  577.     if( Lex_Debug.TokenOutput ) fclose( LexDebugTokenFilePtr );
  578.     if( Lex_Debug.MixOutput ) fclose( LexDebugMixFilePtr );
  579.  
  580.     return RC;
  581. }
  582. #endif
  583.  
  584.  
  585.  
  586. #if( _LEX_DEBUG )
  587. /*
  588.  *    FUNCTION:    LexDebugWrite
  589.  */
  590. ERR LexDebugWrite( UCHAR *text, ... )
  591. {
  592.     ERR RC = ERR_OK;
  593.  
  594.     va_list ptr;                /* va is a variable argument type implemented in newer revisions */
  595.     va_start( ptr, text );        /* of ANSI C.  Support library includes vfprintf, vprintf, vsprintf */
  596.  
  597.     // if screen debug output is enabled...
  598.     if( Lex_Debug.ScreenOutput ) vprintf( text, ptr );                            // ...then output to screen
  599.  
  600.     // if file debug source output is enabled...
  601.     if( Lex_Debug.SourceOutput ) vfprintf( LexDebugSourceFilePtr, text, ptr );    // ...then output to source file
  602.  
  603.     // if file debug token output is enabled...
  604.     if( Lex_Debug.TokenOutput ) vfprintf( LexDebugTokenFilePtr, text, ptr );    // ...then output to token file
  605.  
  606.     // if mix debug output is enabled...
  607.     if( Lex_Debug.MixOutput ) vfprintf( LexDebugMixFilePtr, text, ptr );        // ...then ouput to mix file
  608.  
  609.     va_end( ptr );
  610.  
  611.     return RC;
  612. }
  613. #endif
  614.  
  615.