| 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