mirror of https://github.com/tongzx/nt5src
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.
2537 lines
50 KiB
2537 lines
50 KiB
//
|
|
// Copyright (c) Microsoft Corporation 1995
|
|
//
|
|
// ast.c
|
|
//
|
|
// This file contains the abstract syntax tree functions.
|
|
//
|
|
// History:
|
|
// 05-20-95 ScottH Created
|
|
//
|
|
|
|
|
|
#include "proj.h"
|
|
#include "rcids.h"
|
|
|
|
#define RetInt(ppv, x) (*((LPINT)*(ppv)) = (x))
|
|
#define RetStr(ppv, x) (*((LPSTR)*(ppv)) = (x))
|
|
#define RetBool(ppv, x) (*((LPBOOL)*(ppv)) = (x))
|
|
|
|
|
|
//
|
|
// Wait case functions
|
|
//
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Dump a waitcase structure
|
|
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
void PRIVATE Waitcase_Dump(
|
|
PWAITCASE this)
|
|
{
|
|
Ast_Dump((PAST)this->pexpr);
|
|
if (this->pszIdent)
|
|
{
|
|
TRACE_MSG(TF_ALWAYS, " then %s", this->pszIdent);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Create a wait-case list.
|
|
|
|
Returns: RES_OK
|
|
RES_E_OUTOFMEMORY
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC Waitcase_Create(
|
|
PHSA phsa)
|
|
{
|
|
RES res = RES_OK;
|
|
|
|
if ( !SACreate(phsa, sizeof(WAITCASE), 8) )
|
|
res = RES_E_OUTOFMEMORY;
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Add a case to the given wait-case list.
|
|
|
|
Returns: RES_OK
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC Waitcase_Add(
|
|
HSA hsa,
|
|
PEXPR pexpr,
|
|
LPCSTR pszIdent, // This may be NULL
|
|
DWORD dwFlags)
|
|
{
|
|
RES res = RES_OK; // assume success
|
|
WAITCASE wc;
|
|
|
|
ASSERT(hsa);
|
|
ASSERT(pexpr);
|
|
|
|
wc.pexpr = pexpr;
|
|
wc.dwFlags = dwFlags;
|
|
wc.pszIdent = NULL;
|
|
|
|
// Copy pszIdent since the parameter is freed by the caller.
|
|
if ( pszIdent && !GSetString(&wc.pszIdent, pszIdent) )
|
|
res = RES_E_OUTOFMEMORY;
|
|
|
|
else if ( !SAInsertItem(hsa, SA_APPEND, &wc) )
|
|
res = RES_E_OUTOFMEMORY;
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Free the contents of the given pointer.
|
|
|
|
Returns: --
|
|
|
|
Cond: Don't free the pointer itself!
|
|
*/
|
|
void CALLBACK Waitcase_FreeSA(
|
|
PVOID pv,
|
|
LPARAM lparam)
|
|
{
|
|
PWAITCASE pwc = (PWAITCASE)pv;
|
|
|
|
if (pwc->pexpr)
|
|
Expr_Delete(pwc->pexpr);
|
|
|
|
if (pwc->pszIdent)
|
|
GSetString(&pwc->pszIdent, NULL); // free
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Destroy the wait case list.
|
|
|
|
Returns: RES_OK
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC Waitcase_Destroy(
|
|
HSA hsa)
|
|
{
|
|
ASSERT(hsa);
|
|
|
|
SADestroyEx(hsa, Waitcase_FreeSA, 0);
|
|
return RES_OK;
|
|
}
|
|
|
|
|
|
//
|
|
// Base level AST functions
|
|
//
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Dump the AST
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
void PUBLIC Ast_Dump(
|
|
PAST this)
|
|
{
|
|
ASSERT(this);
|
|
|
|
if (IsFlagSet(g_dwDumpFlags, DF_AST))
|
|
{
|
|
switch (this->asttype)
|
|
{
|
|
case AT_BASE:
|
|
TRACE_MSG(TF_ALWAYS, "Unknown AST");
|
|
break;
|
|
|
|
case AT_MODULE_DECL: {
|
|
PMODULEDECL pmd = (PMODULEDECL)this;
|
|
DWORD i;
|
|
DWORD cprocs = PAGetCount(pmd->hpaProcs);
|
|
|
|
TRACE_MSG(TF_ALWAYS, "module");
|
|
|
|
for (i = 0; i < cprocs; i++)
|
|
Ast_Dump(PAFastGetPtr(pmd->hpaProcs, i));
|
|
}
|
|
break;
|
|
|
|
case AT_PROC_DECL: {
|
|
PPROCDECL ppd = (PPROCDECL)this;
|
|
DWORD i;
|
|
DWORD cstmts = PAGetCount(ppd->hpaStmts);
|
|
|
|
TRACE_MSG(TF_ALWAYS, "proc %s", ProcDecl_GetIdent(ppd));
|
|
|
|
for (i = 0; i < cstmts; i++)
|
|
Ast_Dump(PAFastGetPtr(ppd->hpaStmts, i));
|
|
|
|
TRACE_MSG(TF_ALWAYS, "endproc");
|
|
}
|
|
break;
|
|
|
|
case AT_ENTER_STMT:
|
|
TRACE_MSG(TF_ALWAYS, "enter");
|
|
break;
|
|
|
|
case AT_LEAVE_STMT:
|
|
TRACE_MSG(TF_ALWAYS, "leave");
|
|
break;
|
|
|
|
case AT_HALT_STMT:
|
|
TRACE_MSG(TF_ALWAYS, "halt");
|
|
break;
|
|
|
|
case AT_ASSIGN_STMT:
|
|
TRACE_MSG(TF_ALWAYS, "%s = ", AssignStmt_GetIdent(this));
|
|
Ast_Dump((PAST)AssignStmt_GetExpr(this));
|
|
break;
|
|
|
|
case AT_LABEL_STMT:
|
|
TRACE_MSG(TF_ALWAYS, "%s:", LabelStmt_GetIdent(this));
|
|
break;
|
|
|
|
case AT_GOTO_STMT:
|
|
TRACE_MSG(TF_ALWAYS, "goto %s", GotoStmt_GetIdent(this));
|
|
break;
|
|
|
|
case AT_WHILE_STMT:
|
|
TRACE_MSG(TF_ALWAYS, "while ");
|
|
TRACE_MSG(TF_ALWAYS, " do ");
|
|
TRACE_MSG(TF_ALWAYS, "endwhile ");
|
|
break;
|
|
|
|
case AT_IF_STMT:
|
|
TRACE_MSG(TF_ALWAYS, "if ");
|
|
TRACE_MSG(TF_ALWAYS, " then ");
|
|
TRACE_MSG(TF_ALWAYS, "endif ");
|
|
break;
|
|
|
|
case AT_DELAY_STMT:
|
|
TRACE_MSG(TF_ALWAYS, "delay");
|
|
Ast_Dump((PAST)DelayStmt_GetExpr(this));
|
|
break;
|
|
|
|
case AT_WAITFOR_STMT: {
|
|
PWAITFORSTMT pws = (PWAITFORSTMT)this;
|
|
DWORD ccase = SAGetCount(pws->hsa);
|
|
DWORD i;
|
|
|
|
TRACE_MSG(TF_ALWAYS, "waitfor");
|
|
|
|
for (i = 0; i < ccase; i++)
|
|
{
|
|
PVOID pv;
|
|
SAGetItemPtr(pws->hsa, i, &pv);
|
|
Waitcase_Dump(pv);
|
|
}
|
|
|
|
if (WaitforStmt_GetUntilExpr(this))
|
|
{
|
|
TRACE_MSG(TF_ALWAYS, "until");
|
|
Ast_Dump((PAST)WaitforStmt_GetUntilExpr(this));
|
|
}
|
|
}
|
|
break;
|
|
|
|
case AT_TRANSMIT_STMT:
|
|
TRACE_MSG(TF_ALWAYS, "transmit");
|
|
Ast_Dump((PAST)TransmitStmt_GetExpr(this));
|
|
break;
|
|
|
|
case AT_SET_STMT:
|
|
switch (SetStmt_GetType(this))
|
|
{
|
|
case ST_IPADDR:
|
|
TRACE_MSG(TF_ALWAYS, "set ipaddr getip");
|
|
Ast_Dump((PAST)SetIPStmt_GetExpr(this));
|
|
break;
|
|
|
|
case ST_PORT:
|
|
if (IsFlagSet(SetPortStmt_GetFlags(this), SPF_DATABITS))
|
|
TRACE_MSG(TF_ALWAYS, "set port databits %u", SetPortStmt_GetDatabits(this));
|
|
|
|
if (IsFlagSet(SetPortStmt_GetFlags(this), SPF_STOPBITS))
|
|
TRACE_MSG(TF_ALWAYS, "set port stopbits %u", SetPortStmt_GetStopbits(this));
|
|
|
|
if (IsFlagSet(SetPortStmt_GetFlags(this), SPF_PARITY))
|
|
TRACE_MSG(TF_ALWAYS, "set port parity %u", SetPortStmt_GetParity(this));
|
|
break;
|
|
|
|
case ST_SCREEN:
|
|
if (IsFlagSet(SetScreenStmt_GetFlags(this), SPF_KEYBRD))
|
|
TRACE_MSG(TF_ALWAYS, "set screen keyboard %s", SetScreenStmt_GetKeybrd(this) ? "on" : "off");
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case AT_INT_EXPR:
|
|
TRACE_MSG(TF_ALWAYS, " %d", IntExpr_GetVal(this));
|
|
break;
|
|
|
|
case AT_STRING_EXPR:
|
|
TRACE_MSG(TF_ALWAYS, " %s", StrExpr_GetStr(this));
|
|
break;
|
|
|
|
case AT_BOOL_EXPR:
|
|
TRACE_MSG(TF_ALWAYS, " %s", BoolExpr_GetVal(this) ? (LPSTR)"TRUE" : (LPSTR)"FALSE");
|
|
break;
|
|
|
|
case AT_VAR_EXPR:
|
|
TRACE_MSG(TF_ALWAYS, " %s", VarExpr_GetIdent(this));
|
|
break;
|
|
|
|
case AT_BINOP_EXPR: {
|
|
PBINOPEXPR pbo = (PBINOPEXPR)this;
|
|
|
|
Ast_Dump((PAST)pbo->pexpr1);
|
|
|
|
switch (BinOpExpr_GetType(this))
|
|
{
|
|
case BOT_OR:
|
|
TRACE_MSG(TF_ALWAYS, " or");
|
|
break;
|
|
|
|
case BOT_AND:
|
|
TRACE_MSG(TF_ALWAYS, " and");
|
|
break;
|
|
|
|
case BOT_LT:
|
|
TRACE_MSG(TF_ALWAYS, " <");
|
|
break;
|
|
|
|
case BOT_LEQ:
|
|
TRACE_MSG(TF_ALWAYS, " <=");
|
|
break;
|
|
|
|
case BOT_GT:
|
|
TRACE_MSG(TF_ALWAYS, " >");
|
|
break;
|
|
|
|
case BOT_GEQ:
|
|
TRACE_MSG(TF_ALWAYS, " >=");
|
|
break;
|
|
|
|
case BOT_EQ:
|
|
TRACE_MSG(TF_ALWAYS, " ==");
|
|
break;
|
|
|
|
case BOT_NEQ:
|
|
TRACE_MSG(TF_ALWAYS, " !=");
|
|
break;
|
|
|
|
case BOT_PLUS:
|
|
TRACE_MSG(TF_ALWAYS, " +");
|
|
break;
|
|
|
|
case BOT_MINUS:
|
|
TRACE_MSG(TF_ALWAYS, " -");
|
|
break;
|
|
|
|
case BOT_MULT:
|
|
TRACE_MSG(TF_ALWAYS, " *");
|
|
break;
|
|
|
|
case BOT_DIV:
|
|
TRACE_MSG(TF_ALWAYS, " /");
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
break;
|
|
}
|
|
|
|
Ast_Dump((PAST)pbo->pexpr2);
|
|
}
|
|
break;
|
|
|
|
case AT_UNOP_EXPR: {
|
|
PUNOPEXPR puo = (PUNOPEXPR)this;
|
|
|
|
switch (UnOpExpr_GetType(this))
|
|
{
|
|
case UOT_NEG:
|
|
TRACE_MSG(TF_ALWAYS, " -");
|
|
break;
|
|
|
|
case UOT_NOT:
|
|
TRACE_MSG(TF_ALWAYS, " !");
|
|
break;
|
|
|
|
case UOT_GETIP:
|
|
TRACE_MSG(TF_ALWAYS, " getip");
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
break;
|
|
}
|
|
|
|
Ast_Dump((PAST)puo->pexpr);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif // DEBUG
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Creates a new AST
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_OUTOFMEMORY
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC Ast_New(
|
|
LPVOID * ppv,
|
|
ASTTYPE asttype,
|
|
DWORD cbSize,
|
|
DWORD iLine)
|
|
{
|
|
PAST past;
|
|
|
|
ASSERT(ppv);
|
|
|
|
past = GAlloc(cbSize);
|
|
if (past)
|
|
{
|
|
Ast_SetSize(past, cbSize);
|
|
Ast_SetType(past, asttype);
|
|
Ast_SetLine(past, iLine);
|
|
}
|
|
*ppv = past;
|
|
|
|
return NULL != past ? RES_OK : RES_E_OUTOFMEMORY;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Destroys the given AST.
|
|
Returns:
|
|
Cond: --
|
|
*/
|
|
void PUBLIC Ast_Delete(
|
|
PAST this)
|
|
{
|
|
GFree(this);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Duplicate the given AST.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_OUTOFMEMORY
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC Ast_Dup(
|
|
PAST this,
|
|
PAST * ppast)
|
|
{
|
|
PAST past;
|
|
DWORD cbSize;
|
|
|
|
ASSERT(this);
|
|
ASSERT(ppast);
|
|
|
|
cbSize = Ast_GetSize(this);
|
|
|
|
past = GAlloc(cbSize);
|
|
if (past)
|
|
{
|
|
BltByte(past, this, cbSize);
|
|
}
|
|
*ppast = past;
|
|
|
|
return NULL != past ? RES_OK : RES_E_OUTOFMEMORY;
|
|
}
|
|
|
|
|
|
//
|
|
// Expressions
|
|
//
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Callback for PADestroyEx.
|
|
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
void CALLBACK Expr_DeletePAPtr(
|
|
LPVOID pv,
|
|
LPARAM lparam)
|
|
{
|
|
Expr_Delete(pv);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Destroys an Expr.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC Expr_Delete(
|
|
PEXPR this)
|
|
{
|
|
RES res;
|
|
|
|
DBG_ENTER(Expr_Delete);
|
|
|
|
if (this)
|
|
{
|
|
res = RES_OK;
|
|
|
|
switch (this->ast.asttype)
|
|
{
|
|
case AT_INT_EXPR:
|
|
case AT_BOOL_EXPR:
|
|
// (Nothing to free inside)
|
|
break;
|
|
|
|
case AT_STRING_EXPR: {
|
|
PSTREXPR ps = (PSTREXPR)this;
|
|
|
|
if (ps->psz)
|
|
GSetString(&ps->psz, NULL); // free
|
|
}
|
|
break;
|
|
|
|
case AT_VAR_EXPR: {
|
|
PVAREXPR ps = (PVAREXPR)this;
|
|
|
|
if (ps->pszIdent)
|
|
GSetString(&ps->pszIdent, NULL); // free
|
|
}
|
|
break;
|
|
|
|
case AT_BINOP_EXPR: {
|
|
PBINOPEXPR pbo = (PBINOPEXPR)this;
|
|
|
|
if (pbo->pexpr1)
|
|
Expr_Delete(pbo->pexpr1);
|
|
|
|
if (pbo->pexpr2)
|
|
Expr_Delete(pbo->pexpr2);
|
|
|
|
}
|
|
break;
|
|
|
|
case AT_UNOP_EXPR: {
|
|
PUNOPEXPR puo = (PUNOPEXPR)this;
|
|
|
|
if (puo->pexpr)
|
|
Expr_Delete(puo->pexpr);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
res = RES_E_INVALIDPARAM;
|
|
break;
|
|
}
|
|
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
// Most of the time when the evaluated result
|
|
// is a string, it is just a copy of the pointer
|
|
// in the specific class structure. In these
|
|
// cases it does not need to be freed again,
|
|
// because it was freed above.
|
|
|
|
if (this->er.psz && IsFlagSet(this->dwFlags, EF_ALLOCATED))
|
|
{
|
|
ASSERT(DATA_STRING == Expr_GetDataType(this));
|
|
|
|
GSetString(&this->er.psz, NULL); // free
|
|
}
|
|
|
|
Ast_Delete((PAST)this);
|
|
}
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
DBG_EXIT_RES(Expr_Delete, res);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Creates a IntExpr object.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_OUTOFMEMORY
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC IntExpr_New(
|
|
PEXPR * ppexpr,
|
|
int nVal,
|
|
DWORD iLine)
|
|
{
|
|
RES res;
|
|
|
|
DBG_ENTER(IntExpr_New);
|
|
|
|
ASSERT(ppexpr);
|
|
|
|
if (ppexpr)
|
|
{
|
|
PINTEXPR this;
|
|
|
|
res = Ast_New(&this, AT_INT_EXPR, sizeof(*this), iLine);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
IntExpr_SetVal(this, nVal);
|
|
}
|
|
|
|
*ppexpr = (PEXPR)this;
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
DBG_EXIT_RES(IntExpr_New, res);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Creates a StrExpr object.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_OUTOFMEMORY
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC StrExpr_New(
|
|
PEXPR * ppexpr,
|
|
LPCSTR psz,
|
|
DWORD iLine)
|
|
{
|
|
RES res;
|
|
|
|
DBG_ENTER(StrExpr_New);
|
|
|
|
ASSERT(ppexpr);
|
|
ASSERT(psz);
|
|
|
|
if (ppexpr)
|
|
{
|
|
PSTREXPR this;
|
|
|
|
res = Ast_New(&this, AT_STRING_EXPR, sizeof(*this), iLine);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
res = RES_OK;
|
|
|
|
if (!GSetString(&this->psz, psz))
|
|
res = RES_E_OUTOFMEMORY;
|
|
|
|
if (RFAILED(res))
|
|
{
|
|
Ast_Delete((PAST)this);
|
|
this = NULL;
|
|
}
|
|
}
|
|
|
|
*ppexpr = (PEXPR)this;
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
DBG_EXIT_RES(StrExpr_New, res);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Creates a BoolExpr object.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_OUTOFMEMORY
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC BoolExpr_New(
|
|
PEXPR * ppexpr,
|
|
BOOL bVal,
|
|
DWORD iLine)
|
|
{
|
|
RES res;
|
|
|
|
DBG_ENTER(BoolExpr_New);
|
|
|
|
ASSERT(ppexpr);
|
|
|
|
if (ppexpr)
|
|
{
|
|
PBOOLEXPR this;
|
|
|
|
res = Ast_New(&this, AT_BOOL_EXPR, sizeof(*this), iLine);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
BoolExpr_SetVal(this, bVal);
|
|
}
|
|
|
|
*ppexpr = (PEXPR)this;
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
DBG_EXIT_RES(BoolExpr_New, res);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Creates a VarExpr object.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_OUTOFMEMORY
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC VarExpr_New(
|
|
PEXPR * ppexpr,
|
|
LPCSTR pszIdent,
|
|
DWORD iLine)
|
|
{
|
|
RES res;
|
|
|
|
DBG_ENTER(VarExpr_New);
|
|
|
|
ASSERT(ppexpr);
|
|
ASSERT(pszIdent);
|
|
|
|
if (ppexpr)
|
|
{
|
|
PVAREXPR this;
|
|
|
|
res = Ast_New(&this, AT_VAR_EXPR, sizeof(*this), iLine);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
res = RES_OK;
|
|
|
|
if (!GSetString(&this->pszIdent, pszIdent))
|
|
res = RES_E_OUTOFMEMORY;
|
|
|
|
if (RFAILED(res))
|
|
{
|
|
Ast_Delete((PAST)this);
|
|
this = NULL;
|
|
}
|
|
}
|
|
|
|
*ppexpr = (PEXPR)this;
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
DBG_EXIT_RES(VarExpr_New, res);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Creates a BinOpExpr object.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_OUTOFMEMORY
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC BinOpExpr_New(
|
|
PEXPR * ppexpr,
|
|
BINOPTYPE binoptype,
|
|
PEXPR pexpr1,
|
|
PEXPR pexpr2,
|
|
DWORD iLine)
|
|
{
|
|
RES res;
|
|
|
|
DBG_ENTER(BinOpExpr_New);
|
|
|
|
ASSERT(ppexpr);
|
|
ASSERT(pexpr1);
|
|
ASSERT(pexpr2);
|
|
|
|
if (ppexpr)
|
|
{
|
|
PBINOPEXPR this;
|
|
|
|
res = Ast_New(&this, AT_BINOP_EXPR, sizeof(*this), iLine);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
res = RES_OK;
|
|
|
|
BinOpExpr_SetType(this, binoptype);
|
|
|
|
this->pexpr1 = pexpr1;
|
|
this->pexpr2 = pexpr2;
|
|
}
|
|
|
|
*ppexpr = (PEXPR)this;
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
DBG_EXIT_RES(BinOpExpr_New, res);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Creates a UnOpExpr object.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_OUTOFMEMORY
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC UnOpExpr_New(
|
|
PEXPR * ppexpr,
|
|
UNOPTYPE unoptype,
|
|
PEXPR pexpr,
|
|
DWORD iLine)
|
|
{
|
|
RES res;
|
|
|
|
DBG_ENTER(UnOpExpr_New);
|
|
|
|
ASSERT(ppexpr);
|
|
ASSERT(pexpr);
|
|
|
|
if (ppexpr)
|
|
{
|
|
PUNOPEXPR this;
|
|
|
|
res = Ast_New(&this, AT_UNOP_EXPR, sizeof(*this), iLine);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
UnOpExpr_SetType(this, unoptype);
|
|
|
|
this->pexpr = pexpr;
|
|
}
|
|
|
|
*ppexpr = (PEXPR)this;
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
DBG_EXIT_RES(UnOpExpr_New, res);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
//
|
|
// Stmt
|
|
//
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Callback for PADestroyEx.
|
|
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
void CALLBACK Stmt_DeletePAPtr(
|
|
LPVOID pv,
|
|
LPARAM lparam)
|
|
{
|
|
Stmt_Delete(pv);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Destroys a Stmt.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC Stmt_Delete(
|
|
PSTMT this)
|
|
{
|
|
RES res;
|
|
|
|
DBG_ENTER(Stmt_Delete);
|
|
|
|
if (this)
|
|
{
|
|
PEXPR pexpr;
|
|
HSA hsa;
|
|
|
|
res = RES_OK;
|
|
|
|
switch (this->ast.asttype)
|
|
{
|
|
case AT_ENTER_STMT:
|
|
// (don't free pst -- it belongs to the decl structs)
|
|
case AT_LEAVE_STMT:
|
|
case AT_HALT_STMT:
|
|
break;
|
|
|
|
case AT_ASSIGN_STMT: {
|
|
PASSIGNSTMT pls = (PASSIGNSTMT)this;
|
|
|
|
if (pls->pszIdent)
|
|
GSetString(&pls->pszIdent, NULL); // free
|
|
|
|
pexpr = AssignStmt_GetExpr(this);
|
|
|
|
if (pexpr)
|
|
Expr_Delete(pexpr);
|
|
}
|
|
break;
|
|
|
|
case AT_WHILE_STMT: {
|
|
PWHILESTMT pls = (PWHILESTMT)this;
|
|
|
|
pexpr = WhileStmt_GetExpr(this);
|
|
|
|
if (pexpr)
|
|
Expr_Delete(pexpr);
|
|
|
|
if (pls->hpaStmts)
|
|
PADestroyEx(pls->hpaStmts, Stmt_DeletePAPtr, 0);
|
|
}
|
|
break;
|
|
|
|
case AT_IF_STMT: {
|
|
PIFSTMT pls = (PIFSTMT)this;
|
|
|
|
pexpr = IfStmt_GetExpr(this);
|
|
|
|
if (pexpr)
|
|
Expr_Delete(pexpr);
|
|
|
|
if (pls->hpaStmts)
|
|
PADestroyEx(pls->hpaStmts, Stmt_DeletePAPtr, 0);
|
|
}
|
|
break;
|
|
|
|
case AT_LABEL_STMT: {
|
|
PLABELSTMT pls = (PLABELSTMT)this;
|
|
|
|
if (pls->psz)
|
|
GSetString(&pls->psz, NULL); // free
|
|
}
|
|
break;
|
|
|
|
case AT_GOTO_STMT: {
|
|
PGOTOSTMT pgs = (PGOTOSTMT)this;
|
|
|
|
if (pgs->psz)
|
|
GSetString(&pgs->psz, NULL); // free
|
|
}
|
|
break;
|
|
|
|
case AT_DELAY_STMT:
|
|
pexpr = DelayStmt_GetExpr(this);
|
|
|
|
if (pexpr)
|
|
Expr_Delete(pexpr);
|
|
break;
|
|
|
|
case AT_TRANSMIT_STMT:
|
|
pexpr = TransmitStmt_GetExpr(this);
|
|
|
|
if (pexpr)
|
|
Expr_Delete(pexpr);
|
|
break;
|
|
|
|
case AT_WAITFOR_STMT:
|
|
|
|
hsa = WaitforStmt_GetCaseList(this);
|
|
if (hsa)
|
|
Waitcase_Destroy(hsa);
|
|
|
|
pexpr = WaitforStmt_GetUntilExpr(this);
|
|
if (pexpr)
|
|
Expr_Delete(pexpr);
|
|
break;
|
|
|
|
case AT_SET_STMT:
|
|
switch (SetStmt_GetType(this))
|
|
{
|
|
case ST_IPADDR:
|
|
pexpr = SetIPStmt_GetExpr(this);
|
|
|
|
if (pexpr)
|
|
Expr_Delete(pexpr);
|
|
break;
|
|
|
|
case ST_PORT:
|
|
case ST_SCREEN:
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
res = RES_E_INVALIDPARAM;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
res = RES_E_INVALIDPARAM;
|
|
break;
|
|
}
|
|
|
|
if (RSUCCEEDED(res))
|
|
Ast_Delete((PAST)this);
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
DBG_EXIT_RES(Stmt_Delete, res);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
//
|
|
// Statements
|
|
//
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Creates a WaitforStmt object.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_OUTOFMEMORY
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC WaitforStmt_New(
|
|
PSTMT * ppstmt,
|
|
HSA hsa,
|
|
PEXPR pexprUntil, // May be NULL
|
|
DWORD iLine)
|
|
{
|
|
RES res;
|
|
|
|
DBG_ENTER(WaitforStmt_New);
|
|
|
|
ASSERT(ppstmt);
|
|
ASSERT(hsa);
|
|
|
|
if (ppstmt)
|
|
{
|
|
PWAITFORSTMT this;
|
|
|
|
res = Ast_New(&this, AT_WAITFOR_STMT, sizeof(*this), iLine);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
res = RES_OK; // assume success
|
|
|
|
this->hsa = hsa;
|
|
this->pexprUntil = pexprUntil;
|
|
}
|
|
|
|
*ppstmt = (PSTMT)this;
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
DBG_EXIT_RES(WaitforStmt_New, res);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Creates a TransmitStmt object.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_OUTOFMEMORY
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC TransmitStmt_New(
|
|
PSTMT * ppstmt,
|
|
PEXPR pexpr,
|
|
DWORD dwFlags,
|
|
DWORD iLine)
|
|
{
|
|
RES res;
|
|
|
|
DBG_ENTER(TransmitStmt_New);
|
|
|
|
ASSERT(ppstmt);
|
|
ASSERT(pexpr);
|
|
|
|
if (ppstmt)
|
|
{
|
|
PTRANSMITSTMT this;
|
|
|
|
res = Ast_New(&this, AT_TRANSMIT_STMT, sizeof(*this), iLine);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
res = RES_OK; // assume success
|
|
|
|
this->pexpr = pexpr;
|
|
this->dwFlags = dwFlags;
|
|
}
|
|
|
|
*ppstmt = (PSTMT)this;
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
DBG_EXIT_RES(TransmitStmt_New, res);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Creates a DelayStmt object.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_OUTOFMEMORY
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC DelayStmt_New(
|
|
PSTMT * ppstmt,
|
|
PEXPR pexpr,
|
|
DWORD iLine)
|
|
{
|
|
RES res;
|
|
|
|
DBG_ENTER(DelayStmt_New);
|
|
|
|
ASSERT(ppstmt);
|
|
ASSERT(pexpr);
|
|
|
|
if (ppstmt)
|
|
{
|
|
PDELAYSTMT this;
|
|
|
|
res = Ast_New(&this, AT_DELAY_STMT, sizeof(*this), iLine);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
this->pexprSecs = pexpr;
|
|
|
|
res = RES_OK;
|
|
}
|
|
|
|
*ppstmt = (PSTMT)this;
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
DBG_EXIT_RES(DelayStmt_New, res);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Creates a HaltStmt object.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_OUTOFMEMORY
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC HaltStmt_New(
|
|
PSTMT * ppstmt,
|
|
DWORD iLine)
|
|
{
|
|
RES res;
|
|
|
|
DBG_ENTER(HaltStmt_New);
|
|
|
|
ASSERT(ppstmt);
|
|
|
|
if (ppstmt)
|
|
{
|
|
PHALTSTMT this;
|
|
|
|
res = Ast_New(&this, AT_HALT_STMT, sizeof(*this), iLine);
|
|
|
|
*ppstmt = (PSTMT)this;
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
DBG_EXIT_RES(HaltStmt_New, res);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Creates an EnterStmt object.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_OUTOFMEMORY
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC EnterStmt_New(
|
|
PSTMT * ppstmt,
|
|
PSYMTAB pst,
|
|
DWORD iLine)
|
|
{
|
|
RES res;
|
|
|
|
DBG_ENTER(EnterStmt_New);
|
|
|
|
ASSERT(ppstmt);
|
|
|
|
if (ppstmt)
|
|
{
|
|
PENTERSTMT this;
|
|
|
|
res = Ast_New(&this, AT_ENTER_STMT, sizeof(*this), iLine);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
this->pst = pst;
|
|
}
|
|
|
|
*ppstmt = (PSTMT)this;
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
DBG_EXIT_RES(EnterStmt_New, res);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Creates an LeaveStmt object.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_OUTOFMEMORY
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC LeaveStmt_New(
|
|
PSTMT * ppstmt,
|
|
DWORD iLine)
|
|
{
|
|
RES res;
|
|
|
|
DBG_ENTER(LeaveStmt_New);
|
|
|
|
ASSERT(ppstmt);
|
|
|
|
if (ppstmt)
|
|
{
|
|
PLEAVESTMT this;
|
|
|
|
res = Ast_New(&this, AT_LEAVE_STMT, sizeof(*this), iLine);
|
|
|
|
*ppstmt = (PSTMT)this;
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
DBG_EXIT_RES(LeaveStmt_New, res);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Creates an AssignStmt object.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_OUTOFMEMORY
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC AssignStmt_New(
|
|
PSTMT * ppstmt,
|
|
LPCSTR pszIdent,
|
|
PEXPR pexpr,
|
|
DWORD iLine)
|
|
{
|
|
RES res;
|
|
|
|
DBG_ENTER(AssignStmt_New);
|
|
|
|
ASSERT(ppstmt);
|
|
ASSERT(pszIdent);
|
|
ASSERT(pexpr);
|
|
|
|
if (ppstmt)
|
|
{
|
|
PASSIGNSTMT this;
|
|
|
|
res = Ast_New(&this, AT_ASSIGN_STMT, sizeof(*this), iLine);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
res = RES_OK; // assume success
|
|
|
|
if (!GSetString(&this->pszIdent, pszIdent))
|
|
res = RES_E_OUTOFMEMORY;
|
|
else
|
|
this->pexpr = pexpr;
|
|
|
|
if (RFAILED(res))
|
|
{
|
|
Ast_Delete((PAST)this);
|
|
this = NULL;
|
|
}
|
|
}
|
|
|
|
*ppstmt = (PSTMT)this;
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
DBG_EXIT_RES(AssignStmt_New, res);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Creates a LabelStmt object.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_OUTOFMEMORY
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC LabelStmt_New(
|
|
PSTMT * ppstmt,
|
|
LPCSTR psz,
|
|
DWORD iLine)
|
|
{
|
|
RES res;
|
|
|
|
DBG_ENTER(LabelStmt_New);
|
|
|
|
ASSERT(ppstmt);
|
|
ASSERT(psz);
|
|
|
|
if (ppstmt)
|
|
{
|
|
PLABELSTMT this;
|
|
|
|
res = Ast_New(&this, AT_LABEL_STMT, sizeof(*this), iLine);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
res = RES_OK; // assume success
|
|
|
|
if (!GSetString(&this->psz, psz))
|
|
{
|
|
res = RES_E_OUTOFMEMORY;
|
|
Ast_Delete((PAST)this);
|
|
this = NULL;
|
|
}
|
|
}
|
|
|
|
*ppstmt = (PSTMT)this;
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
DBG_EXIT_RES(LabelStmt_New, res);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Creates a GotoStmt object.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_OUTOFMEMORY
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC GotoStmt_New(
|
|
PSTMT * ppstmt,
|
|
LPCSTR psz,
|
|
DWORD iLine)
|
|
{
|
|
RES res;
|
|
|
|
DBG_ENTER(GotoStmt_New);
|
|
|
|
ASSERT(ppstmt);
|
|
ASSERT(psz);
|
|
|
|
if (ppstmt)
|
|
{
|
|
PGOTOSTMT this;
|
|
|
|
res = Ast_New(&this, AT_GOTO_STMT, sizeof(*this), iLine);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
res = RES_OK; // assume success
|
|
|
|
if (!GSetString(&this->psz, psz))
|
|
{
|
|
res = RES_E_OUTOFMEMORY;
|
|
Ast_Delete((PAST)this);
|
|
this = NULL;
|
|
}
|
|
}
|
|
|
|
*ppstmt = (PSTMT)this;
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
DBG_EXIT_RES(GotoStmt_New, res);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Creates a WhileStmt object.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_OUTOFMEMORY
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC WhileStmt_New(
|
|
PSTMT * ppstmt,
|
|
PEXPR pexpr,
|
|
HPA hpa,
|
|
LPCSTR pszTopLabel,
|
|
LPCSTR pszEndLabel,
|
|
DWORD iLine)
|
|
{
|
|
RES res;
|
|
|
|
ASSERT(ppstmt);
|
|
ASSERT(hpa);
|
|
ASSERT(pexpr);
|
|
ASSERT(pszTopLabel);
|
|
ASSERT(pszEndLabel);
|
|
|
|
if (ppstmt)
|
|
{
|
|
PWHILESTMT this;
|
|
|
|
res = Ast_New(&this, AT_WHILE_STMT, sizeof(*this), iLine);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
res = RES_OK; // assume success
|
|
|
|
this->pexpr = pexpr;
|
|
this->hpaStmts = hpa;
|
|
lstrcpyn(this->szTopLabel, pszTopLabel, sizeof(this->szTopLabel));
|
|
lstrcpyn(this->szEndLabel, pszEndLabel, sizeof(this->szEndLabel));
|
|
}
|
|
|
|
*ppstmt = (PSTMT)this;
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Creates an IfStmt object.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_OUTOFMEMORY
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC IfStmt_New(
|
|
PSTMT * ppstmt,
|
|
PEXPR pexpr,
|
|
HPA hpa,
|
|
LPCSTR pszElseLabel,
|
|
LPCSTR pszEndLabel,
|
|
DWORD iLine)
|
|
{
|
|
RES res;
|
|
|
|
ASSERT(ppstmt);
|
|
ASSERT(hpa);
|
|
ASSERT(pexpr);
|
|
ASSERT(pszElseLabel);
|
|
ASSERT(pszEndLabel);
|
|
|
|
if (ppstmt)
|
|
{
|
|
PIFSTMT this;
|
|
|
|
res = Ast_New(&this, AT_IF_STMT, sizeof(*this), iLine);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
res = RES_OK; // assume success
|
|
|
|
this->pexpr = pexpr;
|
|
this->hpaStmts = hpa;
|
|
lstrcpyn(this->szElseLabel, pszElseLabel, sizeof(this->szElseLabel));
|
|
lstrcpyn(this->szEndLabel, pszEndLabel, sizeof(this->szEndLabel));
|
|
}
|
|
|
|
*ppstmt = (PSTMT)this;
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Creates a SetStmt object.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_OUTOFMEMORY
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PRIVATE SetStmt_New(
|
|
PVOID * ppv,
|
|
SETTYPE settype,
|
|
DWORD cbSize,
|
|
DWORD iLine)
|
|
{
|
|
RES res;
|
|
|
|
DBG_ENTER(SetStmt_New);
|
|
|
|
ASSERT(ppv);
|
|
ASSERT(sizeof(SETSTMT) <= cbSize);
|
|
|
|
if (ppv)
|
|
{
|
|
PSETSTMT this;
|
|
|
|
res = Ast_New(&this, AT_SET_STMT, cbSize, iLine);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
SetStmt_SetType(this, settype);
|
|
|
|
res = RES_OK;
|
|
}
|
|
|
|
*ppv = this;
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
DBG_EXIT_RES(SetStmt_New, res);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Creates a SetIPStmt object.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_OUTOFMEMORY
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC SetIPStmt_New(
|
|
PSTMT * ppstmt,
|
|
PEXPR pexpr,
|
|
DWORD iLine)
|
|
{
|
|
RES res;
|
|
|
|
DBG_ENTER(SetIPStmt_New);
|
|
|
|
ASSERT(ppstmt);
|
|
ASSERT(pexpr);
|
|
|
|
if (ppstmt)
|
|
{
|
|
PSETIPSTMT this;
|
|
|
|
res = SetStmt_New(&this, ST_IPADDR, sizeof(*this), iLine);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
res = RES_OK; // assume success
|
|
|
|
this->pexpr = pexpr;
|
|
}
|
|
|
|
*ppstmt = (PSTMT)this;
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
DBG_EXIT_RES(SetIPStmt_New, res);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Creates a SetPortStmt object.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_OUTOFMEMORY
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC SetPortStmt_New(
|
|
PSTMT * ppstmt,
|
|
PPORTSTATE pstate,
|
|
DWORD iLine)
|
|
{
|
|
RES res;
|
|
|
|
DBG_ENTER(SetPortStmt_New);
|
|
|
|
ASSERT(ppstmt);
|
|
ASSERT(pstate);
|
|
|
|
if (ppstmt && pstate)
|
|
{
|
|
PSETPORTSTMT this;
|
|
|
|
res = SetStmt_New(&this, ST_PORT, sizeof(*this), iLine);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
DWORD dwFlags = pstate->dwFlags;
|
|
|
|
res = RES_OK; // assume success
|
|
|
|
this->portstate.dwFlags = dwFlags;
|
|
|
|
if (IsFlagSet(dwFlags, SPF_DATABITS))
|
|
this->portstate.nDatabits = pstate->nDatabits;
|
|
|
|
if (IsFlagSet(dwFlags, SPF_STOPBITS))
|
|
this->portstate.nStopbits = pstate->nStopbits;
|
|
|
|
if (IsFlagSet(dwFlags, SPF_PARITY))
|
|
this->portstate.nParity = pstate->nParity;
|
|
}
|
|
|
|
*ppstmt = (PSTMT)this;
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
DBG_EXIT_RES(SetPortStmt_New, res);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Creates a SetScreenStmt object.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_OUTOFMEMORY
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC SetScreenStmt_New(
|
|
PSTMT * ppstmt,
|
|
PSCREENSET pstate,
|
|
DWORD iLine)
|
|
{
|
|
RES res;
|
|
|
|
DBG_ENTER(SetScreenStmt_New);
|
|
|
|
ASSERT(ppstmt);
|
|
ASSERT(pstate);
|
|
|
|
if (ppstmt && pstate)
|
|
{
|
|
PSETSCREENSTMT this;
|
|
|
|
res = SetStmt_New(&this, ST_SCREEN, sizeof(*this), iLine);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
DWORD dwFlags = pstate->dwFlags;
|
|
|
|
res = RES_OK; // assume success
|
|
|
|
this->screenset.dwFlags = dwFlags;
|
|
|
|
if (IsFlagSet(dwFlags, SPF_KEYBRD))
|
|
this->screenset.fKBOn = pstate->fKBOn;
|
|
}
|
|
|
|
*ppstmt = (PSTMT)this;
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
DBG_EXIT_RES(SetScreenStmt_New, res);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
//
|
|
// Decl
|
|
//
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Callback for PADestroyEx.
|
|
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
void CALLBACK Decl_DeletePAPtr(
|
|
LPVOID pv,
|
|
LPARAM lparam)
|
|
{
|
|
Decl_Delete(pv);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Destroys a Decl.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC Decl_Delete(
|
|
PDECL this)
|
|
{
|
|
RES res;
|
|
|
|
DBG_ENTER(Decl_Delete);
|
|
|
|
if (this)
|
|
{
|
|
res = RES_OK;
|
|
|
|
switch (this->ast.asttype)
|
|
{
|
|
case AT_MODULE_DECL: {
|
|
PMODULEDECL pmd = (PMODULEDECL)this;
|
|
|
|
if (pmd->hpaProcs)
|
|
PADestroyEx(pmd->hpaProcs, Decl_DeletePAPtr, 0);
|
|
|
|
if (pmd->pst)
|
|
Symtab_Destroy(pmd->pst);
|
|
}
|
|
break;
|
|
|
|
case AT_PROC_DECL: {
|
|
PPROCDECL ppd = (PPROCDECL)this;
|
|
|
|
if (ppd->hpaStmts)
|
|
PADestroyEx(ppd->hpaStmts, Stmt_DeletePAPtr, 0);
|
|
|
|
if (ppd->pst)
|
|
Symtab_Destroy(ppd->pst);
|
|
|
|
if (ppd->pszIdent)
|
|
GSetString(&ppd->pszIdent, NULL); // free
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ASSERT(0);
|
|
res = RES_E_INVALIDPARAM;
|
|
break;
|
|
}
|
|
|
|
if (RSUCCEEDED(res))
|
|
Ast_Delete((PAST)this);
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
DBG_EXIT_RES(Decl_Delete, res);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
//
|
|
// ProcDecl
|
|
//
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Creates a ProcDecl object.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_OUTOFMEMORY
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC ProcDecl_New(
|
|
PDECL * ppdecl,
|
|
LPCSTR pszIdent,
|
|
HPA hpa,
|
|
PSYMTAB pst,
|
|
DWORD iLine)
|
|
{
|
|
RES res;
|
|
|
|
DBG_ENTER(ProcDecl_New);
|
|
|
|
ASSERT(ppdecl);
|
|
ASSERT(hpa);
|
|
ASSERT(pst);
|
|
|
|
if (ppdecl)
|
|
{
|
|
PPROCDECL this;
|
|
|
|
res = Ast_New(&this, AT_PROC_DECL, sizeof(*this), iLine);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
res = RES_OK; // assume success
|
|
|
|
if (!GSetString(&this->pszIdent, pszIdent))
|
|
res = RES_E_OUTOFMEMORY;
|
|
|
|
else
|
|
{
|
|
this->hpaStmts = hpa;
|
|
this->pst = pst;
|
|
}
|
|
|
|
if (RFAILED(res))
|
|
{
|
|
Decl_Delete((PDECL)this);
|
|
this = NULL;
|
|
}
|
|
}
|
|
|
|
*ppdecl = (PDECL)this;
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
DBG_EXIT_RES(ProcDecl_New, res);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
//
|
|
// ModuleDecl
|
|
//
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Creates a ModuleDecl object.
|
|
|
|
Returns: RES_OK
|
|
|
|
RES_E_OUTOFMEMORY
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC ModuleDecl_New(
|
|
PDECL * ppdecl,
|
|
HPA hpa,
|
|
PSYMTAB pst,
|
|
DWORD iLine)
|
|
{
|
|
RES res;
|
|
|
|
DBG_ENTER(ModuleDecl_New);
|
|
|
|
ASSERT(ppdecl);
|
|
ASSERT(hpa);
|
|
ASSERT(pst);
|
|
|
|
if (ppdecl)
|
|
{
|
|
PMODULEDECL this;
|
|
|
|
res = Ast_New(&this, AT_MODULE_DECL, sizeof(*this), iLine);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
res = RES_OK; // assume success
|
|
|
|
this->hpaProcs = NULL;
|
|
if ( !PAClone(&this->hpaProcs, hpa) )
|
|
res = RES_E_OUTOFMEMORY;
|
|
|
|
else
|
|
{
|
|
this->pst = pst;
|
|
}
|
|
|
|
if (RFAILED(res))
|
|
{
|
|
Decl_Delete((PDECL)this);
|
|
this = NULL;
|
|
}
|
|
}
|
|
|
|
*ppdecl = (PDECL)this;
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
DBG_EXIT_RES(ModuleDecl_New, res);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
//
|
|
// AST Exec block
|
|
//
|
|
|
|
#define SZ_SUCCESS "$SUCCESS"
|
|
#define SZ_FAILURE "$FAILURE"
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Initialize the AST exec block.
|
|
|
|
Returns: RES_OK
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC Astexec_Init(
|
|
PASTEXEC this,
|
|
HANDLE hport,
|
|
PSESS_CONFIGURATION_INFO psci,
|
|
HSA hsaStxerr)
|
|
{
|
|
RES res;
|
|
|
|
ASSERT(this);
|
|
ASSERT(psci);
|
|
ASSERT(hsaStxerr);
|
|
|
|
// For this first version, we only support one module and one
|
|
// main procedure, so set the starting point on the first
|
|
// statement in that procedure.
|
|
if (this)
|
|
{
|
|
ZeroInit(this, ASTEXEC);
|
|
|
|
this->hport = hport;
|
|
this->psci = psci;
|
|
// Don't free hsaStxerr -- it belongs to the caller
|
|
this->hsaStxerr = hsaStxerr;
|
|
|
|
if ( !PACreate(&this->hpaPcode, 8) )
|
|
res = RES_E_OUTOFMEMORY;
|
|
else
|
|
{
|
|
res = Symtab_Create(&this->pstSystem, NULL);
|
|
if (RSUCCEEDED(res))
|
|
{
|
|
// Add the system variables
|
|
PSTE pste;
|
|
struct
|
|
{
|
|
LPCSTR pszIdent;
|
|
DATATYPE dt;
|
|
EVALRES er;
|
|
} s_rgvars[] =
|
|
{
|
|
{ "$USERID", DATA_STRING, psci->szUserName },
|
|
{ "$PASSWORD", DATA_STRING, psci->szPassword },
|
|
{ SZ_SUCCESS, DATA_BOOL, (LPSTR)TRUE },
|
|
{ SZ_FAILURE, DATA_BOOL, (LPSTR)FALSE },
|
|
};
|
|
int i;
|
|
|
|
for (i = 0; i < ARRAY_ELEMENTS(s_rgvars); i++)
|
|
{
|
|
res = STE_Create(&pste, s_rgvars[i].pszIdent, s_rgvars[i].dt);
|
|
if (RFAILED(res))
|
|
break;
|
|
|
|
pste->er.dw = s_rgvars[i].er.dw;
|
|
|
|
res = Symtab_InsertEntry(this->pstSystem, pste);
|
|
if (RFAILED(res))
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// Did something fail above?
|
|
if (RFAILED(res))
|
|
{
|
|
// Yes; clean up
|
|
Astexec_Destroy(this);
|
|
}
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Destroys the AST exec block.
|
|
|
|
Returns: RES_OK
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC Astexec_Destroy(
|
|
PASTEXEC this)
|
|
{
|
|
RES res;
|
|
|
|
if (this)
|
|
{
|
|
if (this->hpaPcode)
|
|
{
|
|
PADestroy(this->hpaPcode);
|
|
this->hpaPcode = NULL;
|
|
}
|
|
|
|
if (this->pstSystem)
|
|
{
|
|
Symtab_Destroy(this->pstSystem);
|
|
this->pstSystem = NULL;
|
|
}
|
|
|
|
// ('this' was not allocated. Do not free it.)
|
|
// (hsaStxerr is not owned by this class. Do not free it.)
|
|
|
|
res = RES_OK;
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Sets the success/failure code
|
|
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
void PUBLIC Astexec_SetError(
|
|
PASTEXEC this,
|
|
BOOL bSuccess, // TRUE: success
|
|
BOOL bFailure)
|
|
{
|
|
PSTE pste;
|
|
|
|
ASSERT(this);
|
|
|
|
if (RES_OK == Symtab_FindEntry(this->pstSystem, SZ_SUCCESS, STFF_DEFAULT, &pste, NULL))
|
|
{
|
|
// Set the code for success
|
|
pste->er.bVal = bSuccess;
|
|
|
|
if (RES_OK == Symtab_FindEntry(this->pstSystem, SZ_FAILURE, STFF_DEFAULT, &pste, NULL))
|
|
{
|
|
// Set the code for failure
|
|
pste->er.bVal = bFailure;
|
|
}
|
|
else
|
|
ASSERT(0);
|
|
}
|
|
else
|
|
ASSERT(0);
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Adds the statement to the executable list.
|
|
|
|
Returns: RES_OK
|
|
RES_E_OUTOFMEMORY
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC Astexec_Add(
|
|
PASTEXEC this,
|
|
PSTMT pstmt)
|
|
{
|
|
RES res;
|
|
|
|
ASSERT(this);
|
|
ASSERT(pstmt);
|
|
|
|
if (PAInsertPtr(this->hpaPcode, PA_APPEND, pstmt))
|
|
res = RES_OK;
|
|
else
|
|
res = RES_E_OUTOFMEMORY;
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Inserts a label into the executable list by recording
|
|
the current ipaCur into the label entry in the
|
|
symbol table.
|
|
|
|
Returns: RES_OK
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC Astexec_InsertLabel(
|
|
PASTEXEC this,
|
|
LPCSTR pszIdent,
|
|
PSYMTAB pst)
|
|
{
|
|
RES res;
|
|
DWORD ipa;
|
|
PSTE pste;
|
|
|
|
ASSERT(this);
|
|
ASSERT(pszIdent);
|
|
ASSERT(pst);
|
|
|
|
ipa = PAGetCount(this->hpaPcode);
|
|
if (RES_OK == Symtab_FindEntry(pst, pszIdent, STFF_DEFAULT, &pste, NULL))
|
|
{
|
|
// Set the current code location in the symbol table
|
|
pste->er.dw = ipa;
|
|
res = RES_OK;
|
|
}
|
|
else
|
|
{
|
|
ASSERT(0);
|
|
res = RES_E_FAIL;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Jumps to the given label.
|
|
|
|
Returns: RES_OK
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC Astexec_JumpToLabel(
|
|
PASTEXEC this,
|
|
LPCSTR pszIdent)
|
|
{
|
|
RES res;
|
|
PSTE pste;
|
|
|
|
ASSERT(pszIdent);
|
|
ASSERT(this);
|
|
ASSERT(this->pstCur);
|
|
|
|
if (RES_OK == Symtab_FindEntry(this->pstCur, pszIdent, STFF_DEFAULT, &pste, NULL))
|
|
{
|
|
EVALRES er;
|
|
|
|
STE_GetValue(pste, &er);
|
|
|
|
// Set instruction pointer
|
|
Astexec_SetIP(this, (DWORD) er.dw);
|
|
res = RES_OK;
|
|
}
|
|
else
|
|
{
|
|
// The label should have been in the symbol table!
|
|
ASSERT(0);
|
|
res = RES_E_FAIL;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Sends psz to the port (via hwnd)
|
|
|
|
Returns: --
|
|
Cond: --
|
|
*/
|
|
void PUBLIC Astexec_SendString(
|
|
PASTEXEC this,
|
|
LPCSTR pszSend,
|
|
BOOL bRaw) // TRUE: send unformatted
|
|
{
|
|
// Send string
|
|
LPCSTR psz;
|
|
char ch;
|
|
HWND hwnd = this->hwnd;
|
|
|
|
// Send unformatted?
|
|
if (bRaw)
|
|
{
|
|
// Yes
|
|
for (psz = pszSend; *psz; )
|
|
{
|
|
ch = *psz;
|
|
|
|
psz++;
|
|
|
|
SendByte(hwnd, ch);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// No
|
|
DWORD dwFlags = 0;
|
|
|
|
for (psz = pszSend; *psz; )
|
|
{
|
|
psz = MyNextChar(psz, &ch, &dwFlags);
|
|
|
|
SendByte(hwnd, ch);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Destroy the find format handle
|
|
|
|
Returns: RES_OK
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC Astexec_DestroyFindFormat(
|
|
PASTEXEC this)
|
|
{
|
|
// Reset the pending statement so we can handle multiple
|
|
// expressions that can pend in a single evaluation.
|
|
Astexec_SetPending(this, NULL);
|
|
|
|
DestroyFindFormat(this->hFindFmt);
|
|
this->hFindFmt = NULL;
|
|
|
|
return RES_OK;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Make another pass at finding a string.
|
|
|
|
Returns: RES_OK (if string was found)
|
|
RES_FALSE (if the string was not found yet)
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC Astexec_FindFormat(
|
|
PASTEXEC this,
|
|
LPDWORD piFound)
|
|
{
|
|
RES res;
|
|
|
|
ASSERT(piFound);
|
|
|
|
while (TRUE)
|
|
{
|
|
// Did we get the IP address?
|
|
res = FindFormat(this->hwnd, this->hFindFmt, piFound);
|
|
if (RES_OK == res)
|
|
{
|
|
// Yes
|
|
this->nIter--;
|
|
ASSERT(0 <= this->nIter);
|
|
|
|
// Is this the right one?
|
|
if (0 >= this->nIter)
|
|
{
|
|
// Yes; reset the pending statement so we
|
|
// can handle multiple pending expressions
|
|
// in a single evaluation.
|
|
Astexec_DestroyFindFormat(this);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// No; return read-pending RES_FALSE
|
|
if (RES_E_MOREDATA == res)
|
|
{
|
|
TRACE_MSG(TF_GENERAL, "Buffer to FindFormat is too small");
|
|
res = RES_OK; // don't blow up
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
ASSERT(RSUCCEEDED(res));
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Sets the IP address.
|
|
|
|
Returns: RES_OK
|
|
RES_E_FAIL (if IP address cannot be set)
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC Astexec_SetIPAddr(
|
|
PASTEXEC this,
|
|
LPCSTR psz)
|
|
{
|
|
DWORD dwRet;
|
|
|
|
ASSERT(this);
|
|
ASSERT(psz);
|
|
|
|
TRACE_MSG(TF_GENERAL, "Setting IP address to {%s}", psz);
|
|
|
|
#ifndef WINNT_RAS
|
|
//
|
|
// On NT, the IP address is set by calling RxSetIPAddress,
|
|
// which writes a new value to the phonebook if the connection uses SLIP.
|
|
//
|
|
|
|
dwRet = TerminalSetIP(this->hwnd, psz);
|
|
|
|
#else // !WINNT_RAS
|
|
|
|
dwRet = RxSetIPAddress(((SCRIPTDATA*)this->hwnd)->hscript, psz);
|
|
|
|
#endif // !WINNT_RAS
|
|
return ERROR_SUCCESS == dwRet ? RES_OK : RES_E_FAIL;
|
|
}
|
|
|
|
|
|
#define Astexec_Validate(this) ((this)->hpaPcode && (this)->psci)
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Returns the source line number of the current
|
|
command that is executing.
|
|
|
|
Returns: see above
|
|
Cond: --
|
|
*/
|
|
DWORD PUBLIC Astexec_GetCurLine(
|
|
PASTEXEC this)
|
|
{
|
|
DWORD iLine;
|
|
|
|
if (Astexec_Validate(this) &&
|
|
(this->ipaCur < PAGetCount(this->hpaPcode)))
|
|
{
|
|
PSTMT pstmt = PAFastGetPtr(this->hpaPcode, this->ipaCur);
|
|
iLine = Ast_GetLine(pstmt);
|
|
}
|
|
else
|
|
iLine = 0;
|
|
|
|
return iLine;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Execute a statement and process the results.
|
|
|
|
Returns: RES_OK
|
|
other error values
|
|
|
|
Cond: --
|
|
*/
|
|
RES PRIVATE Astexec_ProcessStmt(
|
|
PASTEXEC this,
|
|
PSTMT pstmt)
|
|
{
|
|
RES res;
|
|
|
|
ASSERT(this);
|
|
ASSERT(pstmt);
|
|
|
|
// (Re-)Execute the (possibly pending) statement
|
|
res = Stmt_Exec(pstmt, this);
|
|
|
|
// Set the pending statement based on the return value
|
|
if (RES_OK == res)
|
|
Astexec_SetPending(this, NULL);
|
|
else if (RES_FALSE == res)
|
|
{
|
|
// (Re-set the current pending statement since
|
|
// it could have been reset in Stmt_Exec. For
|
|
// example, the evaluation of an expression could
|
|
// have continued on to the next sub-expression
|
|
// that caused another pending read.)
|
|
|
|
Astexec_SetPending(this, pstmt);
|
|
res = RES_OK;
|
|
}
|
|
else if (RFAILED(res))
|
|
{
|
|
Stxerr_ShowErrors(this->hsaStxerr, this->hwnd);
|
|
|
|
// Halt script
|
|
SetFlag(this->dwFlags, AEF_HALT);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: Executes the next command in the AST.
|
|
|
|
Returns: RES_OK
|
|
RES_FALSE (if at end of script)
|
|
RES_HALT (if at end of script)
|
|
|
|
RES_E_FAIL (invalid command -- should never happen)
|
|
RES_E_INVALIDPARAM
|
|
|
|
Cond: --
|
|
*/
|
|
RES PUBLIC Astexec_Next(
|
|
PASTEXEC this)
|
|
{
|
|
RES res;
|
|
|
|
DBG_ENTER(Astexec_Next);
|
|
|
|
if (this)
|
|
{
|
|
if (!Astexec_Validate(this))
|
|
{
|
|
// No script
|
|
res = RES_E_FAIL;
|
|
}
|
|
else if (Astexec_IsDone(this) || Astexec_IsHalted(this))
|
|
{
|
|
res = RES_HALT;
|
|
}
|
|
else if (Astexec_IsReadPending(this))
|
|
{
|
|
PSTMT pstmt = Astexec_GetPending(this);
|
|
|
|
// ("Read pending" and "Paused" are mutually exclusive)
|
|
ASSERT( !Astexec_IsPaused(this) );
|
|
|
|
res = Astexec_ProcessStmt(this, pstmt);
|
|
}
|
|
else if (Astexec_IsPaused(this))
|
|
{
|
|
// ("Read pending" and "Paused" are mutually exclusive)
|
|
ASSERT( !Astexec_IsReadPending(this) );
|
|
|
|
// Do nothing while we're paused
|
|
res = RES_OK;
|
|
}
|
|
else if (this->ipaCur < PAGetCount(this->hpaPcode))
|
|
{
|
|
PSTMT pstmt = PAFastGetPtr(this->hpaPcode, this->ipaCur++);
|
|
|
|
res = Astexec_ProcessStmt(this, pstmt);
|
|
}
|
|
else
|
|
{
|
|
// We reach here if there is an error in the script.
|
|
TRACE_MSG(TF_ASTEXEC, "Exec: (reached end of script)");
|
|
|
|
SetFlag(this->dwFlags, AEF_DONE);
|
|
res = RES_HALT;
|
|
}
|
|
}
|
|
else
|
|
res = RES_E_INVALIDPARAM;
|
|
|
|
DBG_EXIT_RES(Astexec_Next, res);
|
|
|
|
return res;
|
|
}
|