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

  1. /*
  2.  *        C . A . P .   P A R S 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:    parser
  14.  *        File:        parser\parser.c
  15.  *        Version:    0.2.3
  16.  *
  17.  *        This file contains all of the source code that makes up the parser
  18.  *        used with the interpreter BILL.
  19.  */
  20.  
  21.  
  22.  
  23. /*
  24.  *    Versions:
  25.  *
  26.  *    0.0.1    - design of structure and implementation, Stéphane Charette, 94Mar27
  27.  *    0.0.2    - implemented procedures for top-down recursive descent, SC, 94Mar27-Apr10
  28.  *    0.1.0    - added simple pcode generator for basic functions, SC, 94Apr10-11
  29.  *    0.2.0    - included full-function pcode generator, SC, 94Apr11
  30.  *    0.2.1    - fixed various bugs occuring while generating pcode, SC, 94Apr11-13
  31.  *    0.2.2    - fixed odd functionality, SC, 94Apr14
  32.  *    0.2.2    - fixed while functionality, SC, 94Apr14-23
  33.  *    0.2.3    - ported to OS/2, SC, 94Apr23-27
  34.  *    0.2.3 - reformatted text, SC, 95Oct29
  35.  */
  36.  #define _PARSER_VERSION "Parser v0.2.2, Stéphane Charette, 95October29\n"
  37.  
  38.  
  39.  
  40. /*
  41.  *    Includes
  42.  */
  43.     #include "..\parser\parser.hi"        // internal parser include file
  44.  
  45.  
  46.  
  47. /*
  48.  *    FUNCTION:  InitParser
  49.  */
  50. ERR InitParser( UCHAR filename[] )
  51. {
  52.     ERR RC = ERR_OK;
  53.  
  54.     #if( _PARSER_DEBUG )
  55.     Parser_Debug.ScreenOutput = false;    // pre-initialize debug value
  56.     Parser_Debug.FileOutput = false;        // pre-initialize debug value
  57.     Parser_Debug.Indent = 0;                // indentation for parse tree
  58.     #endif
  59.  
  60.     Parser_State.Error = ERR_OK;            // internal symbol table error
  61.  
  62.     // is the path len valid?
  63.     if( strlen( filename ) > PARSER_MAX_PATH_LEN ) ParserError( ERR_PARSER_PATH_TOO_LONG );    //    is the path valid?
  64.     strcpy( Parser_State.Filename, filename );                                                    //    save the path of file
  65.  
  66.     // initialize the lexical analyzer
  67.     InitLex( filename );
  68.     #if( _LEX_DEBUG )
  69.     InitLexDebug( true, true, true, true );
  70.     #endif
  71.  
  72.     // initialize the symbol table
  73.     InitSymTable( );
  74.     #if( _SYMTABLE_DEBUG )
  75.     InitSymTableDebug( false, true );
  76.     #endif
  77.  
  78.     // initialize the pcoder
  79.     StartPCodeGenerator( );
  80.  
  81.     return RC;
  82. }
  83.  
  84.  
  85.  
  86. /*
  87.  *    FUNCTION:  ResetParser
  88.  */
  89. ERR ResetParser( )
  90. {
  91.     return ERR_OK;
  92. }
  93.  
  94.  
  95.  
  96. /*
  97.  *    FUNCTION:  ParserError
  98.  */
  99. void ParserError( ERR error_code )
  100. {
  101.     Parser_State.Error = error_code;
  102.  
  103.     printf( "\n\nError encountered in parser:  %i\n", Parser_State.Error );
  104.     printf( "Token in question:  \"%s\".\n\a", Lex_State.Token );
  105.     #if( _SYMTABLE_DEBUG )
  106.     ResetSymTableDebug( );                    // shutdown the debug procedures
  107.     #endif
  108.  
  109.     ResetParser( );                            // perform shutdown procedures
  110.  
  111.     ExitCode( error_code );                    // return to operating system
  112. }
  113.  
  114.  
  115.  
  116. /*
  117.  *    FUNCTION:  BeginParser
  118.  */
  119. ERR BeginParser( )
  120. {
  121.     ERR RC = ERR_OK;
  122.  
  123.     Parser_Program( );
  124.  
  125.     // write out the generated pcode
  126.     WritePCodeBuffer( );
  127.  
  128.     return RC;
  129. }
  130.  
  131.  
  132.  
  133. /*
  134.  *    FUNCTION:  Parser_Program
  135.  */
  136. void Parser_Program( )
  137. {
  138.     ERR RC;
  139.  
  140.     // get the first token - hopefully the keyword "program"
  141.     _AcceptNext( TOK_PROGRAM_ID, ERR_PARSER_PROGRAM_EXPCTD );
  142.  
  143.     // get the next token - hopefully an identifier
  144.     _AcceptNext( TOK_IDENTIFIER_ID, ERR_PARSER_IDENT_EXPCTD );
  145.  
  146.     // get the next token - hopefully a semi-colon
  147.     _AcceptNext( TOK_SEMICOLON_ID, ERR_PARSER_SEMICOLON_EXPCTD );
  148.  
  149.     Parser_Block( );                // get the "block" - the rest of the programme
  150.  
  151.     // look at the current token - hopefully a period
  152.     _AcceptNext( TOK_PERIOD_ID, ERR_PARSER_PERIOD_EXPCTD );
  153.  
  154.     // programme was recognized!
  155.     AddPCode( HLT );
  156.  
  157.     #if( _PARSER_DEBUG )
  158.     ParserDebugWrite( "\nFile parsed correctly.\n" );
  159.     #endif
  160.  
  161.     // if any code exists after the last period, it will be completely ignored...
  162.  
  163.     return;
  164. }
  165.  
  166.  
  167.  
  168. /*
  169.  *    FUNCTION:  Parser_Block
  170.  */
  171. void Parser_Block( )
  172. {
  173.     ERR RC;
  174.  
  175.     _GetNextToken;
  176.  
  177.     while( ( Lex_State.TokenID == TOK_CONST_ID ) || ( Lex_State.TokenID == TOK_VAR_ID ) )
  178.     {
  179.         // look at the current token - maybe the keyword "const"
  180.         if( Lex_State.TokenID == TOK_CONST_ID )    // is there a "const" section to this programme?
  181.         {                                                        // ...yes there is
  182.             Parser_Constdeclaration( );                // ...evaluate const declarations
  183.         }
  184.  
  185.         // look at the current token - maybe the keyword "var"
  186.         if( Lex_State.TokenID == TOK_VAR_ID )        // is there a "var" section to this programme?
  187.         {                                                        // ...yes there is
  188.             Parser_Vardeclaration( );                    // ...evaluate var declerations
  189.         }
  190.     }
  191.  
  192.     // the next token should be the "begin" keyword
  193.     Parser_Statementpart( );    // get the "statements" - the actual programme
  194.  
  195.     // now that the programme is done, there should only be an "end." left
  196.     _AcceptCurrent( TOK_END_ID, ERR_PARSER_END_EXPCTD );
  197.  
  198.     return;
  199. }
  200.  
  201.  
  202.     
  203. /*
  204.  *    FUNCTION:  Parser_Constdeclaration
  205.  */
  206. void Parser_Constdeclaration( )
  207. {
  208.     ERR RC;
  209.     UCHAR constname[LEX_MAX_TOKEN_LEN+1];
  210.     SHORT constindex;
  211.     USHORT number_of_consts = 0;
  212.     USHORT address_of_consts;
  213.  
  214.     address_of_consts = AddDPCode( INT, 0 );    // increment stack for constant declarations
  215.  
  216.     // we've recognized "const", so now lets read the identifiers/values
  217.     _GetNextToken;                                // get the const name
  218.     do
  219.     {
  220.         number_of_consts ++;                    // number of constants that we have found so far...
  221.  
  222.         if( ( Lex_State.TokenID != TOK_IDENTIFIER_ID ) || ( Lex_State.LexemeID != LEX_VAR_ID ) )
  223.             ParserError( ERR_PARSER_IDENT_EXPCTD );
  224.  
  225.         strcpy( constname, Lex_State.Token );    // store the name for when we'll update it
  226.         // register this with the symbol table
  227.         RC = NewTableEntry( &constindex, constname );
  228.         if( RC ) ParserError( RC );
  229.         if( constindex == SYM_DUPLICATE_ID ) ParserError( ERR_PARSER_REDEFINITION );
  230.  
  231.         // make current declaration into a constant
  232.         RC = TableMakeConst( constname );
  233.         if( RC ) ParserError( RC );
  234.  
  235.         // get the "=" symbol
  236.         _GetNextToken;                            // get the "=" symbol
  237.         if( ( Lex_State.TokenID != TOK_RELOP_ID ) || ( Lex_State.LexemeID != LEX_EQ_ID ) )
  238.             ParserError( ERR_PARSER_EQUAL_EXPCTD );
  239.  
  240.         // get the value for this token
  241.         _GetNextToken;                            // get the value to associate with this name
  242.         if( ( Lex_State.TokenID != TOK_IDENTIFIER_ID ) || ( Lex_State.LexemeID != LEX_VALUE_ID ) )
  243.             ParserError( ERR_PARSER_VALUE_EXPCTD );
  244.  
  245.         // assign the value to the constant
  246.         AddDPCode( LDI, constindex );
  247.         AddDPCode( LDI, Lex_State.VarID );
  248.         AddPCode( STO );
  249.  
  250.         // get the semicolon following this declaration
  251.         _AcceptNext( TOK_SEMICOLON_ID, ERR_PARSER_SEMICOLON_EXPCTD );
  252.  
  253.         // get the next token - could be another constant declaration or something new
  254.         _GetNextToken;
  255.     }
  256.     while( ( Lex_State.TokenID == TOK_IDENTIFIER_ID ) && ( Lex_State.LexemeID == LEX_VAR_ID ) );
  257.  
  258.     // make sure that the correct number of spaces are reserved on stack
  259.     UpdatePCode( address_of_consts, number_of_consts );
  260.  
  261.     return;
  262. }
  263.  
  264.  
  265.  
  266. /*
  267.  *    FUNCTION:  Parser_Vardeclaration
  268.  */
  269. void Parser_Vardeclaration( )
  270. {
  271.     ERR RC;
  272.     SHORT varindex;
  273.     USHORT number_of_vars = 0;
  274.     USHORT address_of_vars;
  275.  
  276.     address_of_vars = AddDPCode( INT, 0 );    // increment stack for variable declarations
  277.  
  278.  
  279.     // we've recognized "var", so now lets read the identifiers/values
  280.  
  281.     do
  282.     {
  283.         number_of_vars ++;                    // number of vars that we have found so far...
  284.  
  285.         // get the next identifier
  286.         _GetNextToken;                            // get the var name
  287.  
  288.         if( ( Lex_State.TokenID != TOK_IDENTIFIER_ID ) || ( Lex_State.LexemeID != LEX_VAR_ID ) )
  289.             ParserError( ERR_PARSER_IDENT_EXPCTD );
  290.  
  291.         // register this with the symbol table
  292.         RC = NewTableEntry( &varindex, Lex_State.Token );
  293.         if( RC ) ParserError( RC );
  294.         if( varindex == SYM_DUPLICATE_ID ) ParserError( ERR_PARSER_REDEFINITION );
  295.  
  296.         // get the token following this declaration
  297.         _GetNextToken;                            // get the comma (maybe) following the declaration
  298.     }
  299.     while( Lex_State.TokenID == TOK_COMMA_ID );
  300.  
  301.     // since we didn't just read a comma, it better be a semicolon
  302.     _AcceptCurrent( TOK_SEMICOLON_ID, ERR_PARSER_SEMICOLON_EXPCTD );
  303.  
  304.     // make sure that the correct number of spaces are reserved on stack
  305.     UpdatePCode( address_of_vars, number_of_vars );
  306.  
  307.     // get the next token - just to be ready for whatever comes after this var declaration
  308.     _GetNextToken;                                // get whatever comes next
  309.  
  310.     return;
  311. }
  312.  
  313.  
  314.  
  315. /*
  316.  *    FUNCTION:  Parser_Statementpart
  317.  */
  318. void Parser_Statementpart( )
  319. {
  320.     ERR RC = ERR_OK;
  321.     _AcceptCurrent( TOK_BEGIN_ID, ERR_PARSER_BEGIN_EXPCTD );
  322.     Parser_Statementsequence( );
  323.     _AcceptCurrent( TOK_END_ID, ERR_PARSER_END_EXPCTD );
  324.     return;
  325. }
  326.  
  327.  
  328.  
  329. /*
  330.  *    FUNCTION:  Parser_Statementsequence
  331.  */
  332. void Parser_Statementsequence( )
  333. {
  334.     ERR RC = ERR_OK;
  335.  
  336.     Parser_Statement( );
  337.     while( Lex_State.TokenID == TOK_SEMICOLON_ID )
  338.     {
  339.         _AcceptCurrent( TOK_SEMICOLON_ID, ERR_PARSER_SEMICOLON_EXPCTD );
  340.         Parser_Statement( );
  341.     }
  342.     return;
  343. }
  344.  
  345.  
  346.  
  347. /*
  348.  *  FUNCTION:  Parser_Statement
  349.  */
  350. void Parser_Statement( )
  351. {
  352.     ERR RC = ERR_OK;
  353.  
  354.     _GetNextToken;                                // get the next token
  355.  
  356.     switch( Lex_State.TokenID )
  357.     {
  358.         case TOK_BEGIN_ID:                    // BEGIN statement
  359.         {
  360.             Parser_Statementpart( );
  361.             _GetNextToken;                        // be prepared for what comes next
  362.             break;
  363.         }
  364.         case TOK_IDENTIFIER_ID:                // assignment
  365.         {
  366.             Parser_Assignment( );
  367.             break;
  368.         }
  369.         case TOK_IF_ID:                        // IF statement
  370.         {
  371.             Parser_Ifstatement( );
  372.             break;
  373.         }
  374.         case TOK_WHILE_ID:                    // WHILE statement
  375.         {
  376.             Parser_Whilestatement( );
  377.             break;
  378.         }
  379.         case TOK_WRITE_ID:                    // WRITE statement
  380.         {
  381.             Parser_Writestatement( );
  382.             break;
  383.         }
  384.         case TOK_READ_ID:                        // READ statement
  385.         {
  386.             Parser_Readstatement( );
  387.             _GetNextToken;                        // be prepared for what comes next
  388.             break;
  389.         }
  390.     }
  391.  
  392.     return;
  393. }
  394.  
  395.  
  396.  
  397. /*
  398.  *    FUNCTION:  Parser_Assignment
  399.  */
  400. void Parser_Assignment( )
  401. {
  402.     ERR RC = ERR_OK;
  403.     BOOL isconst;
  404.     SHORT index;
  405.  
  406.     _AcceptCurrent( TOK_IDENTIFIER_ID, ERR_PARSER_IDENT_EXPCTD );
  407.  
  408.     // is this identifier a constant?  (does it even exist?)
  409.     RC = TableIsConst( &isconst, Lex_State.Token );
  410.     if( RC ) ParserError( RC );
  411.     if( isconst ) ParserError( ERR_PARSER_CONST_REASSIGN );
  412.  
  413.     // get the index for this identifier
  414.     RC = GetTableEntry( &index, Lex_State.Token );
  415.     if( RC ) ParserError( RC );
  416.  
  417.     // note the address (index) of this assignment
  418.     AddDPCode( LDI, index );
  419.  
  420.     _AcceptNext( TOK_ASSIGNMENT_ID, ERR_PARSER_ASSIGN_EXPCTD );
  421.  
  422.     // find out what this assignment is worth
  423.     _GetNextToken;
  424.     Parser_Expression( );
  425.  
  426.     // perform the assignment
  427.     AddPCode( STO );
  428.  
  429.     return;
  430. }
  431.  
  432.  
  433.  
  434. /*
  435.  *    FUNCTION:  Parser_Expression
  436.  */
  437. void Parser_Expression( )
  438. {
  439.     ERR RC = ERR_OK;
  440.  
  441.     switch( Lex_State.TokenID )
  442.     {
  443.         case TOK_PLUS_ID:            // expression begins with "+"
  444.         {
  445.             _GetNextToken;
  446.             Parser_Term( );
  447.             AddPCode( ADD );
  448.             break;
  449.         }
  450.         case TOK_MINUS_ID:            // expression begins with "-"
  451.         {
  452.             _GetNextToken;
  453.             Parser_Term( );
  454.             AddPCode( NEG );
  455.             AddPCode( ADD );
  456.             break;
  457.         }
  458.         default:                    // expression does not start with "+" or "-"
  459.         {
  460.             Parser_Term( );
  461.         }
  462.     }
  463.  
  464.     if( ( Lex_State.TokenID == TOK_PLUS_ID ) || ( Lex_State.TokenID == TOK_MINUS_ID ) ) Parser_Expression( );
  465.  
  466.     return;
  467. }
  468.  
  469.  
  470.  
  471. /*
  472.  *    FUNCTION:  Parser_Term
  473.  */
  474. void Parser_Term( )
  475. {
  476.     ERR RC = ERR_OK;
  477.  
  478.     Parser_Factor( );
  479.  
  480.     while( ( Lex_State.TokenID == TOK_MULT_ID ) || ( Lex_State.TokenID == TOK_DIV_ID ) )
  481.     {
  482.         switch( Lex_State.TokenID )
  483.         {
  484.             case TOK_MULT_ID:
  485.             {
  486.                 _AcceptCurrent( TOK_MULT_ID, ERR_PARSER_GEN );
  487.                 _GetNextToken;
  488.                 Parser_Factor( );
  489.                 AddPCode( MUL );    // multiply
  490.                 break;
  491.             }
  492.             case TOK_DIV_ID:
  493.             {
  494.                 _AcceptCurrent( TOK_DIV_ID, ERR_PARSER_GEN );
  495.                 _GetNextToken;
  496.                 Parser_Factor( );
  497.                 AddPCode( DVD );    // divide
  498.                 break;
  499.             }
  500.         }
  501.     }
  502.  
  503.     return;
  504. }
  505.  
  506.  
  507.  
  508. /*
  509.  *    FUNCTION:  Parser_Factor
  510.  */
  511. void Parser_Factor( )
  512. {
  513.     ERR RC = ERR_OK;
  514.  
  515.     switch( Lex_State.TokenID )
  516.     {
  517.         case TOK_IDENTIFIER_ID:
  518.         {
  519.             switch( Lex_State.LexemeID )
  520.             {
  521.                 case LEX_VALUE_ID:    // token is a numeric value
  522.                 {
  523.                     AddDPCode( LDI, Lex_State.VarID );
  524.                     break;
  525.                 }
  526.                 case LEX_VAR_ID:        // token is a variable
  527.                 {
  528.                     SHORT index;
  529.  
  530.                     RC = GetTableEntry( &index, Lex_State.Token );
  531.                     if( RC ) ParserError( RC );
  532.                     AddDPCode( LDI, index );
  533.                     AddPCode( LDV );
  534.                     break;
  535.                 }
  536.             }
  537.             break;
  538.         }
  539.         case TOK_PO_ID:                // parentheses open
  540.         {
  541.             _AcceptCurrent( TOK_PO_ID, ERR_PARSER_GEN );
  542.             _GetNextToken;
  543.             Parser_Expression( );
  544.             _AcceptCurrent( TOK_PC_ID, ERR_PARSER_PARENTC_EXPCTD );
  545.             break;
  546.         }
  547.     }
  548.     // just to be ready for whatever comes next
  549.     _GetNextToken;
  550.     return;
  551. }
  552.  
  553.  
  554.  
  555. /*
  556.  *    FUNCTION:  Parser_Ifstatement
  557.  */
  558. void Parser_Ifstatement( )
  559. {
  560.     ERR RC = ERR_OK;
  561.     USHORT address;
  562.  
  563.     _AcceptCurrent( TOK_IF_ID, ERR_PARSER_GEN );
  564.     Parser_Condition( );
  565.     address = AddDPCode( BZE, 0 );
  566.     _AcceptCurrent( TOK_THEN_ID, ERR_PARSER_THEN_EXPCTD );
  567.     Parser_Statement( );
  568.  
  569.     UpdatePCode( address, (SHORT)GetCurrentIndex( ) );
  570.  
  571.     return;
  572. }
  573.  
  574.  
  575.  
  576. /*
  577.  *    FUNCTION:  Parser_Whilestatement
  578.  */
  579. void Parser_Whilestatement( )
  580. {
  581.     ERR RC = ERR_OK;
  582.     USHORT newaddress;
  583.     USHORT oldaddress;
  584.  
  585.     _AcceptCurrent( TOK_WHILE_ID, ERR_PARSER_GEN );
  586.     oldaddress = GetCurrentIndex( );
  587.     Parser_Condition( );
  588.     newaddress = AddDPCode( BZE, 0 );
  589.     _AcceptCurrent( TOK_DO_ID, ERR_PARSER_DO_EXPCTD );
  590.     Parser_Statement( );
  591.     AddDPCode( BRN, (SHORT)(oldaddress - 1) );
  592.  
  593.     UpdatePCode( newaddress, (SHORT)GetCurrentIndex( ) );
  594.  
  595.     return;
  596. }
  597.  
  598.  
  599.  
  600. /*
  601.  *    FUNCTION:  Parser_Writestatement
  602.  */
  603. void Parser_Writestatement( )
  604. {
  605.     ERR RC = ERR_OK;
  606.  
  607.     _AcceptCurrent( TOK_WRITE_ID, ERR_PARSER_GEN );
  608.     _GetNextToken;
  609.     if( Lex_State.TokenID == TOK_PO_ID )
  610.     {
  611.         _AcceptCurrent( TOK_PO_ID, ERR_PARSER_GEN );
  612.         Parser_Writelist( );
  613.         _AcceptCurrent( TOK_PC_ID, ERR_PARSER_PARENTC_EXPCTD );
  614.         _GetNextToken;
  615.     }
  616.  
  617.     AddPCode( NLN );    // print a new line (carriage-return/line-feed) after all the printing is done
  618.  
  619.     return;
  620. }
  621.  
  622.  
  623.  
  624. /*
  625.  *    FUNCTION:  Parser_Readstatement
  626.  */
  627. void Parser_Readstatement( )
  628. {
  629.     ERR RC = ERR_OK;
  630.  
  631.     _AcceptCurrent( TOK_READ_ID, ERR_PARSER_GEN );
  632.     _AcceptNext( TOK_PO_ID, ERR_PARSER_PARENTO_EXPCTD );
  633.     Parser_Identsequence( );
  634.     _AcceptCurrent( TOK_PC_ID, ERR_PARSER_PARENTC_EXPCTD );
  635.  
  636.     return;
  637. }
  638.  
  639.  
  640.  
  641. /*
  642.  *    FUNCTION:  Parser_Identsequence
  643.  */
  644. void Parser_Identsequence( )
  645. {
  646.     ERR RC = ERR_OK;
  647.     BOOL isconst;
  648.     SHORT index;
  649.  
  650.     do
  651.     {
  652.         _AcceptNext( TOK_IDENTIFIER_ID, ERR_PARSER_IDENT_EXPCTD );
  653.         // is this identifier a constant?  (does it even exist?)
  654.         RC = TableIsConst( &isconst, Lex_State.Token );
  655.         if( RC ) ParserError( RC );
  656.         if( isconst ) ParserError( ERR_PARSER_CONST_REASSIGN );
  657.  
  658.         // get the index for this identifier
  659.         RC = GetTableEntry( &index, Lex_State.Token );
  660.         if( RC ) ParserError( RC );
  661.  
  662.         // note the address (index) for this assignment
  663.         AddDPCode( LDI, index );
  664.  
  665.         // read in the value
  666.         AddPCode( INN );
  667.  
  668.         _GetNextToken;                // maybe a comma?
  669.     }
  670.     while( Lex_State.TokenID == TOK_COMMA_ID );
  671.  
  672.     return;
  673. }
  674.  
  675.  
  676.  
  677. /*
  678.  *    FUNCTION:  Parser_Condition
  679.  */
  680. void Parser_Condition( )
  681. {
  682.     ERR RC = ERR_OK;
  683.  
  684.     _GetNextToken;
  685.  
  686.     if( Lex_State.TokenID == TOK_ODD_ID )
  687.     {
  688.         _AcceptCurrent( TOK_ODD_ID, ERR_PARSER_GEN );
  689.         _AcceptNext( TOK_PO_ID, ERR_PARSER_PARENTO_EXPCTD );
  690.         _GetNextToken;
  691.         Parser_Expression( );
  692.         _AcceptCurrent( TOK_PC_ID, ERR_PARSER_PARENTC_EXPCTD );
  693.         AddPCode( OD );
  694.         _GetNextToken;
  695.     }
  696.     else
  697.     {
  698.         Parser_Expression( );
  699.         _AcceptCurrent( TOK_RELOP_ID, ERR_PARSER_RELOP_EXPCTD );
  700.         switch( Lex_State.LexemeID )
  701.         {
  702.             case LEX_EQ_ID:
  703.             {
  704.                 _GetNextToken;
  705.                 Parser_Expression( );
  706.                 AddPCode( EQL );
  707.                 break;
  708.             }
  709.             case LEX_NE_ID:
  710.             {
  711.                 _GetNextToken;
  712.                 Parser_Expression( );
  713.                 AddPCode( NEQ );
  714.                 break;
  715.             }
  716.             case LEX_LE_ID:
  717.             {
  718.                 _GetNextToken;
  719.                 Parser_Expression( );
  720.                 AddPCode( LEQ );
  721.                 break;
  722.             }
  723.             case LEX_LT_ID:
  724.             {
  725.                 _GetNextToken;
  726.                 Parser_Expression( );
  727.                 AddPCode( LSS );
  728.                 break;
  729.             }
  730.             case LEX_GE_ID:
  731.             {
  732.                 _GetNextToken;
  733.                 Parser_Expression( );
  734.                 AddPCode( GEQ );
  735.                 break;
  736.             }
  737.             case LEX_GT_ID:
  738.             {
  739.                 _GetNextToken;
  740.                 Parser_Expression( );
  741.                 AddPCode( GTR );
  742.                 break;
  743.             }
  744.         }
  745.     }
  746.  
  747.     return;
  748. }
  749.  
  750.  
  751.  
  752. /*
  753.  *    FUNCTION:  Parser_Writelist
  754.  */
  755. void Parser_Writelist( )
  756. {
  757.     ERR RC = ERR_OK;
  758.     _GetNextToken;
  759.  
  760.     do
  761.     {
  762.         if( Lex_State.TokenID == TOK_COMMA_ID )
  763.         {
  764.             _AcceptCurrent( TOK_COMMA_ID, ERR_PARSER_GEN );
  765.             _GetNextToken;
  766.         }
  767.  
  768.         switch( Lex_State.TokenID )
  769.         {
  770.             case TOK_STRING_ID:
  771.             {
  772.                 SHORT stringlen = 0;
  773.                 while( Lex_State.Token[stringlen] != '\0' )
  774.                 {
  775.                     AddDPCode( LDI, (SHORT)Lex_State.Token[stringlen] );
  776.                     stringlen ++;
  777.                 }
  778.                 AddDPCode( LDI, stringlen );
  779.                 AddPCode( PRS );            // print the string
  780.                 _GetNextToken;
  781.                 break;
  782.             }
  783.             case TOK_IDENTIFIER_ID:
  784.             {
  785.                 switch( Lex_State.LexemeID )
  786.                 {
  787.                     case LEX_VALUE_ID:    // token is a numeric value
  788.                     {
  789.                         AddDPCode( LDI, Lex_State.VarID );
  790.                         break;
  791.                     }
  792.                     case LEX_VAR_ID:        // token is a variable
  793.                     {
  794.                         SHORT index;
  795.                         // get the index for this identifier
  796.                         RC = GetTableEntry( &index, Lex_State.Token );
  797.                         if( RC ) ParserError( RC );
  798.                         // note the address (index) for this assignment
  799.                         AddDPCode( LDI, index );
  800.                         AddPCode( LDV );    // dereference the address
  801.                         break;
  802.                     }
  803.                 }
  804.                 AddPCode( PRN );            // print the bugger
  805.                 _GetNextToken;
  806.                 break;
  807.             }
  808.             default:
  809.             {
  810.                 Parser_Expression( );
  811.                 AddPCode( PRN );            // print the value
  812.                 break;
  813.             }
  814.         }
  815.     }
  816.     while( Lex_State.TokenID == TOK_COMMA_ID );
  817.  
  818.     return;
  819. }
  820.  
  821.  
  822.  
  823. #if( _PARSER_DEBUG )
  824. /*
  825.  *    FUNCTION:  InitParserDebug
  826.  */
  827. ERR InitParserDebug( BOOL screen, BOOL source )
  828. {
  829.     ERR RC = ERR_OK;
  830.  
  831.     Parser_Debug.ScreenOutput = screen;
  832.     Parser_Debug.FileOutput = source;
  833.  
  834.     if( Parser_Debug.FileOutput )
  835.     {
  836.         if( ! ( ParserDebugFilePtr = fopen( PARSER_DEBUG_FILENAME, "wt" ) ) ) ParserError( ERR_PARSER_DEBUG_FILE_ERROR );
  837.     }
  838.  
  839.     ParserDebugWrite( "\n%s\n", _PARSER_VERSION );
  840.     if( Parser_Debug.ScreenOutput ) ParserDebugWrite( "=> screen output enabled.\n" );
  841.         else ParserDebugWrite( "=> screen output disabled.\n" );
  842.     if( Parser_Debug.FileOutput ) ParserDebugWrite( "=> output to file \"%s\" enabled.\n", PARSER_DEBUG_FILENAME );
  843.         else ParserDebugWrite( "=> output to file disabled.\n" );
  844.  
  845.     return RC;
  846. }
  847. #endif
  848.  
  849.  
  850.  
  851. #if( _PARSER_DEBUG )
  852. /*
  853.  *    FUNCTION:  ResetParserDebug
  854.  */
  855. ERR ResetParserDebug( )
  856. {
  857.     ERR RC = ERR_OK;
  858.  
  859.     if( Parser_State.Error ) ParserDebugWrite( "\n\nError encountered in parser:  %i\n\a", Parser_State.Error );
  860.  
  861.     if( Parser_Debug.FileOutput ) fclose( ParserDebugFilePtr );
  862.  
  863.     return RC;
  864. }
  865. #endif
  866.  
  867.  
  868.  
  869. #if( _PARSER_DEBUG )
  870. /*
  871.  *    FUNCTION:    ParserDebugWrite
  872.  */
  873. ERR ParserDebugWrite( UCHAR *text, ... )
  874. {
  875.     ERR RC = ERR_OK;
  876.  
  877.     va_list ptr;                    /* va is a variable argument type implemented in newer revisions */
  878.     va_start( ptr, text );        /* of ANSI C.  Support library includes vfprintf, vprintf, vsprintf */
  879.  
  880.     // if screen debug output is enabled...
  881.     if( Parser_Debug.ScreenOutput ) vprintf( text, ptr );                                // ...then output to screen
  882.  
  883.     // if file debug output is enabled...
  884.     if( Parser_Debug.FileOutput ) vfprintf( ParserDebugFilePtr, text, ptr );    // ...then output to file
  885.  
  886.     va_end( ptr );
  887.  
  888.     return RC;
  889. }
  890. #endif
  891.  
  892.