| home | contents | previous | next page | send comment | send link | add bookmark |

PRS_MAIN.CPP

main parser

/*-------------------------------------------------------------------*
     Parser for the program, declared procedures and functions

     File:     prs_main.cpp

     Module:   parser

     by:  Stephen R. Schmitt
 *-------------------------------------------------------------------*/

#include "tpl_data.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>

/*
 *   External variables
 */
       /* in tpl_main.cpp */
extern bool Debug_flag;
       /* in scn_main.cpp */
extern token_struct Token;
extern token_struct Next_token;
extern TOKEN_CODE Stmt_start_list[];
extern TOKEN_CODE Decl_start_list[];
extern TOKEN_CODE Pass_one_list[];
extern TOKEN_CODE Pass_two_list[];
extern TOKEN_CODE Pass_end_list[];
extern TOKEN_CODE Data_decl_list[];
extern TOKEN_CODE Rtne_stmt_list[];
extern TOKEN_CODE Rtne_end_list[];
       /* in sym_tabl.cpp */
extern int Scope;
extern SYMTAB_NODE_PTR Symbol_table[];
extern TYPE_STRUCT_PTR Integer_typep, Real_typep,
		       Boolean_typep, Char_typep,
		       String_typep,  Null_typep;
       /* in prs_decl.cpp */
extern SYMTAB_NODE_PTR Last_rtne_idp;
       /* in prs_emit.cpp */
extern int Routine_number;

/*
 *   Global variables
 */
bool Routine_flag;
bool Result_flag;

/*-------------------------------------------------------------------*
			 Code Section
 *-------------------------------------------------------------------*/

/*
 *   "pass_one" processes the first pass on an entire program
 *
 *   returns:  nothing
 */
void pass_one()
{
    SYMTAB_NODE_PTR prog_idp,                       // "program"
                    last_idp,                       // main data
                    main_idp;                       // "_main"

    init_symtab();
    init_emit();

    // create main node
    main_idp = insert("_main", &Symbol_table[Scope]);
    main_idp->definition = MAIN_DEFN;
    main_idp->routine.parm_count = 0;
    main_idp->routine.segment = 0;
    main_idp->typep = Null_typep;

    Last_rtne_idp = main_idp;                       // for chaining id's
    last_idp = Last_rtne_idp;

    Routine_flag = false;

    get_token();                                    // first in source file

    while (Token.code != END_OF_FILE)               // process main segment
    {
        if (token_in(Data_decl_list))
        {
            declaration();
	    last_idp = Last_rtne_idp;               // save for main data
        }
        else if (Token.code == PROGRAM)
            program_header();
        else if (Token.code == PROCEDURE)
            procedure_header();
        else if (Token.code == FUNCTION)
            function_header();

        Last_rtne_idp = last_idp;                   // reset for main data

        if ((!token_in(Pass_one_list)) &&
            (!token_in(Pass_end_list)))
        {
            compile_error(M_SYNTAX, M_ERROR, M_0);
            synchronize(Pass_one_list, Pass_end_list, NULL);
        }
    }

    // jump to program at completion of main segment processing
    prog_idp = lookup("_program", Symbol_table[Scope]);
    if (prog_idp == NULL)
        compile_error(M_PROGRAM, M_UNDEFINED, M_0);
    else
    {
        emit_statement_marker(prog_idp->routine.file,
                              prog_idp->routine.line);
        emit_operator(CALL, NO_CODE, 1, 0);         // prog is seg 1
    }

    emit_operator(RETP, NO_CODE, 0, 0);
    emit_code_segment(main_idp);                    // for main program
}

/*
 *   "pass_two" processes the subprograms in an entire program
 *
 *   returns:  nothing
 */
void pass_two()
{
    get_token();                                    // first in source file

    while (Token.code != END_OF_FILE)               // process code segment
    {
        if (Token.code == PROGRAM)
            program_body();
        else if (Token.code == PROCEDURE)
            procedure_body();
        else if (Token.code == FUNCTION)
            function_body();

        synchronize(Pass_two_list, NULL, NULL);
    }

    exit_emit();
}

/*
 *   "program_header" processes the program module header:
 *
 *       program                                            % header
 *           <declarations and statements>                  % body
 *       end program
 *
 *   returns:  nothing
 */
void program_header()
{
    SYMTAB_NODE_PTR prog_idp;

    prog_idp = lookup("_program", Symbol_table[Scope]);
    if (prog_idp == NULL)
    {
        prog_idp = insert("_program", &Symbol_table[Scope]);
        prog_idp->definition = PROG_DEFN;
        prog_idp->routine.parm_count = 0;
        prog_idp->routine.segment = 1;
        strcpy(prog_idp->routine.file, Token.file);
        prog_idp->routine.line = Token.line;
        prog_idp->typep = Null_typep;
    }
    else
        compile_error(M_PROGRAM, M_REDEFINED, M_0);

    while (!((Token.code == END) &&
 	     (Next_token.code == PROGRAM)))
    {
        get_token();
        if (Token.code == END_OF_FILE)
        {
            compile_error(M_SYNTAX, M_ERROR, M_0);
            break;
        }
    }
    get_token();                                    // after "end"
    get_token();                                    // after "program"
}

/*
 *   "program_body" processes the program module body:
 *
 *       program                                            % header
 *           <declarations and statements>                  % body
 *       end program
 *
 *   returns:  nothing
 */
void program_body()
{
    SYMTAB_NODE_PTR prog_idp;

    prog_idp = lookup("_program", Symbol_table[Scope]);
    assert(prog_idp != NULL);

    get_token();                                    // after "program"

    Last_rtne_idp = prog_idp;                       // for chaining id's

    incr_scope();
    Routine_flag = true;

    parse_block(prog_idp,
		Data_decl_list, Rtne_stmt_list, Rtne_end_list);

    decr_scope();

    if_code_get_token_else_error(END);

    if (Token.code == PROGRAM)
    {
        emit_code_label(0);
        emit_statement_marker(Token.file, Token.line);
        emit_pop_local_parm(prog_idp);
        emit_operator(POP, REG_BP, 0, 0);
        emit_operator(RETF, NO_CODE, 0, 0);
        emit_code_segment(prog_idp);
        Routine_flag = false;

        get_token();
    }
    else
        compile_error(M_MISSING, M_PROGRAM, M_0);
}

/*
 *   "procedure_header" processes a procedure_header during pass one:
 *
 *       procedure <id>[(<formal parameters>)]          % header
 *           <declarations and statements>              % body
 *       end <id>
 *
 *   returns:  nothing
 */
void procedure_header()
{
    SYMTAB_NODE_PTR proc_idp;                       // for procedure

    get_token();                                    // after "procedure"

    if (Token.code == ID_TOKEN)
    {
        proc_idp = lookup(Token.lexeme, Symbol_table[Scope]);
        if (proc_idp == NULL)
        {
            proc_idp = insert(Token.lexeme, &Symbol_table[Scope]);
            proc_idp->definition = PROC_DEFN;
            proc_idp->routine.parm_count = 0;
            proc_idp->routine.segment = Routine_number++;
            strcpy(proc_idp->routine.file, Token.file);
            proc_idp->routine.line = Token.line;
            proc_idp->typep = Null_typep;
        }
        else
        {
            compile_error(M_REDEFINED, M_IDENTIFIER, M_0);
            goto procedure_header_exit;
        }
    }
    else
    {
        compile_error(M_MISSING, M_IDENTIFIER, M_0);
        goto procedure_header_exit;
    }

    get_token();                                    // after <id>

    if (Token.code == L_PAREN)
    {
        Last_rtne_idp = proc_idp;                   // for chaining id's
        incr_scope();
        proc_idp->routine.parm_count = formal_parameters();
        decr_scope();
    }

procedure_header_exit:
    while (!((Token.code == END) &&
             (Next_token.code == ID_TOKEN)))
    {
        get_token();
        if (Token.code == END_OF_FILE)
        {
            compile_error(M_SYNTAX, M_ERROR, M_0);
            break;
        }
    }
    get_token();                                    // after "end"
    get_token();                                    // after <id>
}

/*
 *   "procedure_body" processes a procedure body during pass two:
 *
 *       procedure <id>[(<formal parameters>)]          %header
 *           <declarations and statements>              %body
 *       end <id>
 *
 *   returns:  nothing
 */
void procedure_body()
{
    SYMTAB_NODE_PTR idp, proc_idp;                  // for procedure

    get_token();                                    // after "procedure"

    assert(Token.code == ID_TOKEN);
    proc_idp = lookup(Token.lexeme, Symbol_table[Scope]);
    assert(proc_idp != NULL);

    get_token();                                    // after <id>

    if (Token.code == L_PAREN)
    {
        while (Token.code != R_PAREN)
            get_token();                            // after "("

        get_token();                                // after ")"
    }

    Last_rtne_idp = proc_idp;                       // for chaining id's
    Routine_flag = true;
    incr_scope();
    Symbol_table[Scope] = proc_idp->next;
    idp = proc_idp->next;

    while (idp != NULL)                             // find last param idp
    {
        Last_rtne_idp = idp;
        idp = idp->next;
    }

    parse_block(proc_idp,
		Data_decl_list, Rtne_stmt_list, Rtne_end_list);

    decr_scope();

    if_code_get_token_else_error(END);

    if (Token.code == ID_TOKEN)
    {
        idp = lookup(Token.lexeme, Symbol_table[Scope]);
        if (idp == NULL)
	    compile_error(M_UNDEFINED, M_IDENTIFIER, M_0);
        else if (idp != proc_idp)
            compile_error(M_REDEFINED, M_IDENTIFIER, M_0);

        emit_code_label(0);
        emit_statement_marker(Token.file, Token.line);
        emit_pop_local_parm(proc_idp);
        emit_operator(POP, REG_BP, 0, 0);
        emit_operator(RETF, NO_CODE, 0, 0);
        emit_code_segment(proc_idp);
        Routine_flag = false;

        get_token();                                // after <id>
    }
    else
        compile_error(M_MISSING, M_IDENTIFIER, M_0);
}

/*
 *   "function_header" processes a function header:
 *
 *   function <id>[(<formal parameters>)] : <type spec> %header
 *      <declarations and statements>                   %body
 *   end <id>
 *
 *   returns:  nothing
 */
void function_header()
{
    SYMTAB_NODE_PTR func_idp;                       // for the function

    get_token();                                    // after "function"

    if (Token.code == ID_TOKEN)
    {
        func_idp = lookup(Token.lexeme, Symbol_table[Scope]);
        if (func_idp == NULL)
        {
            func_idp = insert(Token.lexeme, &Symbol_table[Scope]);
            func_idp->definition = FUNC_DEFN;
            func_idp->routine.parm_count = 0;
            func_idp->routine.segment = Routine_number++;
            strcpy(func_idp->routine.file, Token.file);
            func_idp->routine.line = Token.line;
            func_idp->typep = Null_typep;
        }
        else
        {
            compile_error(M_REDEFINED, M_IDENTIFIER, M_0);
            goto function_header_exit;
        }
    }
    else
    {
        compile_error(M_MISSING, M_IDENTIFIER, M_0);
        goto function_header_exit;
    }

    get_token();                                    // after <id>

    if (Token.code == L_PAREN)
    {
        Last_rtne_idp = func_idp;                   // for chaining id's
        incr_scope();
        func_idp->routine.parm_count = formal_parameters();
        decr_scope();
    }

    if (Token.code == COLON)
    {
        get_token();                                // after ":"
        func_idp->typep = do_type();                // and get next token
    }
    else
    {
        compile_error(M_MISSING, M_COLON, M_0);
        goto function_header_exit;
    }

function_header_exit:
    while (!((Token.code == END) &&
             (Next_token.code == ID_TOKEN)))
    {
       get_token();
       if (Token.code == END_OF_FILE)
       {
            compile_error(M_SYNTAX, M_ERROR, M_0);
            break;
       }
    }
    get_token();                                    // after "end"
    get_token();                                    // after <id>
}

/*
 *   "function_body" processes a function body:
 *
 *   function <id>[(<formal parameters> })] : <type spec> %header
 *      <declarations and statements>                       %body
 *   end <id>
 *
 *   returns:  nothing
 */
void function_body()
{
    SYMTAB_NODE_PTR idp, func_idp;                  // for the function

    get_token();                                    // after "function"

    assert(Token.code == ID_TOKEN);
    func_idp = lookup(Token.lexeme, Symbol_table[Scope]);
    assert(func_idp != NULL);

    get_token();                                    // after <id>

    if (Token.code == L_PAREN)
    {
        while (Token.code != R_PAREN)
            get_token();                            // after "("

        get_token();                                // after ")"
    }

    assert(Token.code == COLON);
    get_token();                                    // after ":"
    do_type();                                      // and get next token

    Last_rtne_idp = func_idp;                       // for chaining id's
    Routine_flag = true;
    Result_flag = false;
    incr_scope();
    Symbol_table[Scope] = func_idp->next;
    idp = func_idp->next;

    while (idp != NULL)                             // find last param idp
    {
        Last_rtne_idp = idp;
        idp = idp->next;
    }

    parse_block(func_idp,
		Data_decl_list, Rtne_stmt_list, Rtne_end_list);

    if (Result_flag == false)
        compile_error(M_MISSING, M_RETURN, M_OF, M_VALUE, M_0);

    decr_scope();

    if_code_get_token_else_error(END);

    if (Token.code == ID_TOKEN)
    {
        idp = lookup(Token.lexeme, Symbol_table[Scope]);
        if (idp != func_idp)
            compile_error(M_REDEFINED, M_IDENTIFIER, M_0);
        else if (idp == NULL)
            compile_error(M_UNDEFINED, M_IDENTIFIER, M_0);

        emit_code_label(0);
        emit_statement_marker(Token.file, Token.line);
        emit_pop_local_parm(func_idp);
        emit_operator(POP, REG_BP, 0, 0);
        emit_operator(RETF, NO_CODE, 0, 0);
        emit_code_segment(func_idp);
        Routine_flag = false;
        Result_flag = false;

        get_token();                                // after <id>
    }
    else
        compile_error(M_MISSING, M_IDENTIFIER, M_0);
}

/*
 *   "formal_parameters" processes a list of formal parameters in
 *   a function or procedure declaration:
 *
 *       ([var] <id> {, <id>} : <type spec> {,
 *        [var] <id> {, <id>} : <type spec> } )
 *
 *   and returns a pointer to the beginning of the parameter list.
 *
 *   returns:  the number of parameters
 */
int formal_parameters()
{
    DEFN_KEY parm_defn;                             // of parameter
    TYPE_STRUCT_PTR parm_tp;                        // of parameter
    SYMTAB_NODE_PTR parm_idp, first_idp, last_idp;
    SYMTAB_NODE_PTR prev_last_idp = NULL;           // initialize
    int parm_count  = 0;
    int parm_offset = 0;

    get_token();                                    // after "("

    while ((Token.code == ID_TOKEN) || (Token.code == VAR))
    {
        first_idp = NULL;

        if (Token.code == VAR)
        {
            parm_defn = VARPARM_DEFN;
            get_token();                            // after "var"
        }
        else
            parm_defn = VALPARM_DEFN;

        while (Token.code == ID_TOKEN)
        {
            parm_idp = lookup(Token.lexeme, Symbol_table[Scope]);
            if (parm_idp == NULL)
                parm_idp = insert(Token.lexeme, &Symbol_table[Scope]);
            else
                compile_error(M_REDEFINED, M_IDENTIFIER, M_0);

            parm_idp->definition = parm_defn;
            parm_idp->initialized = true;           // must be initialized
            parm_count++;

            if (first_idp == NULL)                  // first parameter?
            {
                Last_rtne_idp->next = parm_idp;
                parm_idp->prev = Last_rtne_idp;

                first_idp = parm_idp;
                last_idp = parm_idp;
            }
            else                                    // link <id>s together
            {
                last_idp->next = parm_idp;          // ptr to current <id>
                parm_idp->prev = last_idp;
                last_idp = parm_idp;                // reset last <id> ptr
            }

            get_token();                            // after <id>

            if (Token.code == COMMA)
                get_token();                        // after ","
        }

        Last_rtne_idp = parm_idp;                   // for next declaration

        if_code_get_token_else_error(COLON);

        parm_tp = do_type();                        // and get token

        if (parm_defn == VALPARM_DEFN)
        {
            if ((parm_tp == Real_typep       )||
                (parm_tp == Integer_typep    )||
                (parm_tp == Boolean_typep    )||
	        (parm_tp == Char_typep       )||
                (parm_tp->form == ENUM_FORM  )||
                (parm_tp->form == STRING_FORM))
                /* ok */;
            else
                compile_error(M_INVALID, M_TYPE, M_0);
        }

        for (parm_idp = first_idp;                  // assign offset values
             parm_idp != NULL;                      // to all <id>s in the
	     parm_idp = parm_idp->next)             // sublist
        {
	    parm_idp->typep = parm_tp;
            parm_idp->data_offset = parm_offset++;
        }

        if (prev_last_idp != NULL)                  // link sublist to last
            prev_last_idp->next = first_idp;        // sublist

        prev_last_idp = last_idp;

        if (Token.code == COMMA)
            get_token();                            // after ","
    }

    if_code_get_token_else_error(R_PAREN);

    return parm_count;
}

/*
 *   "declared_routine_call" processes a call to a declared
 *   procedure or function:
 *
 *     <id> [(parameterDeclaration {, parameterDeclaration})]
 *
 *   The actual parameters are checked for correct type and number.
 *   A pointer is returned to the type structure of the call.
 *
 *   returns:  a pointer to the type structure of the return
 *             value of a function or NULL if a procedure
 */
TYPE_STRUCT_PTR declared_routine_call(SYMTAB_NODE_PTR rtn_idp)
{
    TYPE_STRUCT_PTR rtn_tp;                         // return value

    if (rtn_idp->definition == FUNC_DEFN)
    {
        // return a value
        rtn_tp = rtn_idp->typep;
        if (rtn_tp->form == STRING_FORM)
            emit_operator(INC_sp_string, NO_CODE, 0, 0);
        else
            emit_operator(INC_sp, NO_CODE, 0, 0);
    }
    else
        rtn_tp = NULL;

    // jump to new segment
    if (Debug_flag)
        emit_operator(SKIP, NO_CODE, 0, 0);
    emit_statement_marker(rtn_idp->routine.file,
			  rtn_idp->routine.line);
    actual_parameters(rtn_idp);
    emit_operator(CALL, NO_CODE, rtn_idp->routine.segment, 0);
    emit_pop_formal_parm(rtn_idp);

    if (Debug_flag)
        emit_operator(UNSKIP, NO_CODE, 0, 0);

    return rtn_tp;
}

/*
 *   "actual_parameters" processes a list of actual parameters in
 *   a declared function or procedure call.
 *
 *   returns:  nothing
 */
void actual_parameters(SYMTAB_NODE_PTR rtn_idp)     // of subroutine
{
    SYMTAB_NODE_PTR formal_parm_idp, idp;
    DEFN_KEY formal_parm_defn;
    TYPE_STRUCT_PTR formal_parm_tp, actual_parm_tp;
    int formal_parm_count, actual_parm_count;

    formal_parm_idp = rtn_idp->next;
    formal_parm_count = rtn_idp->routine.parm_count;
    actual_parm_count = 0;

    if (Token.code == L_PAREN)
    {
        while ((Token.code == L_PAREN) || (Token.code == COMMA))
        {
            get_token();                            // after "(" or ","

            actual_parm_count++;

            if (formal_parm_idp != NULL)
            {
                formal_parm_defn = formal_parm_idp->definition;
                formal_parm_tp = formal_parm_idp->typep;
            }

            if (formal_parm_defn == VALPARM_DEFN)
            {
                if (formal_parm_tp == Boolean_typep)
                    actual_parm_tp = boolean_expression();
                else if (formal_parm_tp->form == STRING_FORM)
                    actual_parm_tp = string_expression();
                else
                    actual_parm_tp = expression();

                if ((formal_parm_idp != NULL) &&
                    !assign_type_compatible(formal_parm_tp, actual_parm_tp))
                    compile_error(M_INCOMPATIBLE, M_TYPES, M_0);
            }
            else
            {
                // it is a formal VAR parameter and must be an identifier
                if (Token.code == ID_TOKEN)
                {
	            idp = search_symbol_tables(Token.lexeme);
	            if (idp == NULL)
		        compile_error(M_UNDEFINED, M_IDENTIFIER, M_0);
                    else
                    {
                        idp->initialized = true;
                        actual_parm_tp = idp->typep;

                        if (formal_parm_tp != actual_parm_tp)
                            compile_error(M_INCOMPATIBLE, M_TYPES, M_0);
                        else
                            emit_push_address(idp);
                    }
                }
                else
	        {
                    // invalid, parse for error recovery
                    actual_parm_tp = expression();  // and get next token

                    compile_error(M_INVALID, M_VARIABLE, M_PARAMETER, M_0);
                }
                get_token();                        // after <id>
            }

            if (actual_parm_count > formal_parm_count)
                compile_error(M_WRONG, M_NUMBER, M_OF, M_PARAMETERS, M_0);
            else
	        formal_parm_idp = formal_parm_idp->next;
        }

        if_code_get_token_else_error(R_PAREN);
    }

    if (formal_parm_count != actual_parm_count)
        compile_error(M_WRONG, M_NUMBER, M_OF, M_PARAMETERS, M_0);
}

/*
 *   "parse_block" parses a block of declarations and statements
 *
 *   returns:       nothing
 */
void parse_block(SYMTAB_NODE_PTR idp,               // of routine
                 TOKEN_CODE decl_list[],            // 1st list of tokens
                 TOKEN_CODE stmt_list[],            // 2nd list of tokens
                 TOKEN_CODE end_list[] )            // 3rd list of tokens
{
    do
    {
        if (token_in(decl_list))
            declaration();
        else if (token_in(stmt_list))
            statement(idp);
        else if (token_in(Decl_start_list)||token_in(Stmt_start_list))
        {
            compile_error(M_CONTEXT, M_ERROR, M_0);
            synchronize(decl_list, stmt_list, end_list);
        }

        if (!token_in(decl_list) &&
            !token_in(stmt_list) &&
            !token_in(end_list ))
        {
            compile_error(M_SYNTAX, M_ERROR, M_0);
            synchronize(decl_list, stmt_list, end_list  );
        }
    }
    while (token_in(decl_list)||token_in(stmt_list));
}

| home | contents | previous | next page | send comment | send link | add bookmark |

Copyright © 2004, Stephen R. Schmitt