Source code of Windows XP (NT5)
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

//
// 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;
}