You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
990 lines
22 KiB
990 lines
22 KiB
//
|
|
// Copyright (c) Microsoft Corporation 1995
|
|
//
|
|
// typechk.c
|
|
//
|
|
// This file contains the typechecking functions.
|
|
//
|
|
// The typechecking rules are:
|
|
//
|
|
// waitfor Takes a string expression
|
|
// transmit Takes a string expression
|
|
// delay Takes an integer expression
|
|
// while Evaluates a boolean expression
|
|
// set ipaddr Takes a string expression
|
|
// getip Takes an integer expression
|
|
//
|
|
//
|
|
//
|
|
// History:
|
|
// 06-15-95 ScottH Created
|
|
//
|
|
|
|
|
|
#include "proj.h"
|
|
#include "rcids.h"
|
|
|
|
RES PRIVATE Stmt_Typecheck(PSTMT this, PSYMTAB pst, HSA hsaStxerr);
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Typechecks whether an identifier is a valid type.
|
|
|
|
Returns: RES_OK
|
|
RES_E_REQUIRELABEL
|
|
RES_E_UNDEFINED
|
|
|
|
Cond: --
|
|
*/
|
|
RES PRIVATE Ident_Typecheck(
|
|
LPCSTR pszIdent,
|
|
DATATYPE dt,
|
|
PDATATYPE pdt, // May be NULL
|
|
DWORD iLine,
|
|
PSYMTAB pst,
|
|
HSA hsaStxerr)
|
|
{
|
|
RES res = RES_OK;
|
|
PSTE pste;
|
|
|
|
if (RES_OK == Symtab_FindEntry(pst, pszIdent, STFF_DEFAULT, &pste, NULL))
|
|
{
|
|
if (pdt)
|
|
{
|
|
*pdt = STE_GetDataType(pste);
|
|
res = RES_OK;
|
|
}
|
|
else if (dt == STE_GetDataType(pste))
|
|
{
|
|
res = RES_OK;
|
|
}
|
|
else
|
|
{
|
|
switch (dt)
|
|
{
|
|
case DATA_LABEL:
|
|
res = RES_E_REQUIRELABEL;
|
|
break;
|
|
|
|
case DATA_STRING:
|
|
res = RES_E_REQUIRESTRING;
|
|
break;
|
|
|
|
case DATA_INT:
|
|
res = RES_E_REQUIREINT;
|
|
break;
|
|
|
|
case DATA_BOOL:
|
|
res = RES_E_REQUIREBOOL;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
break;
|
|
}
|
|
Stxerr_Add(hsaStxerr, pszIdent, iLine, res);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
res = Stxerr_Add(hsaStxerr, pszIdent, iLine, RES_E_UNDEFINED);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
//
|
|
// Exprs
|
|
//
|
|
|
|
RES PRIVATE Expr_Typecheck(PEXPR this, PSYMTAB pst, HSA hsaStxerr);
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Return a string given a binoptype.
|
|
|
|
Returns: Pointer to string
|
|
Cond: --
|
|
*/
|
|
LPCSTR PRIVATE SzFromBot(
|
|
BINOPTYPE bot)
|
|
{
|
|
#pragma data_seg(DATASEG_READONLY)
|
|
static const LPCSTR s_mpbotsz[] =
|
|
{ "'or' operand",
|
|
"'and' operand",
|
|
"'<=' operand",
|
|
"'<' operand",
|
|
"'>=' operand",
|
|
"'>' operand",
|
|
"'!=' operand",
|
|
"'==' operand",
|
|
"'+' operand",
|
|
"'-' operand",
|
|
"'*' operand",
|
|
"'/' operand",
|
|
};
|
|
#pragma data_seg()
|
|
|
|
if (ARRAY_ELEMENTS(s_mpbotsz) <= bot)
|
|
{
|
|
ASSERT(0);
|
|
return "";
|
|
}
|
|
|
|
return s_mpbotsz[bot];
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Return a string given a unoptype.
|
|
|
|
Returns: Pointer to string
|
|
Cond: --
|
|
*/
|
|
LPCSTR PRIVATE SzFromUot(
|
|
UNOPTYPE uot)
|
|
{
|
|
#pragma data_seg(DATASEG_READONLY)
|
|
static const LPCSTR s_mpuotsz[] =
|
|
{
|
|
"unary '-' operand",
|
|
"'!' operand",
|
|
"'getip' parameter",
|
|
};
|
|
#pragma data_seg()
|
|
|
|
if (ARRAY_ELEMENTS(s_mpuotsz) <= uot)
|
|
{
|
|
ASSERT(0);
|
|
return "";
|
|
}
|
|
|
|
return s_mpuotsz[uot];
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Typechecks a variable reference expression.
|
|
|
|
Returns: RES_OK
|
|
or some error result
|
|
|
|
Cond: --
|
|
*/
|
|
RES PRIVATE VarExpr_Typecheck(
|
|
PEXPR this,
|
|
PSYMTAB pst,
|
|
HSA hsaStxerr)
|
|
{
|
|
RES res;
|
|
LPSTR pszIdent;
|
|
PSTE pste;
|
|
|
|
ASSERT(this);
|
|
ASSERT(hsaStxerr);
|
|
|
|
pszIdent = VarExpr_GetIdent(this);
|
|
|
|
if (RES_OK == Symtab_FindEntry(pst, pszIdent, STFF_DEFAULT, &pste, NULL))
|
|
{
|
|
DATATYPE dt = STE_GetDataType(pste);
|
|
|
|
ASSERT(DATA_BOOL == dt || DATA_INT == dt || DATA_STRING == dt);
|
|
|
|
Expr_SetDataType(this, dt);
|
|
res = RES_OK;
|
|
}
|
|
else
|
|
{
|
|
res = Stxerr_Add(hsaStxerr, pszIdent, Ast_GetLine(this), RES_E_UNDEFINED);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Typechecks a binary operator expression.
|
|
|
|
Returns: RES_OK
|
|
or some error result
|
|
|
|
Cond: --
|
|
*/
|
|
RES PRIVATE BinOpExpr_Typecheck(
|
|
PEXPR this,
|
|
PSYMTAB pst,
|
|
HSA hsaStxerr)
|
|
{
|
|
RES res;
|
|
PEXPR pexpr1;
|
|
PEXPR pexpr2;
|
|
|
|
ASSERT(this);
|
|
ASSERT(hsaStxerr);
|
|
|
|
pexpr1 = BinOpExpr_GetExpr1(this);
|
|
res = Expr_Typecheck(pexpr1, pst, hsaStxerr);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
pexpr2 = BinOpExpr_GetExpr2(this);
|
|
res = Expr_Typecheck(pexpr2, pst, hsaStxerr);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
BINOPTYPE bot = BinOpExpr_GetType(this);
|
|
|
|
// Types must match
|
|
if (Expr_GetDataType(pexpr1) != Expr_GetDataType(pexpr2))
|
|
{
|
|
res = RES_E_TYPEMISMATCH;
|
|
}
|
|
else
|
|
{
|
|
// Just choose one of the datatypes, since they
|
|
// should be the same.
|
|
DATATYPE dt = Expr_GetDataType(pexpr1);
|
|
|
|
switch (bot)
|
|
{
|
|
case BOT_OR:
|
|
case BOT_AND:
|
|
Expr_SetDataType(this, DATA_BOOL);
|
|
|
|
if (DATA_BOOL != dt)
|
|
res = RES_E_REQUIREBOOL;
|
|
break;
|
|
|
|
case BOT_PLUS:
|
|
Expr_SetDataType(this, dt);
|
|
|
|
// String + string means concatenate.
|
|
if (DATA_INT != dt && DATA_STRING != dt)
|
|
res = RES_E_REQUIREINTSTRING;
|
|
break;
|
|
|
|
case BOT_NEQ:
|
|
case BOT_EQ:
|
|
Expr_SetDataType(this, DATA_BOOL);
|
|
|
|
if (DATA_INT != dt && DATA_STRING != dt &&
|
|
DATA_BOOL != dt)
|
|
res = RES_E_REQUIREINTSTRBOOL;
|
|
break;
|
|
|
|
case BOT_LEQ:
|
|
case BOT_LT:
|
|
case BOT_GEQ:
|
|
case BOT_GT:
|
|
Expr_SetDataType(this, DATA_BOOL);
|
|
|
|
if (DATA_INT != dt)
|
|
res = RES_E_REQUIREINT;
|
|
break;
|
|
|
|
case BOT_MINUS:
|
|
case BOT_MULT:
|
|
case BOT_DIV:
|
|
Expr_SetDataType(this, DATA_INT);
|
|
|
|
if (DATA_INT != dt)
|
|
res = RES_E_REQUIREINT;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
res = RES_E_INVALIDPARAM;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (RFAILED(res))
|
|
Stxerr_Add(hsaStxerr, SzFromBot(bot), Ast_GetLine(this), res);
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Typechecks a unary operator expression.
|
|
|
|
Returns: RES_OK
|
|
or some error result
|
|
|
|
Cond: --
|
|
*/
|
|
RES PRIVATE UnOpExpr_Typecheck(
|
|
PEXPR this,
|
|
PSYMTAB pst,
|
|
HSA hsaStxerr)
|
|
{
|
|
RES res;
|
|
PEXPR pexpr;
|
|
|
|
ASSERT(this);
|
|
ASSERT(hsaStxerr);
|
|
|
|
pexpr = UnOpExpr_GetExpr(this);
|
|
res = Expr_Typecheck(pexpr, pst, hsaStxerr);
|
|
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
UNOPTYPE uot = UnOpExpr_GetType(this);
|
|
DATATYPE dt = Expr_GetDataType(pexpr);
|
|
|
|
// Check the type of the expression
|
|
switch (uot)
|
|
{
|
|
case UOT_NEG:
|
|
Expr_SetDataType(this, DATA_INT);
|
|
|
|
if (DATA_INT != dt)
|
|
res = RES_E_REQUIREINT;
|
|
break;
|
|
|
|
case UOT_NOT:
|
|
Expr_SetDataType(this, DATA_BOOL);
|
|
|
|
if (DATA_BOOL != dt)
|
|
res = RES_E_REQUIREBOOL;
|
|
break;
|
|
|
|
case UOT_GETIP:
|
|
Expr_SetDataType(this, DATA_STRING);
|
|
|
|
if (DATA_INT != dt)
|
|
res = RES_E_REQUIREINT;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
res = RES_E_INVALIDPARAM;
|
|
break;
|
|
}
|
|
|
|
if (RFAILED(res))
|
|
Stxerr_Add(hsaStxerr, SzFromUot(uot), Ast_GetLine(this), res);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Typechecks an expression.
|
|
|
|
Returns: RES_OK
|
|
or some error result
|
|
|
|
Cond: --
|
|
*/
|
|
RES PRIVATE Expr_Typecheck(
|
|
PEXPR this,
|
|
PSYMTAB pst,
|
|
HSA hsaStxerr)
|
|
{
|
|
RES res;
|
|
|
|
ASSERT(this);
|
|
ASSERT(hsaStxerr);
|
|
|
|
switch (Ast_GetType(this))
|
|
{
|
|
case AT_INT_EXPR:
|
|
Expr_SetDataType(this, DATA_INT);
|
|
res = RES_OK;
|
|
break;
|
|
|
|
case AT_STRING_EXPR:
|
|
Expr_SetDataType(this, DATA_STRING);
|
|
res = RES_OK;
|
|
break;
|
|
|
|
case AT_BOOL_EXPR:
|
|
Expr_SetDataType(this, DATA_BOOL);
|
|
res = RES_OK;
|
|
break;
|
|
|
|
case AT_VAR_EXPR:
|
|
res = VarExpr_Typecheck(this, pst, hsaStxerr);
|
|
break;
|
|
|
|
case AT_UNOP_EXPR:
|
|
res = UnOpExpr_Typecheck(this, pst, hsaStxerr);
|
|
break;
|
|
|
|
case AT_BINOP_EXPR:
|
|
res = BinOpExpr_Typecheck(this, pst, hsaStxerr);
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
res = RES_E_INVALIDPARAM;
|
|
break;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Typecheck the assignment statement
|
|
|
|
Returns: RES_OK
|
|
or some error result
|
|
|
|
Cond: --
|
|
*/
|
|
RES PRIVATE AssignStmt_Typecheck(
|
|
PSTMT this,
|
|
PSYMTAB pst,
|
|
HSA hsaStxerr)
|
|
{
|
|
RES res;
|
|
LPSTR pszIdent;
|
|
DATATYPE dt;
|
|
|
|
ASSERT(this);
|
|
ASSERT(hsaStxerr);
|
|
ASSERT(AT_ASSIGN_STMT == Ast_GetType(this));
|
|
|
|
pszIdent = AssignStmt_GetIdent(this);
|
|
res = Ident_Typecheck(pszIdent, 0, &dt, Ast_GetLine(this), pst, hsaStxerr);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
PEXPR pexpr = AssignStmt_GetExpr(this);
|
|
|
|
res = Expr_Typecheck(pexpr, pst, hsaStxerr);
|
|
|
|
// Types must match
|
|
if (dt != Expr_GetDataType(pexpr))
|
|
{
|
|
res = Stxerr_Add(hsaStxerr, "=", Ast_GetLine(pexpr), RES_E_TYPEMISMATCH);
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Typecheck the 'while' statement
|
|
|
|
Returns: RES_OK
|
|
or some error result
|
|
|
|
Cond: --
|
|
*/
|
|
RES PRIVATE WhileStmt_Typecheck(
|
|
PSTMT this,
|
|
PSYMTAB pst,
|
|
HSA hsaStxerr)
|
|
{
|
|
RES res;
|
|
PEXPR pexpr;
|
|
|
|
ASSERT(this);
|
|
ASSERT(hsaStxerr);
|
|
ASSERT(AT_WHILE_STMT == Ast_GetType(this));
|
|
|
|
pexpr = WhileStmt_GetExpr(this);
|
|
res = Expr_Typecheck(pexpr, pst, hsaStxerr);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
if (DATA_BOOL != Expr_GetDataType(pexpr))
|
|
{
|
|
res = Stxerr_Add(hsaStxerr, "'while' expression", Ast_GetLine(pexpr), RES_E_REQUIREBOOL);
|
|
}
|
|
else
|
|
{
|
|
// Typecheck the statement block
|
|
DWORD i;
|
|
DWORD cstmts;
|
|
HPA hpaStmts = WhileStmt_GetStmtBlock(this);
|
|
|
|
res = RES_OK;
|
|
|
|
cstmts = PAGetCount(hpaStmts);
|
|
|
|
// Typecheck each statement
|
|
for (i = 0; i < cstmts; i++)
|
|
{
|
|
PSTMT pstmt = PAFastGetPtr(hpaStmts, i);
|
|
|
|
res = Stmt_Typecheck(pstmt, pst, hsaStxerr);
|
|
if (RFAILED(res))
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Typecheck the 'if' statement
|
|
|
|
Returns: RES_OK
|
|
or some error result
|
|
|
|
Cond: --
|
|
*/
|
|
RES PRIVATE IfStmt_Typecheck(
|
|
PSTMT this,
|
|
PSYMTAB pst,
|
|
HSA hsaStxerr)
|
|
{
|
|
RES res;
|
|
PEXPR pexpr;
|
|
|
|
ASSERT(this);
|
|
ASSERT(hsaStxerr);
|
|
ASSERT(AT_IF_STMT == Ast_GetType(this));
|
|
|
|
pexpr = IfStmt_GetExpr(this);
|
|
res = Expr_Typecheck(pexpr, pst, hsaStxerr);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
if (DATA_BOOL != Expr_GetDataType(pexpr))
|
|
{
|
|
res = Stxerr_Add(hsaStxerr, "'if' expression", Ast_GetLine(pexpr), RES_E_REQUIREBOOL);
|
|
}
|
|
else
|
|
{
|
|
// Typecheck the statement block
|
|
DWORD i;
|
|
DWORD cstmts;
|
|
HPA hpaStmts = IfStmt_GetStmtBlock(this);
|
|
|
|
res = RES_OK;
|
|
|
|
cstmts = PAGetCount(hpaStmts);
|
|
|
|
// Typecheck each statement
|
|
for (i = 0; i < cstmts; i++)
|
|
{
|
|
PSTMT pstmt = PAFastGetPtr(hpaStmts, i);
|
|
|
|
res = Stmt_Typecheck(pstmt, pst, hsaStxerr);
|
|
if (RFAILED(res))
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Typecheck the label statement
|
|
|
|
Returns: RES_OK
|
|
or some error result
|
|
|
|
Cond: --
|
|
*/
|
|
RES PRIVATE LabelStmt_Typecheck(
|
|
PSTMT this,
|
|
PSYMTAB pst,
|
|
HSA hsaStxerr)
|
|
{
|
|
RES res;
|
|
PSTE pste;
|
|
LPSTR pszIdent;
|
|
|
|
ASSERT(this);
|
|
ASSERT(hsaStxerr);
|
|
ASSERT(AT_LABEL_STMT == Ast_GetType(this));
|
|
|
|
pszIdent = LabelStmt_GetIdent(this);
|
|
|
|
if (RES_OK == Symtab_FindEntry(pst, pszIdent, STFF_DEFAULT, &pste, NULL))
|
|
{
|
|
if (DATA_LABEL == STE_GetDataType(pste))
|
|
res = RES_OK;
|
|
else
|
|
res = Stxerr_Add(hsaStxerr, pszIdent, Ast_GetLine(this), RES_E_REQUIRELABEL);
|
|
}
|
|
else
|
|
{
|
|
// This should never get here
|
|
ASSERT(0);
|
|
res = RES_E_FAIL;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Typecheck the 'goto' statement
|
|
|
|
Returns: RES_OK
|
|
or some error result
|
|
|
|
Cond: --
|
|
*/
|
|
RES PRIVATE GotoStmt_Typecheck(
|
|
PSTMT this,
|
|
PSYMTAB pst,
|
|
HSA hsaStxerr)
|
|
{
|
|
LPSTR pszIdent;
|
|
|
|
ASSERT(this);
|
|
ASSERT(hsaStxerr);
|
|
ASSERT(AT_GOTO_STMT == Ast_GetType(this));
|
|
|
|
pszIdent = GotoStmt_GetIdent(this);
|
|
|
|
return Ident_Typecheck(pszIdent, DATA_LABEL, NULL, Ast_GetLine(this), pst, hsaStxerr);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Typecheck the transmit statement
|
|
|
|
Returns: RES_OK
|
|
or some error result
|
|
|
|
Cond: --
|
|
*/
|
|
RES PRIVATE TransmitStmt_Typecheck(
|
|
PSTMT this,
|
|
PSYMTAB pst,
|
|
HSA hsaStxerr)
|
|
{
|
|
RES res;
|
|
PEXPR pexpr;
|
|
|
|
ASSERT(this);
|
|
ASSERT(hsaStxerr);
|
|
ASSERT(AT_TRANSMIT_STMT == Ast_GetType(this));
|
|
|
|
pexpr = TransmitStmt_GetExpr(this);
|
|
res = Expr_Typecheck(pexpr, pst, hsaStxerr);
|
|
if (DATA_STRING != Expr_GetDataType(pexpr))
|
|
{
|
|
res = Stxerr_Add(hsaStxerr, "'transmit' parameter", Ast_GetLine(pexpr), RES_E_REQUIRESTRING);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Typecheck the 'waitfor' statement
|
|
|
|
waitfor <Expr>
|
|
[ then IDENT { , <Expr> then IDENT } ]
|
|
[ until <UntilExpr> ]
|
|
|
|
where:
|
|
<Expr> is a string
|
|
IDENT is a label
|
|
<UntilExpr> is an integer
|
|
|
|
Returns: RES_OK
|
|
or some error result
|
|
|
|
Cond: --
|
|
*/
|
|
RES PRIVATE WaitforStmt_Typecheck(
|
|
PSTMT this,
|
|
PSYMTAB pst,
|
|
HSA hsaStxerr)
|
|
{
|
|
RES res = RES_E_FAIL;
|
|
PEXPR pexpr;
|
|
HSA hsa;
|
|
DWORD i;
|
|
DWORD ccase;
|
|
PWAITCASE pwc;
|
|
|
|
ASSERT(this);
|
|
ASSERT(hsaStxerr);
|
|
ASSERT(AT_WAITFOR_STMT == Ast_GetType(this));
|
|
|
|
// Typecheck that <Expr> is of type string, and any
|
|
// IDENTs are labels.
|
|
|
|
hsa = WaitforStmt_GetCaseList(this);
|
|
ccase = SAGetCount(hsa);
|
|
for (i = 0; i < ccase; i++)
|
|
{
|
|
SAGetItemPtr(hsa, i, &pwc);
|
|
ASSERT(pwc);
|
|
|
|
// Typecheck <Expr>
|
|
res = Expr_Typecheck(pwc->pexpr, pst, hsaStxerr);
|
|
if (DATA_STRING != Expr_GetDataType(pwc->pexpr))
|
|
{
|
|
res = Stxerr_Add(hsaStxerr, "'waitfor' parameter", Ast_GetLine(pwc->pexpr), RES_E_REQUIRESTRING);
|
|
break;
|
|
}
|
|
|
|
// Typecheck IDENT label. If there is only one <Expr>, there
|
|
// may not be an IDENT label.
|
|
|
|
if (pwc->pszIdent)
|
|
{
|
|
res = Ident_Typecheck(pwc->pszIdent, DATA_LABEL, NULL, Ast_GetLine(pwc->pexpr), pst, hsaStxerr);
|
|
if (RFAILED(res))
|
|
break;
|
|
}
|
|
else
|
|
ASSERT(1 == ccase);
|
|
}
|
|
|
|
// 'until' expression is optional
|
|
if (RSUCCEEDED(res) &&
|
|
NULL != (pexpr = WaitforStmt_GetUntilExpr(this)))
|
|
{
|
|
res = Expr_Typecheck(pexpr, pst, hsaStxerr);
|
|
if (DATA_INT != Expr_GetDataType(pexpr))
|
|
{
|
|
res = Stxerr_Add(hsaStxerr, "'until' parameter", Ast_GetLine(pexpr), RES_E_REQUIREINT);
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Typecheck the 'delay' statement
|
|
|
|
Returns: RES_OK
|
|
or some error result
|
|
|
|
Cond: --
|
|
*/
|
|
RES PRIVATE DelayStmt_Typecheck(
|
|
PSTMT this,
|
|
PSYMTAB pst,
|
|
HSA hsaStxerr)
|
|
{
|
|
RES res;
|
|
PEXPR pexpr;
|
|
|
|
ASSERT(this);
|
|
ASSERT(hsaStxerr);
|
|
ASSERT(AT_DELAY_STMT == Ast_GetType(this));
|
|
|
|
pexpr = DelayStmt_GetExpr(this);
|
|
res = Expr_Typecheck(pexpr, pst, hsaStxerr);
|
|
if (DATA_INT != Expr_GetDataType(pexpr))
|
|
{
|
|
res = Stxerr_Add(hsaStxerr, "'delay' parameter", Ast_GetLine(pexpr), RES_E_REQUIREINT);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Typecheck the 'set' statement
|
|
|
|
Returns: RES_OK
|
|
or some error result
|
|
|
|
Cond: --
|
|
*/
|
|
RES PRIVATE SetStmt_Typecheck(
|
|
PSTMT this,
|
|
PSYMTAB pst,
|
|
HSA hsaStxerr)
|
|
{
|
|
RES res;
|
|
PEXPR pexpr;
|
|
|
|
ASSERT(this);
|
|
ASSERT(hsaStxerr);
|
|
ASSERT(AT_SET_STMT == Ast_GetType(this));
|
|
|
|
switch (SetStmt_GetType(this))
|
|
{
|
|
case ST_IPADDR:
|
|
pexpr = SetIPStmt_GetExpr(this);
|
|
res = Expr_Typecheck(pexpr, pst, hsaStxerr);
|
|
if (DATA_STRING != Expr_GetDataType(pexpr))
|
|
{
|
|
res = Stxerr_Add(hsaStxerr, "'ipaddr' parameter", Ast_GetLine(pexpr), RES_E_REQUIRESTRING);
|
|
}
|
|
break;
|
|
|
|
case ST_PORT:
|
|
case ST_SCREEN:
|
|
res = RES_OK;
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
res = RES_E_INVALIDPARAM;
|
|
break;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Typecheck a statement
|
|
|
|
Returns: RES_OK
|
|
or some error result
|
|
|
|
Cond: --
|
|
*/
|
|
RES PRIVATE Stmt_Typecheck(
|
|
PSTMT this,
|
|
PSYMTAB pst,
|
|
HSA hsaStxerr)
|
|
{
|
|
RES res;
|
|
|
|
ASSERT(this);
|
|
ASSERT(hsaStxerr);
|
|
|
|
switch (Ast_GetType(this))
|
|
{
|
|
case AT_ENTER_STMT:
|
|
case AT_LEAVE_STMT:
|
|
res = RES_OK;
|
|
break;
|
|
|
|
case AT_WHILE_STMT:
|
|
res = WhileStmt_Typecheck(this, pst, hsaStxerr);
|
|
break;
|
|
|
|
case AT_IF_STMT:
|
|
res = IfStmt_Typecheck(this, pst, hsaStxerr);
|
|
break;
|
|
|
|
case AT_ASSIGN_STMT:
|
|
res = AssignStmt_Typecheck(this, pst, hsaStxerr);
|
|
break;
|
|
|
|
case AT_HALT_STMT:
|
|
// Nothing to typecheck here
|
|
res = RES_OK;
|
|
break;
|
|
|
|
case AT_TRANSMIT_STMT:
|
|
res = TransmitStmt_Typecheck(this, pst, hsaStxerr);
|
|
break;
|
|
|
|
case AT_WAITFOR_STMT:
|
|
res = WaitforStmt_Typecheck(this, pst, hsaStxerr);
|
|
break;
|
|
|
|
case AT_DELAY_STMT:
|
|
res = DelayStmt_Typecheck(this, pst, hsaStxerr);
|
|
break;
|
|
|
|
case AT_LABEL_STMT:
|
|
res = LabelStmt_Typecheck(this, pst, hsaStxerr);
|
|
break;
|
|
|
|
case AT_GOTO_STMT:
|
|
res = GotoStmt_Typecheck(this, pst, hsaStxerr);
|
|
break;
|
|
|
|
case AT_SET_STMT:
|
|
res = SetStmt_Typecheck(this, pst, hsaStxerr);
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
res = RES_E_INVALIDPARAM;
|
|
break;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Typecheck a procedure declaration.
|
|
|
|
Returns: RES_OK
|
|
or some error result
|
|
|
|
Cond: --
|
|
*/
|
|
RES PRIVATE ProcDecl_Typecheck(
|
|
PPROCDECL this,
|
|
PSYMTAB pst,
|
|
HSA hsaStxerr)
|
|
{
|
|
RES res = RES_OK;
|
|
DWORD i;
|
|
DWORD cstmts;
|
|
|
|
ASSERT(this);
|
|
ASSERT(hsaStxerr);
|
|
|
|
cstmts = PAGetCount(this->hpaStmts);
|
|
|
|
// Typecheck each statement
|
|
for (i = 0; i < cstmts; i++)
|
|
{
|
|
PSTMT pstmt = PAFastGetPtr(this->hpaStmts, i);
|
|
|
|
res = Stmt_Typecheck(pstmt, this->pst, hsaStxerr);
|
|
if (RFAILED(res))
|
|
break;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Typecheck a module declaration.
|
|
|
|
Returns: RES_OK
|
|
or some error result
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC ModuleDecl_Typecheck(
|
|
PMODULEDECL this,
|
|
HSA hsaStxerr)
|
|
{
|
|
RES res = RES_OK;
|
|
DWORD i;
|
|
DWORD cprocs;
|
|
BOOL bFoundMain = FALSE;
|
|
|
|
ASSERT(this);
|
|
ASSERT(hsaStxerr);
|
|
|
|
TRACE_MSG(TF_GENERAL, "Typechecking...");
|
|
|
|
cprocs = PAGetCount(this->hpaProcs);
|
|
|
|
// Typecheck each proc
|
|
for (i = 0; i < cprocs; i++)
|
|
{
|
|
PPROCDECL pprocdecl = PAFastGetPtr(this->hpaProcs, i);
|
|
|
|
if (IsSzEqualC(ProcDecl_GetIdent(pprocdecl), "main"))
|
|
bFoundMain = TRUE;
|
|
|
|
res = ProcDecl_Typecheck(pprocdecl, this->pst, hsaStxerr);
|
|
if (RFAILED(res))
|
|
break;
|
|
}
|
|
|
|
// There must be a main proc
|
|
if (RSUCCEEDED(res) && !bFoundMain)
|
|
res = Stxerr_AddTok(hsaStxerr, NULL, RES_E_MAINMISSING);
|
|
|
|
return res;
|
|
}
|
|
|
|
|