| home
| contents
| previous
| next page
| send comment
| send link
| add bookmark |
PRS_STMT.CPP
statements
/*-------------------------------------------------------------------*
Parsing routines for T statements.
File: prs_stmt.cpp
Module: parser
by: Stephen R. Schmitt
*-------------------------------------------------------------------*/
#include "tpl_data.h"
#include <assert.h>
#include <stdlib.h>
/*
* External variables
*/
/* in scn_main.cpp */
extern token_struct Token;
extern TOKEN_CODE Stmt_start_list[];
extern TOKEN_CODE Decl_start_list[];
extern TOKEN_CODE Stmt_end_list[];
extern TOKEN_CODE Data_decl_list[];
extern TOKEN_CODE Loop_end_list[];
extern TOKEN_CODE For_end_list[];
extern TOKEN_CODE If_end1_list[];
extern TOKEN_CODE If_end2_list[];
extern TOKEN_CODE Case_label_list[];
extern TOKEN_CODE Case_end_list[];
extern TOKEN_CODE Put_item_list[];
extern TOKEN_CODE Number_type_list[];
extern TOKEN_CODE String_type_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 exc_util.cpp */
extern bool Routine_flag;
/* in prs_decl.cpp */
extern SYMTAB_NODE_PTR Last_rtne_idp;
/* in prs_rutn.cpp */
extern bool Result_flag;
/*
* Global declarations
*/
int Id_count = 0;
int Level = 0;
TOKEN_CODE Construct_Stack[NESTING_LEVELS];
int Continue_label[NESTING_LEVELS];
int Exit_label[NESTING_LEVELS];
/*-------------------------------------------------------------------*
Code Section
*-------------------------------------------------------------------*/
/*
* "statement" calls the appropriate parsing procedure based on
* the statement's first token.
*
* returns: nothing
*/
void statement(SYMTAB_NODE_PTR rtn_idp) // procedure or function
{
SYMTAB_NODE_PTR idp;
emit_statement_marker(Token.file, Token.line);
switch (Token.code)
{
case ID_TOKEN:
idp = search_symbol_tables(Token.lexeme);
if (idp == NULL)
{
compile_error(M_UNDEFINED, M_IDENTIFIER, M_0);
get_token();
synchronize(Stmt_start_list, Data_decl_list, Stmt_end_list);
}
else if (idp->definition == PROC_DEFN)
{
get_token(); // after <id>
declared_routine_call(idp);
}
else if ((idp->definition == VAR_DEFN) ||
(idp->definition == VALPARM_DEFN) ||
(idp->definition == VARPARM_DEFN))
assignment_statement(idp);
else if (idp->definition == LABEL_DEFN)
label_statement(idp);
else
{
compile_error(M_INVALID, M_IDENTIFIER, M_USAGE, M_0);
get_token();
synchronize(Stmt_start_list, Data_decl_list, Stmt_end_list);
}
break;
case PUTCH:
case PUTSTR:
case PUTLINE:
case PUTPIXEL:
case CURSOR:
case LOCATE:
case RANDOMIZE:
case RANDSEED:
case SCROLL:
case SETVIDEO:
case WATCH:
standard_routine_call();
break;
case LOOP:
loop_statement(rtn_idp);
break;
case FOR:
for_statement(rtn_idp);
break;
case IF:
if_statement(rtn_idp);
break;
case CASE:
case_statement(rtn_idp);
break;
case ASSERT:
assert_statement();
break;
case CONTINUE:
continue_statement();
break;
case EXIT:
exit_statement();
break;
case GOTO:
goto_statement();
break;
case GET:
get_statement();
break;
case PUT:
put_statement();
break;
case RETURN:
return_statement(rtn_idp);
break;
default:
assert(0);
break;
}
}
/*
* "assignment_statement" parses:
*
* <variable> := <expn>
*
* returns: nothing
*/
void assignment_statement(SYMTAB_NODE_PTR var_idp) // target id
{
TYPE_STRUCT_PTR var_tp, expr_tp;
var_tp = target_variable(var_idp); // and get next token
if (Token.code == ASSIGN)
get_token(); // after ":="
else // don't process <expn>
{
compile_error(M_MISSING, M_ASSIGN, M_0);
synchronize(Stmt_start_list, Data_decl_list, Stmt_end_list);
return;
}
if (var_tp == Boolean_typep)
expr_tp = boolean_expression(); // and get next token
else if (var_tp->form == STRING_FORM)
expr_tp = string_expression(); // and get next token
else
expr_tp = expression(); // and get next token
if (assign_type_compatible(var_tp, expr_tp))
{
if (var_idp->definition == VARPARM_DEFN)
emit_var_item(POP, var_idp, var_tp);
else
{
emit_mem_item(POP, var_idp, var_tp);
var_idp->initialized = true;
}
}
else
compile_error(M_INCOMPATIBLE, M_ASSIGNMENT, M_0);
}
/*
* "target_variable" processes a variable to be assigned a value
*
* returns: a pointer to the type structure of the variable
*/
TYPE_STRUCT_PTR target_variable(SYMTAB_NODE_PTR idp)
{
TYPE_STRUCT_PTR tp = idp->typep;
get_token(); // after <id>
// subscripts and/or field designators?
if ((Token.code == L_PAREN)||(Token.code == PERIOD))
emit_push_imm_index(0);
if ((Token.code == L_PAREN)&&(tp->form == STRING_FORM))
tp = target_string_char(tp);
else while ((Token.code == L_PAREN)||(Token.code == PERIOD))
{
if ((Token.code == L_PAREN)&&(tp->form == ARRAY_FORM))
tp = target_array_element(tp);
else if ((Token.code == PERIOD)&&
((tp->form == RECORD_FORM)||(tp->form == UNION_FORM)))
tp = target_structure_field(tp);
else
{
compile_error(M_INVALID, M_IDENTIFIER, M_USAGE, M_0);
while ((Token.code != R_PAREN ) &&
(!token_in(Decl_start_list)) &&
(!token_in(Stmt_start_list)))
get_token(); // until synchronized
tp = Real_typep; // avoid run time error
}
}
return tp;
}
/*
* "target_string_char" processes a subscript following
* a string identifier. The next "Token" is obtained.
*
* returns: a pointer to the type structure of the string element
*/
TYPE_STRUCT_PTR target_string_char(TYPE_STRUCT_PTR tp)
{
get_token(); // after "("
get_integer_expression();
emit_op_reg_imm( MOV_ax_imm, tp->array.max_index );
emit_op_reg_imm( MOV_bx_imm, tp->array.val_index );
emit_operator( ADD_xi_offset, NO_CODE, 0, 0);
if_code_get_token_else_error(R_PAREN);
return tp->array.elmt_typep;
}
/*
* "target_array_element" processes a list of subscripts following
* an array identifier. The next "Token" is obtained.
*
* returns: a pointer to the type structure of the array element
*/
TYPE_STRUCT_PTR target_array_element(TYPE_STRUCT_PTR tp)
{
TYPE_STRUCT_PTR elmt_tp = tp->array.elmt_typep;
do // process a subscript list
{
if (tp->form == ARRAY_FORM) // if an indexed array
{
get_token(); // after "(" or ","
get_integer_expression();
emit_op_reg_imm( MOV_ax_imm, tp->array.max_index );
emit_op_reg_imm( MOV_bx_imm, tp->array.val_index );
emit_operator( ADD_xi_offset, NO_CODE, 0, 0);
}
else
{
compile_error(M_TOO, M_MANY, M_SUBSCRIPTS, M_0);
while ((Token.code != R_PAREN) &&
!token_in(Data_decl_list) &&
!token_in(Stmt_start_list))
get_token(); // until synchronized
}
// if the next subscript is valid,
// tp->form will be set to ARRAY_FORM
tp = tp->array.next_indexp; // for next dimension
}
while (Token.code == COMMA);
if_code_get_token_else_error(R_PAREN);
return elmt_tp;
}
/*
* "target_structure_field" processes a field designation following
* a structure identifier
*
* returns: a pointer to the type structure of the right id
*/
TYPE_STRUCT_PTR target_structure_field(TYPE_STRUCT_PTR tp)
{
SYMTAB_NODE_PTR field_idp;
TYPE_STRUCT_PTR field_tp;
get_token(); // after "."
if (((tp->form == RECORD_FORM)||(tp->form == UNION_FORM ))&&
(Token.code == ID_TOKEN))
{
if (tp->form == RECORD_FORM)
{
field_idp = lookup(Token.lexeme, tp->record_struct.field_symtab);
}
else
{
field_idp = lookup(Token.lexeme, tp->union_struct.field_symtab);
}
if (field_idp == NULL)
{
compile_error(M_INVALID, M_FIELD, M_0);
field_tp = Null_typep;
}
else
field_tp = field_idp->typep;
emit_operator(ADD_xi_imm, NO_CODE, 0, field_idp->data_offset);
get_token(); // after <id>
}
else
{
compile_error(M_INVALID, M_FIELD, M_0);
field_tp = Null_typep;
get_token(); // after <id>
}
return field_tp;
}
/*
* "loop_statement" parses:
*
* loop
* <declarationsAndStatements>
* end loop
*
* returns: nothing
*/
void loop_statement(SYMTAB_NODE_PTR rtn_idp) // subroutine id
{
get_token(); // after "loop"
int begin = next_code_label();
int end = next_code_label();
emit_code_label(begin); // jump here to continue
incr_level(LOOP, begin, end);
incr_scope();
parse_block(rtn_idp, Data_decl_list, Stmt_start_list, Loop_end_list);
emit_operator(JMP, NO_CODE, 0, begin);
decr_level();
decr_scope();
if_code_get_token_else_error(END);
if (Token.code == LOOP)
{
emit_code_label(end); // jump here to exit
emit_statement_marker(Token.file, Token.line);
get_token(); // after "loop"
}
else
compile_error(M_MISSING, M_LOOP, M_0);
}
/*
* "for_statement" parses:
*
* for [decreasing] <id> := <expn> ... <expn> do
* <declarations and statements>
* end for
*
* returns: nothing
*/
void for_statement(SYMTAB_NODE_PTR rtn_idp) // subroutine id
{
int begin, // loop top
again, // continue
end; // exit
char buffer[8];
SYMTAB_NODE_PTR count_idp, end_idp;
TYPE_STRUCT_PTR count_tp, end_tp;
bool count_ok = false; // default
bool increasing = true; // default
get_token(); // after "for"
if (Token.code == DECREASING)
{
increasing = false;
get_token(); // after "decreasing"
}
// process count parameter
if (Token.code == ID_TOKEN)
{
count_idp = search_symbol_tables(Token.lexeme);
if (count_idp == NULL)
compile_error(M_UNDEFINED, M_IDENTIFIER, M_0);
else if ((count_idp->definition == VAR_DEFN )||
(count_idp->definition == VALPARM_DEFN)||
(count_idp->definition == VARPARM_DEFN))
{
count_idp->initialized = true;
count_tp = count_idp->typep;
if (count_tp != Integer_typep)
compile_error(M_INVALID, M_TYPE, M_0);
else
count_ok = true;
}
else
compile_error(M_INVALID, M_IDENTIFIER, M_USAGE, M_0);
get_token(); // after <id>
}
else
compile_error(M_MISSING, M_IDENTIFIER, M_0);
// create internal idp for end value
Id_count++;
itoa(Id_count, buffer, 10);
end_idp = insert(buffer, &Symbol_table[Scope]);
end_idp->definition = CONST_DEFN;
end_idp->typep = Integer_typep;
end_tp = end_idp->typep;
Last_rtne_idp->next = end_idp;
end_idp->prev = Last_rtne_idp;
Last_rtne_idp = end_idp;
if (Token.code == ASSIGN)
get_token(); // after ":="
else
{
compile_error(M_MISSING, M_ASSIGN, M_0);
get_token();
}
// process count limits
get_integer_expression(); // beginning value
if (count_ok)
{
if (count_idp->definition == VARPARM_DEFN)
emit_var_item(POP, count_idp, count_tp);
else
emit_mem_item(POP, count_idp, count_tp);
}
if_code_get_token_else_error(ELLIPSES);
get_integer_expression(); // ending value
emit_mem_item(POP, end_idp, end_tp);
if_code_get_token_else_error(DO);
begin = next_code_label();
again = next_code_label();
end = next_code_label();
emit_code_label(begin); // jump here to loop
// emit code to check for completion of loop
if (count_ok)
{
if (count_idp->definition == VARPARM_DEFN)
emit_var_item(PUSH, count_idp, count_tp);
else
emit_mem_item(PUSH, count_idp, count_tp);
}
emit_mem_item(PUSH, end_idp, end_tp);
if (increasing)
emit_operator(TEST_NUMBER, TEST_GT, 0, 0);
else
emit_operator(TEST_NUMBER, TEST_LT, 0, 0);
emit_operator(JNZ, NO_CODE, 0, end);
// emit code for block of statements
incr_level(FOR, again, end);
incr_scope();
parse_block(rtn_idp, Data_decl_list, Stmt_start_list, For_end_list);
emit_code_label(again); // jump here to continue
// increment or decrement counter
if (count_ok)
{
if (count_idp->definition == VARPARM_DEFN)
emit_var_item(PUSH, count_idp, count_tp);
else
emit_mem_item(PUSH, count_idp, count_tp);
}
if (increasing)
emit_push_imm_integer(+1L); // increment
else
emit_push_imm_integer(-1L); // decrement
emit_operator(IADD, NO_CODE, 0, 0);
if (count_ok)
{
if (count_idp->definition == VARPARM_DEFN)
emit_var_item(POP, count_idp, count_tp);
else
emit_mem_item(POP, count_idp, count_tp);
}
emit_operator(JMP, NO_CODE, 0, begin);
decr_level();
decr_scope();
if_code_get_token_else_error(END);
if (Token.code == FOR)
{
emit_code_label(end); // jump here to exit
emit_statement_marker(Token.file, Token.line);
get_token(); // after "for"
}
else
compile_error(M_MISSING, M_FOR, M_0);
}
/*
* "if_statement" parses:
*
* if <booleanExpn> then
* <declarationsAndStatements>
* { elsif <booleanExpn> then
* <declarationsAndStatements> }
* [else
* <declarationsAndStatements>]
* end if
*
* returns: nothing
*/
void if_statement(SYMTAB_NODE_PTR rtn_idp) // subroutine id
{
get_token(); // after "if"
int if_exit = next_code_label();
int if_false = next_code_label();
boolean_expression(); // and get next token
emit_operator(JZ, NO_CODE, 0, if_false);
if_code_get_token_else_error(THEN);
incr_level(IF, 0, 0);
incr_scope();
parse_block(rtn_idp, Data_decl_list, Stmt_start_list, If_end1_list);
decr_level();
decr_scope();
emit_operator(JMP, NO_CODE, 0, if_exit);
emit_code_label(if_false); // jump here if false
while (Token.code == ELSIF)
{
emit_statement_marker(Token.file, Token.line);
get_token(); // after "elsif"
if_false = next_code_label();
boolean_expression(); // and get next token
emit_operator(JZ, NO_CODE, 0, if_false);
if_code_get_token_else_error(THEN);
incr_level(ELSIF, 0, 0);
incr_scope();
parse_block(rtn_idp, Data_decl_list, Stmt_start_list, If_end1_list);
decr_level();
decr_scope();
emit_operator(JMP, NO_CODE, 0, if_exit);
emit_code_label(if_false); // jump here if false
}
if (Token.code == ELSE)
{
emit_statement_marker(Token.file, Token.line);
get_token(); // after "else"
incr_level(ELSE, 0, 0);
incr_scope();
parse_block(rtn_idp, Data_decl_list, Stmt_start_list, If_end2_list);
decr_level();
decr_scope();
}
if_code_get_token_else_error(END);
if (Token.code == IF)
{
emit_code_label(if_exit); // jump here when done
emit_statement_marker(Token.file, Token.line);
get_token(); // after "if"
}
else
compile_error(M_MISSING, M_IF, M_0);
}
/*
* "case_statement" parses:
*
* case <expn> of
* value <const> {, <const> } :
* <declarations and statements>
* { value <const> {, <const> } :
* <declarations and statements> }
* [value :
* <declarations and statements>]
* end case
*
* returns: nothing
*/
void case_statement(SYMTAB_NODE_PTR rtn_idp) // subroutine id
{
SYMTAB_NODE_PTR expr_idp, idp;
TYPE_STRUCT_PTR expr_tp, label_tp;
bool another_branch, another_label, expr_ok;
int case_exit, case_true, case_false;
char buffer[8];
get_token(); // after "case"
if (Token.code == ID_TOKEN) // get expression's type
{
idp = search_symbol_tables(Token.lexeme);
if (idp == NULL)
{
compile_error(M_UNDEFINED, M_IDENTIFIER, M_0);
expr_tp = Integer_typep; // default
get_token(); // after <id>
}
else
{
if (idp->typep->form == STRING_FORM)
expr_tp = string_expression(); // and get next token
else
expr_tp = expression(); // and get next token
}
}
else if (Token.code == STR_TOKEN)
expr_tp = string_expression(); // and get next token
else
expr_tp = expression(); // and get next token
// create internal idp for case expression's value
Id_count++;
itoa(Id_count, buffer, 10);
expr_idp = insert(buffer, &Symbol_table[Scope]);
expr_idp->definition = CONST_DEFN;
expr_idp->typep = expr_tp;
Last_rtne_idp->next = expr_idp;
expr_idp->prev = Last_rtne_idp;
Last_rtne_idp = expr_idp;
if ((expr_tp == Integer_typep)||
(expr_tp == Char_typep )||
(expr_tp->form == STRING_FORM )||
(expr_tp->form == ENUM_FORM ))
{
expr_ok = true;
emit_mem_item(POP, expr_idp, expr_tp);
}
else
{
expr_ok = false;
compile_error(M_INVALID, M_TYPE, M_0);
}
if_code_get_token_else_error(OF);
another_branch = true;
case_exit = next_code_label();
while ((Token.code == VALUE) && another_branch)
{
get_token(); // after label
case_true = next_code_label();
case_false = next_code_label();
if (token_in(Case_label_list)) // valid label
{
// get label value(s) for a branch
another_label = true;
while (another_label)
{
label_tp = case_label(); // and get next token
if (expr_tp != label_tp)
compile_error(M_INCOMPATIBLE, M_TYPES, M_0);
else if (expr_ok)
emit_mem_item(PUSH, expr_idp, expr_tp);
if (expr_tp == Integer_typep)
emit_operator(TEST_NUMBER, TEST_EQ, 0, 0);
else if (expr_tp == Char_typep)
emit_operator(TEST_CHAR, TEST_EQ, 0, 0);
else if (expr_tp->form == STRING_FORM)
emit_operator(TEST_STRING, TEST_EQ, 0, 0);
else if (expr_tp->form == ENUM_FORM)
emit_operator(TEST_INDEX, TEST_EQ, 0, 0);
else
assert(0);
emit_operator(JNZ, NO_CODE, 0, case_true);
if (Token.code == COMMA)
{
get_token(); // after ","
if (token_in(Case_label_list))
another_label = true;
else
{
compile_error(M_MISSING, M_CASE, M_VALUE, M_0);
another_label = false;
}
}
else
another_label = false;
}
another_branch = true;
}
else
{
another_branch = false;
emit_operator(JMP, NO_CODE, 0, case_true);
}
if_code_get_token_else_error(COLON);
if (another_branch)
emit_operator(JMP, NO_CODE, 0, case_false);
emit_code_label(case_true);
incr_level(CASE, 0, 0);
incr_scope();
parse_block(rtn_idp, Data_decl_list, Stmt_start_list, Case_end_list);
decr_level();
decr_scope();
emit_operator(JMP, NO_CODE, 0, case_exit);
if (another_branch)
emit_code_label(case_false);
}
if_code_get_token_else_error(END);
if (Token.code == CASE)
{
emit_code_label(case_exit); // jump here when done
emit_statement_marker(Token.file, Token.line);
get_token(); // after "case"
}
else
compile_error(M_MISSING, M_CASE, M_0);
}
/*
* "case_label" processes a case label value
*
* returns: a pointer to the type structure of the case label
*/
TYPE_STRUCT_PTR case_label()
{
bool saw_sign = false; // default
TYPE_STRUCT_PTR label_tp = Integer_typep; // default
SYMTAB_NODE_PTR label_idp;
TOKEN_CODE code;
if ((Token.code == PLUS)||(Token.code == MINUS))
{
code = Token.code;
saw_sign = true;
get_token(); // after sign
}
if (Token.code == INT_TOKEN)
{
label_tp = Integer_typep;
emit_push_imm_integer(Token.integer);
if (saw_sign && (code == MINUS))
emit_operator(RNEG, NO_CODE, 0, 0);
get_token(); // after <int>
}
else if (Token.code == STR_TOKEN)
{
label_tp = String_typep;
emit_push_imm_string(Token.lexeme);
if (saw_sign)
compile_error(M_INVALID, M_CASE, M_VALUE, M_0);
get_token(); // after <str>
}
else if (Token.code == CHAR_TOKEN)
{
label_tp = Char_typep;
emit_push_imm_char(Token.lexeme[0]);
if (saw_sign)
compile_error(M_INVALID, M_CASE, M_VALUE, M_0);
get_token(); // after <str>
}
else if (Token.code == ID_TOKEN)
{
label_idp = search_symbol_tables(Token.lexeme);
if (label_idp == NULL)
{
compile_error(M_UNDEFINED, M_IDENTIFIER, M_0);
get_token(); // after <id>
}
else if ((label_idp->typep == Integer_typep)&&
(label_idp->definition == CONST_DEFN ))
{
label_tp = label_idp->typep;
emit_mem_item(PUSH, label_idp, label_tp);
if (saw_sign && (code == MINUS))
emit_operator(INEG, NO_CODE, 0, 0);
get_token(); // after <id>
}
else if ((label_idp->typep == Char_typep)&&
(label_idp->definition == CONST_DEFN))
{
if (saw_sign)
compile_error(M_INVALID, M_CASE, M_VALUE, M_0);
label_tp = label_idp->typep;
emit_mem_item(PUSH, label_idp, label_tp);
get_token(); // after <id>
}
else if ((label_idp->typep->form == STRING_FORM)&&
(label_idp->definition == CONST_DEFN ))
{
if (saw_sign)
compile_error(M_INVALID, M_CASE, M_VALUE, M_0);
label_tp = label_idp->typep;
emit_mem_item(PUSH, label_idp, label_tp);
get_token(); // after <id>
}
else if ((label_idp->typep->form == ENUM_FORM)&&
(label_idp->definition == TYPE_DEFN))
{
if (saw_sign)
compile_error(M_INVALID, M_CASE, M_VALUE, M_0);
get_token(); // after <id>
// push index value of enumeration field
if (Token.code == PERIOD)
label_tp = dot_field(label_idp->typep);
else
compile_error(M_INVALID, M_CASE, M_VALUE, M_0);
}
else
{
compile_error(M_INVALID, M_CASE, M_VALUE, M_0);
while ((Token.code != COLON )&&
(Token.code != COMMA )&&
(Token.code != END )&&
(Token.code != END_OF_FILE))
get_token();
}
}
else
{
compile_error(M_INVALID, M_CASE, M_VALUE, M_0);
while ((Token.code != COLON )&&
(Token.code != COMMA )&&
(Token.code != END )&&
(Token.code != END_OF_FILE))
get_token();
}
return label_tp;
}
/*
* "assert_statement" parses:
*
* assert <boolean expn>
*
* whichs aborts the program if the expression is false
*
* returns: nothing
*/
void assert_statement()
{
int line = Token.line;
get_token(); // after "assert"
boolean_expression(); // and get next token
emit_operator(EXITZ, NO_CODE, 0, line);
}
/*
* "continue_statement" parses:
*
* continue [when <boolean expn>]
*
* returns: nothing
*/
void continue_statement()
{
int i;
if (!in_for_or_loop_construct())
compile_error(M_CONTEXT, M_ERROR, M_0);
else
{
for (i = Level; i >= 0; i--)
{
if ((Construct_Stack[i] == FOR)||(Construct_Stack[i] == LOOP))
break;
}
}
get_token(); // after "continue"
if (Token.code == WHEN)
{
get_token(); // after "when"
boolean_expression(); // and get next token
emit_operator(JNZ, NO_CODE, 0, Continue_label[i]);
}
else
emit_operator(JMP, NO_CODE, 0, Continue_label[i]);
}
/*
* "exit_statement" parses:
*
* exit [when <boolean expn>]
*
* returns: nothing
*/
void exit_statement()
{
int i;
if (!in_for_or_loop_construct())
compile_error(M_CONTEXT, M_ERROR, M_0);
else
{
for (i = Level; i >= 0; i--)
{
if ((Construct_Stack[i] == FOR)||(Construct_Stack[i] == LOOP))
break;
}
}
get_token(); // after "exit"
if (Token.code == WHEN)
{
get_token(); // after "when"
boolean_expression(); // and get next token
emit_operator(JNZ, NO_CODE, 0, Exit_label[i]);
}
else
emit_operator(JMP, NO_CODE, 0, Exit_label[i]);
}
/*
* "goto_statement" parses:
*
* goto <label>
*
* returns: nothing
*/
void goto_statement()
{
SYMTAB_NODE_PTR idp;
get_token(); // after "goto"
if (Token.code == ID_TOKEN)
{
idp = search_symbol_tables(Token.lexeme);
if (idp == NULL)
compile_error(M_UNDEFINED, M_IDENTIFIER, M_0);
else if (idp->definition != LABEL_DEFN)
compile_error(M_INVALID, M_IDENTIFIER, M_USAGE, M_0);
else
emit_operator(JMP, NO_CODE, 0, idp->integer);
get_token(); // after <label>
}
else
compile_error(M_MISSING, M_IDENTIFIER, M_0);
}
/*
* "label_statement" parses:
*
* <label> :
*
* returns: nothing
*/
void label_statement(SYMTAB_NODE_PTR idp)
{
if (idp->initialized == true)
compile_error(M_INVALID, M_LABEL, M_USAGE, M_0);
else
{
idp->initialized = true;
emit_code_label(idp->integer); // goto here
}
get_token(); // after <label>
if_code_get_token_else_error(COLON);
}
/*
* "get_statement" parses:
*
* get [:<streamNumber>,] <getItem> {, <getItem> }
*
* in which <getItem> is one of:
*
* a. <varRef> - either string, integer, or real token
* b. <varRef>:* - input a line as a string
* c. <varRef>:<width> - input <width> characters as a string
*
* returns: nothing
*/
void get_statement()
{
bool flush_stdin; // flush stream if true
bool item_ok;
TYPE_STRUCT_PTR item_tp;
SYMTAB_NODE_PTR item_idp;
get_token(); // after "get"
if (Token.code == COLON) // get <streamNumber>
{
get_token(); // after ":"
get_integer_expression();
emit_operator(SET_file_ptr, NO_CODE, 0, 0);
flush_stdin = false;
if_code_get_token_else_error(COMMA);
}
else
{
emit_operator(SET_stdin, NO_CODE, 0, 0);
flush_stdin = true;
}
while (Token.code == ID_TOKEN)
{
item_idp = search_symbol_tables(Token.lexeme);
if (item_idp == NULL)
{
compile_error(M_UNDEFINED, M_IDENTIFIER, M_0);
item_ok = false;
get_token(); // next in file
}
else
{
item_ok = true;
item_tp = target_variable(item_idp); // and get token
if ((item_tp != Integer_typep) &&
(item_tp != Real_typep) &&
(item_tp->form != STRING_FORM))
compile_error(M_INVALID, M_TYPE, M_0);
if ((item_idp->definition != VAR_DEFN) &&
(item_idp->definition != VARPARM_DEFN) &&
(item_idp->definition != VALPARM_DEFN))
compile_error(M_NOT, M_VARIABLE, M_IDENTIFIER, M_0);
}
if (Token.code == COLON) // get <width>
{
if (item_tp->form != STRING_FORM)
compile_error(M_INVALID, M_TYPE, M_0);
get_token(); // after ":"
if (Token.code == STAR)
{
emit_push_imm_real(MAX_STRING_LENGTH);
emit_operator(GET_str, NO_CODE, 0, 0);
get_token(); // after "*"
}
else
{
get_integer_expression();
emit_operator(GET_str, NO_CODE, 0, 0);
}
}
else
emit_operator(GET_item, NO_CODE, 0, 0);
if (item_ok)
{
if (item_tp == Integer_typep)
emit_operator(CALL_stnd, SF_STRINT, 0, 0);
else if (item_tp == Real_typep)
emit_operator(CALL_stnd, SF_STRREAL, 0, 0);
if (item_idp->definition == VARPARM_DEFN)
emit_var_item(POP, item_idp, item_tp);
else
emit_mem_item(POP, item_idp, item_tp);
item_idp->initialized = true;
}
if (Token.code == COMMA)
{
get_token(); // after ","
if (Token.code != ID_TOKEN)
{
compile_error(M_MISSING, M_ITEM, M_0);
synchronize(Stmt_start_list, Data_decl_list, Stmt_end_list);
break;
}
}
else
break;
}
if (flush_stdin)
emit_operator(FLUSH_stdin, NO_CODE, 0, 0);
}
/*
* "put_statement" parses:
*
* put [:<streamNumber>,] <putItem> {, <putItem>}[..]
*
* in which a <putItem> is:
*
* <expn>[:<width>[:<fractWidth>[:<expWidth>]]]
*
* returns: nothing
*/
void put_statement()
{
TYPE_STRUCT_PTR expn_tp;
SYMTAB_NODE_PTR idp;
get_token(); // after "put"
if (Token.code == COLON) // get <streamNumber>
{
get_token(); // after ":"
get_integer_expression();
emit_operator(SET_file_ptr, NO_CODE, 0, 0);
if_code_get_token_else_error(COMMA);
}
else
emit_operator(SET_stdout, NO_CODE, 0, 0);
while (token_in(Put_item_list) ||
token_in(Number_type_list)||
token_in(String_type_list))
{
if (Token.code == ID_TOKEN) // get the output type
{
idp = search_symbol_tables(Token.lexeme);
if (idp == NULL)
{
compile_error(M_UNDEFINED, M_IDENTIFIER, M_0);
get_token(); // after <id>
}
else
{
if (idp->typep->form == STRING_FORM)
expn_tp = string_expression();
else
expn_tp = expression();
}
}
else if (token_in(String_type_list))
expn_tp = string_expression(); // and get next token
else
expn_tp = expression(); // and get next token
// check for valid output type
if ((expn_tp != Integer_typep)&&
(expn_tp != Real_typep )&&
(expn_tp != Char_typep )&&
(expn_tp->form != STRING_FORM ))
{
compile_error(M_INVALID, M_TYPE, M_0);
expn_tp = Null_typep;
get_token(); // after <id>
}
if (Token.code == COLON) // get <width>
{
get_token(); // after ":"
get_integer_expression();
if (Token.code == COLON) // get <fractWidth>
{
if (expn_tp != Real_typep)
compile_error(M_INCOMPATIBLE, M_TYPES, M_0);
get_token(); // after ":"
get_integer_expression();
if (Token.code == COLON) // get <expWidth>
{
get_token(); // after ":"
get_integer_expression();
emit_operator(CALL_stnd, SF_EREALSTR, 0, 0);
}
else
emit_operator(CALL_stnd, SF_FREALSTR, 0, 0);
}
else
{
if (expn_tp == Null_typep) // source code error
emit_operator(NO_CODE, NO_CODE, 0, 0);
else if (expn_tp == Real_typep)
emit_operator(CALL_stnd, SF_REALSTR, 0, 0);
else if (expn_tp == Integer_typep)
emit_operator(CALL_stnd, SF_INTSTR, 0, 0);
else if (expn_tp == Char_typep)
emit_operator(FORMAT_CHR, NO_CODE, 0, 0);
else if (expn_tp->form == STRING_FORM)
emit_operator(FORMAT_STR, NO_CODE, 0, 0);
else
assert(0);
}
}
else
{
emit_push_imm_real(1.0); // width
if (expn_tp == Null_typep) // source code error
emit_operator(NO_CODE, NO_CODE, 0, 0);
else if (expn_tp == Real_typep)
emit_operator(CALL_stnd, SF_REALSTR, 0, 0);
else if (expn_tp == Integer_typep)
emit_operator(CALL_stnd, SF_INTSTR, 0, 0);
else if (expn_tp == Char_typep)
emit_operator(FORMAT_CHR, NO_CODE, 0, 0);
else if (expn_tp->form == STRING_FORM)
emit_operator(FORMAT_STR, NO_CODE, 0, 0);
else
assert(0);
}
emit_operator(PUT_str, NO_CODE, 0, 0);
if (Token.code == COMMA)
{
get_token(); // after ","
if (!token_in(Put_item_list ) &&
!token_in(Number_type_list) &&
!token_in(String_type_list))
compile_error(M_MISSING, M_ITEM, M_0);
}
else
break;
}
if (Token.code == ELLIPSES)
get_token(); // after "..."
else
{
emit_push_imm_string("\n"); // add newline
emit_operator(PUT_str, NO_CODE, 0, 0);
}
}
/*
* "return_statement" parses:
*
* return [<expn>]
*
* A function must return a value; the expression type must match
* the function type.
*
* returns: nothing
*/
void return_statement(SYMTAB_NODE_PTR rtne_idp) // of function
{
TYPE_STRUCT_PTR rtne_tp, expr_tp;
get_token(); // after "return"
if (rtne_idp->definition == FUNC_DEFN)
{
Result_flag = true;
rtne_tp = rtne_idp->typep;
if (rtne_tp == Boolean_typep)
expr_tp = boolean_expression(); // and get next token
else if (rtne_tp->form == STRING_FORM)
expr_tp = string_expression(); // and get next token
else
expr_tp = expression(); // and get next token
if (!assign_type_compatible(rtne_tp, expr_tp))
compile_error(M_INCOMPATIBLE, M_ASSIGNMENT, M_0);
emit_return_value(rtne_idp);
}
emit_operator(JMP, NO_CODE, 0, 0); // zero is return label
}
/*
* "incr_level" enters a deeper logical nesting level.
*
* returns: nothing
*/
void incr_level(TOKEN_CODE construct, int continue_label, int exit_label)
{
Level++; // increment level
if (Level >= NESTING_LEVELS)
compile_error(M_NESTING, M_TOO, M_DEEP, M_0);
Construct_Stack[Level] = construct;
Continue_label[Level] = continue_label;
Exit_label[Level] = exit_label;
}
/*
* "decr_level" exits the current logical nesting level.
*
* returns: nothing
*/
void decr_level()
{
Level--; // decrement level
}
/*
* "in_for_or_loop_construct" determines if the parser is within
* a loop or for logical construct. This is done to determine if
* the token EXIT is valid.
*
* returns: true or false
*/
bool in_for_or_loop_construct()
{
for (int i = Level; i >= 0; i--)
{
if ((Construct_Stack[i] == FOR)||(Construct_Stack[i] == LOOP))
return true;
}
return false;
}
| home
| contents
| previous
| next page
| send comment
| send link
| add bookmark |
Copyright © 2004, Stephen R. Schmitt