#toy.g
#externs.g

/*
 * parseUtil.d - some routines useful for parsing.
 */

/*
 * checkUndef - check a variable to make sure it is defined.
 */

proc checkUndef(*SymbolEntry_t se)void:

    if se*.se_kind = sk_empty then
	se*.se_kind := sk_undefined;
	se*.se_type := rt_error;
	errorHereThree("'", se*.se_name, "' not defined");
    elif se*.se_kind = sk_undefined then
	errorHereThree("'", se*.se_name, "' not defined (subsequent use)");
    fi;
corp;

/*
 * checkAssign - make sure that the given symbol is an assignable variable.
 */

proc checkAssign(register *SymbolEntry_t se)void:

    if se*.se_kind ~= sk_globalVariable and se*.se_kind ~= sk_parameter and
	se*.se_kind ~= sk_localVariable
    then
	if se*.se_kind ~= sk_undefined then
	    errorHereThree("cannot assign to '", se*.se_name, "'");
	fi;
	se*.se_kind := sk_globalVariable;
	se*.se_value := 0;
    fi;
corp;

/*
 * isStatement - return 'true' if the current token can appear after a
 *	semicolon - i.e. it can start a new statement or it is the
 *	closing reserved word of a compound statement.
 */

proc isStatement()bool:
    register TokenKind_t tk;

    tk := getSimpleToken();
    tk = tk_id or tk = tk_number or tk = tk_if or tk = tk_elif or
	tk = tk_else or tk = tk_fi or tk = tk_while or tk = tk_od or
	tk = tk_readln or tk = tk_write or tk = tk_corp or
	tk = tk_semicolon or tk = tk_do
corp;

/*
 * findStatement - find something that can start a statement.
 */

proc findStatement()void:

    while
	skipToken();
	getSimpleToken() ~= tk_eof and not isStatement()
    do
    od;
corp;

/*
 * findClose - skip tokens upto a statement, a comma or a right paren.
 */

proc findClose()void:
    register TokenKind_t tk;

    while
	skipToken();
	tk := getSimpleToken();
	tk ~= tk_comma and tk ~= tk_rightParen and tk ~= tk_eof and
	    not isStatement()
    do
    od;
    if tk = tk_comma then
	nextToken();
    fi;
corp;
