Leaked source code of windows server 2003
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
52 KiB

  1. //
  2. // Copyright (c) Microsoft Corporation 1995
  3. //
  4. // ast.c
  5. //
  6. // This file contains the abstract syntax tree functions.
  7. //
  8. // History:
  9. // 05-20-95 ScottH Created
  10. //
  11. #include "proj.h"
  12. #include "rcids.h"
  13. #define RetInt(ppv, x) (*((LPINT)*(ppv)) = (x))
  14. #define RetStr(ppv, x) (*((LPSTR)*(ppv)) = (x))
  15. #define RetBool(ppv, x) (*((LPBOOL)*(ppv)) = (x))
  16. //
  17. // Wait case functions
  18. //
  19. #ifdef DEBUG
  20. /*----------------------------------------------------------
  21. Purpose: Dump a waitcase structure
  22. Returns: --
  23. Cond: --
  24. */
  25. void PRIVATE Waitcase_Dump(
  26. PWAITCASE this)
  27. {
  28. Ast_Dump((PAST)this->pexpr);
  29. if (this->pszIdent)
  30. {
  31. TRACE_MSG(TF_ALWAYS, " then %s", this->pszIdent);
  32. }
  33. }
  34. #endif
  35. /*----------------------------------------------------------
  36. Purpose: Create a wait-case list.
  37. Returns: RES_OK
  38. RES_E_OUTOFMEMORY
  39. Cond: --
  40. */
  41. RES PUBLIC Waitcase_Create(
  42. PHSA phsa)
  43. {
  44. RES res = RES_OK;
  45. if ( !SACreate(phsa, sizeof(WAITCASE), 8) )
  46. res = RES_E_OUTOFMEMORY;
  47. return res;
  48. }
  49. /*----------------------------------------------------------
  50. Purpose: Add a case to the given wait-case list.
  51. Returns: RES_OK
  52. Cond: --
  53. */
  54. RES PUBLIC Waitcase_Add(
  55. HSA hsa,
  56. PEXPR pexpr,
  57. LPCSTR pszIdent, // This may be NULL
  58. DWORD dwFlags)
  59. {
  60. RES res = RES_OK; // assume success
  61. WAITCASE wc;
  62. ASSERT(hsa);
  63. ASSERT(pexpr);
  64. wc.pexpr = pexpr;
  65. wc.dwFlags = dwFlags;
  66. wc.pszIdent = NULL;
  67. // Copy pszIdent since the parameter is freed by the caller.
  68. if ( pszIdent && !GSetString(&wc.pszIdent, pszIdent) )
  69. res = RES_E_OUTOFMEMORY;
  70. else if ( !SAInsertItem(hsa, SA_APPEND, &wc) )
  71. res = RES_E_OUTOFMEMORY;
  72. return res;
  73. }
  74. /*----------------------------------------------------------
  75. Purpose: Free the contents of the given pointer.
  76. Returns: --
  77. Cond: Don't free the pointer itself!
  78. */
  79. void CALLBACK Waitcase_FreeSA(
  80. PVOID pv,
  81. LPARAM lparam)
  82. {
  83. PWAITCASE pwc = (PWAITCASE)pv;
  84. if (pwc->pexpr)
  85. Expr_Delete(pwc->pexpr);
  86. if (pwc->pszIdent)
  87. GSetString(&pwc->pszIdent, NULL); // free
  88. }
  89. /*----------------------------------------------------------
  90. Purpose: Destroy the wait case list.
  91. Returns: RES_OK
  92. Cond: --
  93. */
  94. RES PUBLIC Waitcase_Destroy(
  95. HSA hsa)
  96. {
  97. ASSERT(hsa);
  98. SADestroyEx(hsa, Waitcase_FreeSA, 0);
  99. return RES_OK;
  100. }
  101. //
  102. // Base level AST functions
  103. //
  104. #ifdef DEBUG
  105. /*----------------------------------------------------------
  106. Purpose: Dump the AST
  107. Returns: --
  108. Cond: --
  109. */
  110. void PUBLIC Ast_Dump(
  111. PAST this)
  112. {
  113. ASSERT(this);
  114. if (IsFlagSet(g_dwDumpFlags, DF_AST))
  115. {
  116. switch (this->asttype)
  117. {
  118. case AT_BASE:
  119. TRACE_MSG(TF_ALWAYS, "Unknown AST");
  120. break;
  121. case AT_MODULE_DECL: {
  122. PMODULEDECL pmd = (PMODULEDECL)this;
  123. DWORD i;
  124. DWORD cprocs = PAGetCount(pmd->hpaProcs);
  125. TRACE_MSG(TF_ALWAYS, "module");
  126. for (i = 0; i < cprocs; i++)
  127. Ast_Dump(PAFastGetPtr(pmd->hpaProcs, i));
  128. }
  129. break;
  130. case AT_PROC_DECL: {
  131. PPROCDECL ppd = (PPROCDECL)this;
  132. DWORD i;
  133. DWORD cstmts = PAGetCount(ppd->hpaStmts);
  134. TRACE_MSG(TF_ALWAYS, "proc %s", ProcDecl_GetIdent(ppd));
  135. for (i = 0; i < cstmts; i++)
  136. Ast_Dump(PAFastGetPtr(ppd->hpaStmts, i));
  137. TRACE_MSG(TF_ALWAYS, "endproc");
  138. }
  139. break;
  140. case AT_ENTER_STMT:
  141. TRACE_MSG(TF_ALWAYS, "enter");
  142. break;
  143. case AT_LEAVE_STMT:
  144. TRACE_MSG(TF_ALWAYS, "leave");
  145. break;
  146. case AT_HALT_STMT:
  147. TRACE_MSG(TF_ALWAYS, "halt");
  148. break;
  149. case AT_ASSIGN_STMT:
  150. TRACE_MSG(TF_ALWAYS, "%s = ", AssignStmt_GetIdent(this));
  151. Ast_Dump((PAST)AssignStmt_GetExpr(this));
  152. break;
  153. case AT_LABEL_STMT:
  154. TRACE_MSG(TF_ALWAYS, "%s:", LabelStmt_GetIdent(this));
  155. break;
  156. case AT_GOTO_STMT:
  157. TRACE_MSG(TF_ALWAYS, "goto %s", GotoStmt_GetIdent(this));
  158. break;
  159. case AT_WHILE_STMT:
  160. TRACE_MSG(TF_ALWAYS, "while ");
  161. TRACE_MSG(TF_ALWAYS, " do ");
  162. TRACE_MSG(TF_ALWAYS, "endwhile ");
  163. break;
  164. case AT_IF_STMT:
  165. TRACE_MSG(TF_ALWAYS, "if ");
  166. TRACE_MSG(TF_ALWAYS, " then ");
  167. TRACE_MSG(TF_ALWAYS, "endif ");
  168. break;
  169. case AT_DELAY_STMT:
  170. TRACE_MSG(TF_ALWAYS, "delay");
  171. Ast_Dump((PAST)DelayStmt_GetExpr(this));
  172. break;
  173. case AT_WAITFOR_STMT: {
  174. PWAITFORSTMT pws = (PWAITFORSTMT)this;
  175. DWORD ccase = SAGetCount(pws->hsa);
  176. DWORD i;
  177. TRACE_MSG(TF_ALWAYS, "waitfor");
  178. for (i = 0; i < ccase; i++)
  179. {
  180. PVOID pv;
  181. SAGetItemPtr(pws->hsa, i, &pv);
  182. Waitcase_Dump(pv);
  183. }
  184. if (WaitforStmt_GetUntilExpr(this))
  185. {
  186. TRACE_MSG(TF_ALWAYS, "until");
  187. Ast_Dump((PAST)WaitforStmt_GetUntilExpr(this));
  188. }
  189. }
  190. break;
  191. case AT_TRANSMIT_STMT:
  192. TRACE_MSG(TF_ALWAYS, "transmit");
  193. Ast_Dump((PAST)TransmitStmt_GetExpr(this));
  194. break;
  195. case AT_SET_STMT:
  196. switch (SetStmt_GetType(this))
  197. {
  198. case ST_IPADDR:
  199. TRACE_MSG(TF_ALWAYS, "set ipaddr getip");
  200. Ast_Dump((PAST)SetIPStmt_GetExpr(this));
  201. break;
  202. case ST_PORT:
  203. if (IsFlagSet(SetPortStmt_GetFlags(this), SPF_DATABITS))
  204. TRACE_MSG(TF_ALWAYS, "set port databits %u", SetPortStmt_GetDatabits(this));
  205. if (IsFlagSet(SetPortStmt_GetFlags(this), SPF_STOPBITS))
  206. TRACE_MSG(TF_ALWAYS, "set port stopbits %u", SetPortStmt_GetStopbits(this));
  207. if (IsFlagSet(SetPortStmt_GetFlags(this), SPF_PARITY))
  208. TRACE_MSG(TF_ALWAYS, "set port parity %u", SetPortStmt_GetParity(this));
  209. break;
  210. case ST_SCREEN:
  211. if (IsFlagSet(SetScreenStmt_GetFlags(this), SPF_KEYBRD))
  212. TRACE_MSG(TF_ALWAYS, "set screen keyboard %s", SetScreenStmt_GetKeybrd(this) ? "on" : "off");
  213. break;
  214. default:
  215. ASSERT(0);
  216. break;
  217. }
  218. break;
  219. case AT_INT_EXPR:
  220. TRACE_MSG(TF_ALWAYS, " %d", IntExpr_GetVal(this));
  221. break;
  222. case AT_STRING_EXPR:
  223. TRACE_MSG(TF_ALWAYS, " %s", StrExpr_GetStr(this));
  224. break;
  225. case AT_BOOL_EXPR:
  226. TRACE_MSG(TF_ALWAYS, " %s", BoolExpr_GetVal(this) ? (LPSTR)"TRUE" : (LPSTR)"FALSE");
  227. break;
  228. case AT_VAR_EXPR:
  229. TRACE_MSG(TF_ALWAYS, " %s", VarExpr_GetIdent(this));
  230. break;
  231. case AT_BINOP_EXPR: {
  232. PBINOPEXPR pbo = (PBINOPEXPR)this;
  233. Ast_Dump((PAST)pbo->pexpr1);
  234. switch (BinOpExpr_GetType(this))
  235. {
  236. case BOT_OR:
  237. TRACE_MSG(TF_ALWAYS, " or");
  238. break;
  239. case BOT_AND:
  240. TRACE_MSG(TF_ALWAYS, " and");
  241. break;
  242. case BOT_LT:
  243. TRACE_MSG(TF_ALWAYS, " <");
  244. break;
  245. case BOT_LEQ:
  246. TRACE_MSG(TF_ALWAYS, " <=");
  247. break;
  248. case BOT_GT:
  249. TRACE_MSG(TF_ALWAYS, " >");
  250. break;
  251. case BOT_GEQ:
  252. TRACE_MSG(TF_ALWAYS, " >=");
  253. break;
  254. case BOT_EQ:
  255. TRACE_MSG(TF_ALWAYS, " ==");
  256. break;
  257. case BOT_NEQ:
  258. TRACE_MSG(TF_ALWAYS, " !=");
  259. break;
  260. case BOT_PLUS:
  261. TRACE_MSG(TF_ALWAYS, " +");
  262. break;
  263. case BOT_MINUS:
  264. TRACE_MSG(TF_ALWAYS, " -");
  265. break;
  266. case BOT_MULT:
  267. TRACE_MSG(TF_ALWAYS, " *");
  268. break;
  269. case BOT_DIV:
  270. TRACE_MSG(TF_ALWAYS, " /");
  271. break;
  272. default:
  273. ASSERT(0);
  274. break;
  275. }
  276. Ast_Dump((PAST)pbo->pexpr2);
  277. }
  278. break;
  279. case AT_UNOP_EXPR: {
  280. PUNOPEXPR puo = (PUNOPEXPR)this;
  281. switch (UnOpExpr_GetType(this))
  282. {
  283. case UOT_NEG:
  284. TRACE_MSG(TF_ALWAYS, " -");
  285. break;
  286. case UOT_NOT:
  287. TRACE_MSG(TF_ALWAYS, " !");
  288. break;
  289. case UOT_GETIP:
  290. TRACE_MSG(TF_ALWAYS, " getip");
  291. break;
  292. default:
  293. ASSERT(0);
  294. break;
  295. }
  296. Ast_Dump((PAST)puo->pexpr);
  297. }
  298. break;
  299. default:
  300. ASSERT(0);
  301. break;
  302. }
  303. }
  304. }
  305. #endif // DEBUG
  306. /*----------------------------------------------------------
  307. Purpose: Creates a new AST
  308. Returns: RES_OK
  309. RES_E_OUTOFMEMORY
  310. Cond: --
  311. */
  312. RES PUBLIC Ast_New(
  313. LPVOID * ppv,
  314. ASTTYPE asttype,
  315. DWORD cbSize,
  316. DWORD iLine)
  317. {
  318. PAST past;
  319. ASSERT(ppv);
  320. past = GAlloc(cbSize);
  321. if (past)
  322. {
  323. Ast_SetSize(past, cbSize);
  324. Ast_SetType(past, asttype);
  325. Ast_SetLine(past, iLine);
  326. }
  327. *ppv = past;
  328. return NULL != past ? RES_OK : RES_E_OUTOFMEMORY;
  329. }
  330. /*----------------------------------------------------------
  331. Purpose: Destroys the given AST.
  332. Returns:
  333. Cond: --
  334. */
  335. void PUBLIC Ast_Delete(
  336. PAST this)
  337. {
  338. GFree(this);
  339. }
  340. /*----------------------------------------------------------
  341. Purpose: Duplicate the given AST.
  342. Returns: RES_OK
  343. RES_E_OUTOFMEMORY
  344. Cond: --
  345. */
  346. RES PUBLIC Ast_Dup(
  347. PAST this,
  348. PAST * ppast)
  349. {
  350. PAST past;
  351. DWORD cbSize;
  352. ASSERT(this);
  353. ASSERT(ppast);
  354. cbSize = Ast_GetSize(this);
  355. past = GAlloc(cbSize);
  356. if (past)
  357. {
  358. BltByte(past, this, cbSize);
  359. }
  360. *ppast = past;
  361. return NULL != past ? RES_OK : RES_E_OUTOFMEMORY;
  362. }
  363. //
  364. // Expressions
  365. //
  366. /*----------------------------------------------------------
  367. Purpose: Callback for PADestroyEx.
  368. Returns: --
  369. Cond: --
  370. */
  371. void CALLBACK Expr_DeletePAPtr(
  372. LPVOID pv,
  373. LPARAM lparam)
  374. {
  375. Expr_Delete(pv);
  376. }
  377. /*----------------------------------------------------------
  378. Purpose: Destroys an Expr.
  379. Returns: RES_OK
  380. RES_E_INVALIDPARAM
  381. Cond: --
  382. */
  383. RES PUBLIC Expr_Delete(
  384. PEXPR this)
  385. {
  386. RES res;
  387. DBG_ENTER(Expr_Delete);
  388. if (this)
  389. {
  390. res = RES_OK;
  391. switch (this->ast.asttype)
  392. {
  393. case AT_INT_EXPR:
  394. case AT_BOOL_EXPR:
  395. // (Nothing to free inside)
  396. break;
  397. case AT_STRING_EXPR: {
  398. PSTREXPR ps = (PSTREXPR)this;
  399. if (ps->psz)
  400. GSetString(&ps->psz, NULL); // free
  401. }
  402. break;
  403. case AT_VAR_EXPR: {
  404. PVAREXPR ps = (PVAREXPR)this;
  405. if (ps->pszIdent)
  406. GSetString(&ps->pszIdent, NULL); // free
  407. }
  408. break;
  409. case AT_BINOP_EXPR: {
  410. PBINOPEXPR pbo = (PBINOPEXPR)this;
  411. if (pbo->pexpr1)
  412. Expr_Delete(pbo->pexpr1);
  413. if (pbo->pexpr2)
  414. Expr_Delete(pbo->pexpr2);
  415. }
  416. break;
  417. case AT_UNOP_EXPR: {
  418. PUNOPEXPR puo = (PUNOPEXPR)this;
  419. if (puo->pexpr)
  420. Expr_Delete(puo->pexpr);
  421. }
  422. break;
  423. default:
  424. ASSERT(0);
  425. res = RES_E_INVALIDPARAM;
  426. break;
  427. }
  428. if (RSUCCEEDED(res))
  429. {
  430. // Most of the time when the evaluated result
  431. // is a string, it is just a copy of the pointer
  432. // in the specific class structure. In these
  433. // cases it does not need to be freed again,
  434. // because it was freed above.
  435. if (this->er.psz && IsFlagSet(this->dwFlags, EF_ALLOCATED))
  436. {
  437. ASSERT(DATA_STRING == Expr_GetDataType(this));
  438. GSetString(&this->er.psz, NULL); // free
  439. }
  440. Ast_Delete((PAST)this);
  441. }
  442. }
  443. else
  444. res = RES_E_INVALIDPARAM;
  445. DBG_EXIT_RES(Expr_Delete, res);
  446. return res;
  447. }
  448. /*----------------------------------------------------------
  449. Purpose: Creates a IntExpr object.
  450. Returns: RES_OK
  451. RES_E_OUTOFMEMORY
  452. RES_E_INVALIDPARAM
  453. Cond: --
  454. */
  455. RES PUBLIC IntExpr_New(
  456. PEXPR * ppexpr,
  457. int nVal,
  458. DWORD iLine)
  459. {
  460. RES res;
  461. DBG_ENTER(IntExpr_New);
  462. ASSERT(ppexpr);
  463. if (ppexpr)
  464. {
  465. PINTEXPR this;
  466. res = Ast_New(&this, AT_INT_EXPR, sizeof(*this), iLine);
  467. if (RSUCCEEDED(res))
  468. {
  469. IntExpr_SetVal(this, nVal);
  470. }
  471. *ppexpr = (PEXPR)this;
  472. }
  473. else
  474. res = RES_E_INVALIDPARAM;
  475. DBG_EXIT_RES(IntExpr_New, res);
  476. return res;
  477. }
  478. /*----------------------------------------------------------
  479. Purpose: Creates a StrExpr object.
  480. Returns: RES_OK
  481. RES_E_OUTOFMEMORY
  482. RES_E_INVALIDPARAM
  483. Cond: --
  484. */
  485. RES PUBLIC StrExpr_New(
  486. PEXPR * ppexpr,
  487. LPCSTR psz,
  488. DWORD iLine)
  489. {
  490. RES res;
  491. DBG_ENTER(StrExpr_New);
  492. ASSERT(ppexpr);
  493. ASSERT(psz);
  494. if (ppexpr)
  495. {
  496. PSTREXPR this;
  497. res = Ast_New(&this, AT_STRING_EXPR, sizeof(*this), iLine);
  498. if (RSUCCEEDED(res))
  499. {
  500. res = RES_OK;
  501. if (!GSetString(&this->psz, psz))
  502. res = RES_E_OUTOFMEMORY;
  503. if (RFAILED(res))
  504. {
  505. Ast_Delete((PAST)this);
  506. this = NULL;
  507. }
  508. }
  509. *ppexpr = (PEXPR)this;
  510. }
  511. else
  512. res = RES_E_INVALIDPARAM;
  513. DBG_EXIT_RES(StrExpr_New, res);
  514. return res;
  515. }
  516. /*----------------------------------------------------------
  517. Purpose: Creates a BoolExpr object.
  518. Returns: RES_OK
  519. RES_E_OUTOFMEMORY
  520. RES_E_INVALIDPARAM
  521. Cond: --
  522. */
  523. RES PUBLIC BoolExpr_New(
  524. PEXPR * ppexpr,
  525. BOOL bVal,
  526. DWORD iLine)
  527. {
  528. RES res;
  529. DBG_ENTER(BoolExpr_New);
  530. ASSERT(ppexpr);
  531. if (ppexpr)
  532. {
  533. PBOOLEXPR this;
  534. res = Ast_New(&this, AT_BOOL_EXPR, sizeof(*this), iLine);
  535. if (RSUCCEEDED(res))
  536. {
  537. BoolExpr_SetVal(this, bVal);
  538. }
  539. *ppexpr = (PEXPR)this;
  540. }
  541. else
  542. res = RES_E_INVALIDPARAM;
  543. DBG_EXIT_RES(BoolExpr_New, res);
  544. return res;
  545. }
  546. /*----------------------------------------------------------
  547. Purpose: Creates a VarExpr object.
  548. Returns: RES_OK
  549. RES_E_OUTOFMEMORY
  550. RES_E_INVALIDPARAM
  551. Cond: --
  552. */
  553. RES PUBLIC VarExpr_New(
  554. PEXPR * ppexpr,
  555. LPCSTR pszIdent,
  556. DWORD iLine)
  557. {
  558. RES res;
  559. DBG_ENTER(VarExpr_New);
  560. ASSERT(ppexpr);
  561. ASSERT(pszIdent);
  562. if (ppexpr)
  563. {
  564. PVAREXPR this;
  565. res = Ast_New(&this, AT_VAR_EXPR, sizeof(*this), iLine);
  566. if (RSUCCEEDED(res))
  567. {
  568. res = RES_OK;
  569. if (!GSetString(&this->pszIdent, pszIdent))
  570. res = RES_E_OUTOFMEMORY;
  571. if (RFAILED(res))
  572. {
  573. Ast_Delete((PAST)this);
  574. this = NULL;
  575. }
  576. }
  577. *ppexpr = (PEXPR)this;
  578. }
  579. else
  580. res = RES_E_INVALIDPARAM;
  581. DBG_EXIT_RES(VarExpr_New, res);
  582. return res;
  583. }
  584. /*----------------------------------------------------------
  585. Purpose: Creates a BinOpExpr object.
  586. Returns: RES_OK
  587. RES_E_OUTOFMEMORY
  588. RES_E_INVALIDPARAM
  589. Cond: --
  590. */
  591. RES PUBLIC BinOpExpr_New(
  592. PEXPR * ppexpr,
  593. BINOPTYPE binoptype,
  594. PEXPR pexpr1,
  595. PEXPR pexpr2,
  596. DWORD iLine)
  597. {
  598. RES res;
  599. DBG_ENTER(BinOpExpr_New);
  600. ASSERT(ppexpr);
  601. ASSERT(pexpr1);
  602. ASSERT(pexpr2);
  603. if (ppexpr)
  604. {
  605. PBINOPEXPR this;
  606. res = Ast_New(&this, AT_BINOP_EXPR, sizeof(*this), iLine);
  607. if (RSUCCEEDED(res))
  608. {
  609. res = RES_OK;
  610. BinOpExpr_SetType(this, binoptype);
  611. this->pexpr1 = pexpr1;
  612. this->pexpr2 = pexpr2;
  613. }
  614. *ppexpr = (PEXPR)this;
  615. }
  616. else
  617. res = RES_E_INVALIDPARAM;
  618. DBG_EXIT_RES(BinOpExpr_New, res);
  619. return res;
  620. }
  621. /*----------------------------------------------------------
  622. Purpose: Creates a UnOpExpr object.
  623. Returns: RES_OK
  624. RES_E_OUTOFMEMORY
  625. RES_E_INVALIDPARAM
  626. Cond: --
  627. */
  628. RES PUBLIC UnOpExpr_New(
  629. PEXPR * ppexpr,
  630. UNOPTYPE unoptype,
  631. PEXPR pexpr,
  632. DWORD iLine)
  633. {
  634. RES res;
  635. DBG_ENTER(UnOpExpr_New);
  636. ASSERT(ppexpr);
  637. ASSERT(pexpr);
  638. if (ppexpr)
  639. {
  640. PUNOPEXPR this;
  641. res = Ast_New(&this, AT_UNOP_EXPR, sizeof(*this), iLine);
  642. if (RSUCCEEDED(res))
  643. {
  644. UnOpExpr_SetType(this, unoptype);
  645. this->pexpr = pexpr;
  646. }
  647. *ppexpr = (PEXPR)this;
  648. }
  649. else
  650. res = RES_E_INVALIDPARAM;
  651. DBG_EXIT_RES(UnOpExpr_New, res);
  652. return res;
  653. }
  654. //
  655. // Stmt
  656. //
  657. /*----------------------------------------------------------
  658. Purpose: Callback for PADestroyEx.
  659. Returns: --
  660. Cond: --
  661. */
  662. void CALLBACK Stmt_DeletePAPtr(
  663. LPVOID pv,
  664. LPARAM lparam)
  665. {
  666. Stmt_Delete(pv);
  667. }
  668. /*----------------------------------------------------------
  669. Purpose: Destroys a Stmt.
  670. Returns: RES_OK
  671. RES_E_INVALIDPARAM
  672. Cond: --
  673. */
  674. RES PUBLIC Stmt_Delete(
  675. PSTMT this)
  676. {
  677. RES res;
  678. DBG_ENTER(Stmt_Delete);
  679. if (this)
  680. {
  681. PEXPR pexpr;
  682. HSA hsa;
  683. res = RES_OK;
  684. switch (this->ast.asttype)
  685. {
  686. case AT_ENTER_STMT:
  687. // (don't free pst -- it belongs to the decl structs)
  688. case AT_LEAVE_STMT:
  689. case AT_HALT_STMT:
  690. break;
  691. case AT_ASSIGN_STMT: {
  692. PASSIGNSTMT pls = (PASSIGNSTMT)this;
  693. if (pls->pszIdent)
  694. GSetString(&pls->pszIdent, NULL); // free
  695. pexpr = AssignStmt_GetExpr(this);
  696. if (pexpr)
  697. Expr_Delete(pexpr);
  698. }
  699. break;
  700. case AT_WHILE_STMT: {
  701. PWHILESTMT pls = (PWHILESTMT)this;
  702. pexpr = WhileStmt_GetExpr(this);
  703. if (pexpr)
  704. Expr_Delete(pexpr);
  705. if (pls->hpaStmts)
  706. PADestroyEx(pls->hpaStmts, Stmt_DeletePAPtr, 0);
  707. }
  708. break;
  709. case AT_IF_STMT: {
  710. PIFSTMT pls = (PIFSTMT)this;
  711. pexpr = IfStmt_GetExpr(this);
  712. if (pexpr)
  713. Expr_Delete(pexpr);
  714. if (pls->hpaStmts)
  715. PADestroyEx(pls->hpaStmts, Stmt_DeletePAPtr, 0);
  716. }
  717. break;
  718. case AT_LABEL_STMT: {
  719. PLABELSTMT pls = (PLABELSTMT)this;
  720. if (pls->psz)
  721. GSetString(&pls->psz, NULL); // free
  722. }
  723. break;
  724. case AT_GOTO_STMT: {
  725. PGOTOSTMT pgs = (PGOTOSTMT)this;
  726. if (pgs->psz)
  727. GSetString(&pgs->psz, NULL); // free
  728. }
  729. break;
  730. case AT_DELAY_STMT:
  731. pexpr = DelayStmt_GetExpr(this);
  732. if (pexpr)
  733. Expr_Delete(pexpr);
  734. break;
  735. case AT_TRANSMIT_STMT:
  736. pexpr = TransmitStmt_GetExpr(this);
  737. if (pexpr)
  738. Expr_Delete(pexpr);
  739. break;
  740. case AT_WAITFOR_STMT:
  741. hsa = WaitforStmt_GetCaseList(this);
  742. if (hsa)
  743. Waitcase_Destroy(hsa);
  744. pexpr = WaitforStmt_GetUntilExpr(this);
  745. if (pexpr)
  746. Expr_Delete(pexpr);
  747. break;
  748. case AT_SET_STMT:
  749. switch (SetStmt_GetType(this))
  750. {
  751. case ST_IPADDR:
  752. pexpr = SetIPStmt_GetExpr(this);
  753. if (pexpr)
  754. Expr_Delete(pexpr);
  755. break;
  756. case ST_PORT:
  757. case ST_SCREEN:
  758. break;
  759. default:
  760. ASSERT(0);
  761. res = RES_E_INVALIDPARAM;
  762. break;
  763. }
  764. break;
  765. default:
  766. ASSERT(0);
  767. res = RES_E_INVALIDPARAM;
  768. break;
  769. }
  770. if (RSUCCEEDED(res))
  771. Ast_Delete((PAST)this);
  772. }
  773. else
  774. res = RES_E_INVALIDPARAM;
  775. DBG_EXIT_RES(Stmt_Delete, res);
  776. return res;
  777. }
  778. //
  779. // Statements
  780. //
  781. /*----------------------------------------------------------
  782. Purpose: Creates a WaitforStmt object.
  783. Returns: RES_OK
  784. RES_E_OUTOFMEMORY
  785. RES_E_INVALIDPARAM
  786. Cond: --
  787. */
  788. RES PUBLIC WaitforStmt_New(
  789. PSTMT * ppstmt,
  790. HSA hsa,
  791. PEXPR pexprUntil, // May be NULL
  792. DWORD iLine)
  793. {
  794. RES res;
  795. DBG_ENTER(WaitforStmt_New);
  796. ASSERT(ppstmt);
  797. ASSERT(hsa);
  798. if (ppstmt)
  799. {
  800. PWAITFORSTMT this;
  801. res = Ast_New(&this, AT_WAITFOR_STMT, sizeof(*this), iLine);
  802. if (RSUCCEEDED(res))
  803. {
  804. res = RES_OK; // assume success
  805. this->hsa = hsa;
  806. this->pexprUntil = pexprUntil;
  807. }
  808. *ppstmt = (PSTMT)this;
  809. }
  810. else
  811. res = RES_E_INVALIDPARAM;
  812. DBG_EXIT_RES(WaitforStmt_New, res);
  813. return res;
  814. }
  815. /*----------------------------------------------------------
  816. Purpose: Creates a TransmitStmt object.
  817. Returns: RES_OK
  818. RES_E_OUTOFMEMORY
  819. RES_E_INVALIDPARAM
  820. Cond: --
  821. */
  822. RES PUBLIC TransmitStmt_New(
  823. PSTMT * ppstmt,
  824. PEXPR pexpr,
  825. DWORD dwFlags,
  826. DWORD iLine)
  827. {
  828. RES res;
  829. DBG_ENTER(TransmitStmt_New);
  830. ASSERT(ppstmt);
  831. ASSERT(pexpr);
  832. if (ppstmt)
  833. {
  834. PTRANSMITSTMT this;
  835. res = Ast_New(&this, AT_TRANSMIT_STMT, sizeof(*this), iLine);
  836. if (RSUCCEEDED(res))
  837. {
  838. res = RES_OK; // assume success
  839. this->pexpr = pexpr;
  840. this->dwFlags = dwFlags;
  841. }
  842. *ppstmt = (PSTMT)this;
  843. }
  844. else
  845. res = RES_E_INVALIDPARAM;
  846. DBG_EXIT_RES(TransmitStmt_New, res);
  847. return res;
  848. }
  849. /*----------------------------------------------------------
  850. Purpose: Creates a DelayStmt object.
  851. Returns: RES_OK
  852. RES_E_OUTOFMEMORY
  853. RES_E_INVALIDPARAM
  854. Cond: --
  855. */
  856. RES PUBLIC DelayStmt_New(
  857. PSTMT * ppstmt,
  858. PEXPR pexpr,
  859. DWORD iLine)
  860. {
  861. RES res;
  862. DBG_ENTER(DelayStmt_New);
  863. ASSERT(ppstmt);
  864. ASSERT(pexpr);
  865. if (ppstmt)
  866. {
  867. PDELAYSTMT this;
  868. res = Ast_New(&this, AT_DELAY_STMT, sizeof(*this), iLine);
  869. if (RSUCCEEDED(res))
  870. {
  871. this->pexprSecs = pexpr;
  872. res = RES_OK;
  873. }
  874. *ppstmt = (PSTMT)this;
  875. }
  876. else
  877. res = RES_E_INVALIDPARAM;
  878. DBG_EXIT_RES(DelayStmt_New, res);
  879. return res;
  880. }
  881. /*----------------------------------------------------------
  882. Purpose: Creates a HaltStmt object.
  883. Returns: RES_OK
  884. RES_E_OUTOFMEMORY
  885. RES_E_INVALIDPARAM
  886. Cond: --
  887. */
  888. RES PUBLIC HaltStmt_New(
  889. PSTMT * ppstmt,
  890. DWORD iLine)
  891. {
  892. RES res;
  893. DBG_ENTER(HaltStmt_New);
  894. ASSERT(ppstmt);
  895. if (ppstmt)
  896. {
  897. PHALTSTMT this;
  898. res = Ast_New(&this, AT_HALT_STMT, sizeof(*this), iLine);
  899. *ppstmt = (PSTMT)this;
  900. }
  901. else
  902. res = RES_E_INVALIDPARAM;
  903. DBG_EXIT_RES(HaltStmt_New, res);
  904. return res;
  905. }
  906. /*----------------------------------------------------------
  907. Purpose: Creates an EnterStmt object.
  908. Returns: RES_OK
  909. RES_E_OUTOFMEMORY
  910. RES_E_INVALIDPARAM
  911. Cond: --
  912. */
  913. RES PUBLIC EnterStmt_New(
  914. PSTMT * ppstmt,
  915. PSYMTAB pst,
  916. DWORD iLine)
  917. {
  918. RES res;
  919. DBG_ENTER(EnterStmt_New);
  920. ASSERT(ppstmt);
  921. if (ppstmt)
  922. {
  923. PENTERSTMT this;
  924. res = Ast_New(&this, AT_ENTER_STMT, sizeof(*this), iLine);
  925. if (RSUCCEEDED(res))
  926. {
  927. this->pst = pst;
  928. }
  929. *ppstmt = (PSTMT)this;
  930. }
  931. else
  932. res = RES_E_INVALIDPARAM;
  933. DBG_EXIT_RES(EnterStmt_New, res);
  934. return res;
  935. }
  936. /*----------------------------------------------------------
  937. Purpose: Creates an LeaveStmt object.
  938. Returns: RES_OK
  939. RES_E_OUTOFMEMORY
  940. RES_E_INVALIDPARAM
  941. Cond: --
  942. */
  943. RES PUBLIC LeaveStmt_New(
  944. PSTMT * ppstmt,
  945. DWORD iLine)
  946. {
  947. RES res;
  948. DBG_ENTER(LeaveStmt_New);
  949. ASSERT(ppstmt);
  950. if (ppstmt)
  951. {
  952. PLEAVESTMT this;
  953. res = Ast_New(&this, AT_LEAVE_STMT, sizeof(*this), iLine);
  954. *ppstmt = (PSTMT)this;
  955. }
  956. else
  957. res = RES_E_INVALIDPARAM;
  958. DBG_EXIT_RES(LeaveStmt_New, res);
  959. return res;
  960. }
  961. /*----------------------------------------------------------
  962. Purpose: Creates an AssignStmt object.
  963. Returns: RES_OK
  964. RES_E_OUTOFMEMORY
  965. RES_E_INVALIDPARAM
  966. Cond: --
  967. */
  968. RES PUBLIC AssignStmt_New(
  969. PSTMT * ppstmt,
  970. LPCSTR pszIdent,
  971. PEXPR pexpr,
  972. DWORD iLine)
  973. {
  974. RES res;
  975. DBG_ENTER(AssignStmt_New);
  976. ASSERT(ppstmt);
  977. ASSERT(pszIdent);
  978. ASSERT(pexpr);
  979. if (ppstmt)
  980. {
  981. PASSIGNSTMT this;
  982. res = Ast_New(&this, AT_ASSIGN_STMT, sizeof(*this), iLine);
  983. if (RSUCCEEDED(res))
  984. {
  985. res = RES_OK; // assume success
  986. if (!GSetString(&this->pszIdent, pszIdent))
  987. res = RES_E_OUTOFMEMORY;
  988. else
  989. this->pexpr = pexpr;
  990. if (RFAILED(res))
  991. {
  992. Ast_Delete((PAST)this);
  993. this = NULL;
  994. }
  995. }
  996. *ppstmt = (PSTMT)this;
  997. }
  998. else
  999. res = RES_E_INVALIDPARAM;
  1000. DBG_EXIT_RES(AssignStmt_New, res);
  1001. return res;
  1002. }
  1003. /*----------------------------------------------------------
  1004. Purpose: Creates a LabelStmt object.
  1005. Returns: RES_OK
  1006. RES_E_OUTOFMEMORY
  1007. RES_E_INVALIDPARAM
  1008. Cond: --
  1009. */
  1010. RES PUBLIC LabelStmt_New(
  1011. PSTMT * ppstmt,
  1012. LPCSTR psz,
  1013. DWORD iLine)
  1014. {
  1015. RES res;
  1016. DBG_ENTER(LabelStmt_New);
  1017. ASSERT(ppstmt);
  1018. ASSERT(psz);
  1019. if (ppstmt)
  1020. {
  1021. PLABELSTMT this;
  1022. res = Ast_New(&this, AT_LABEL_STMT, sizeof(*this), iLine);
  1023. if (RSUCCEEDED(res))
  1024. {
  1025. res = RES_OK; // assume success
  1026. if (!GSetString(&this->psz, psz))
  1027. {
  1028. res = RES_E_OUTOFMEMORY;
  1029. Ast_Delete((PAST)this);
  1030. this = NULL;
  1031. }
  1032. }
  1033. *ppstmt = (PSTMT)this;
  1034. }
  1035. else
  1036. res = RES_E_INVALIDPARAM;
  1037. DBG_EXIT_RES(LabelStmt_New, res);
  1038. return res;
  1039. }
  1040. /*----------------------------------------------------------
  1041. Purpose: Creates a GotoStmt object.
  1042. Returns: RES_OK
  1043. RES_E_OUTOFMEMORY
  1044. RES_E_INVALIDPARAM
  1045. Cond: --
  1046. */
  1047. RES PUBLIC GotoStmt_New(
  1048. PSTMT * ppstmt,
  1049. LPCSTR psz,
  1050. DWORD iLine)
  1051. {
  1052. RES res;
  1053. DBG_ENTER(GotoStmt_New);
  1054. ASSERT(ppstmt);
  1055. ASSERT(psz);
  1056. if (ppstmt)
  1057. {
  1058. PGOTOSTMT this;
  1059. res = Ast_New(&this, AT_GOTO_STMT, sizeof(*this), iLine);
  1060. if (RSUCCEEDED(res))
  1061. {
  1062. res = RES_OK; // assume success
  1063. if (!GSetString(&this->psz, psz))
  1064. {
  1065. res = RES_E_OUTOFMEMORY;
  1066. Ast_Delete((PAST)this);
  1067. this = NULL;
  1068. }
  1069. }
  1070. *ppstmt = (PSTMT)this;
  1071. }
  1072. else
  1073. res = RES_E_INVALIDPARAM;
  1074. DBG_EXIT_RES(GotoStmt_New, res);
  1075. return res;
  1076. }
  1077. /*----------------------------------------------------------
  1078. Purpose: Creates a WhileStmt object.
  1079. Returns: RES_OK
  1080. RES_E_OUTOFMEMORY
  1081. RES_E_INVALIDPARAM
  1082. Cond: --
  1083. */
  1084. RES PUBLIC WhileStmt_New(
  1085. PSTMT * ppstmt,
  1086. PEXPR pexpr,
  1087. HPA hpa,
  1088. LPCSTR pszTopLabel,
  1089. LPCSTR pszEndLabel,
  1090. DWORD iLine)
  1091. {
  1092. RES res;
  1093. ASSERT(ppstmt);
  1094. ASSERT(hpa);
  1095. ASSERT(pexpr);
  1096. ASSERT(pszTopLabel);
  1097. ASSERT(pszEndLabel);
  1098. if (ppstmt)
  1099. {
  1100. PWHILESTMT this;
  1101. res = Ast_New(&this, AT_WHILE_STMT, sizeof(*this), iLine);
  1102. if (RSUCCEEDED(res))
  1103. {
  1104. res = RES_OK; // assume success
  1105. this->pexpr = pexpr;
  1106. this->hpaStmts = hpa;
  1107. lstrcpyn(this->szTopLabel, pszTopLabel, sizeof(this->szTopLabel));
  1108. lstrcpyn(this->szEndLabel, pszEndLabel, sizeof(this->szEndLabel));
  1109. }
  1110. *ppstmt = (PSTMT)this;
  1111. }
  1112. else
  1113. res = RES_E_INVALIDPARAM;
  1114. return res;
  1115. }
  1116. /*----------------------------------------------------------
  1117. Purpose: Creates an IfStmt object.
  1118. Returns: RES_OK
  1119. RES_E_OUTOFMEMORY
  1120. RES_E_INVALIDPARAM
  1121. Cond: --
  1122. */
  1123. RES PUBLIC IfStmt_New(
  1124. PSTMT * ppstmt,
  1125. PEXPR pexpr,
  1126. HPA hpa,
  1127. LPCSTR pszElseLabel,
  1128. LPCSTR pszEndLabel,
  1129. DWORD iLine)
  1130. {
  1131. RES res;
  1132. ASSERT(ppstmt);
  1133. ASSERT(hpa);
  1134. ASSERT(pexpr);
  1135. ASSERT(pszElseLabel);
  1136. ASSERT(pszEndLabel);
  1137. if (ppstmt)
  1138. {
  1139. PIFSTMT this;
  1140. res = Ast_New(&this, AT_IF_STMT, sizeof(*this), iLine);
  1141. if (RSUCCEEDED(res))
  1142. {
  1143. res = RES_OK; // assume success
  1144. this->pexpr = pexpr;
  1145. this->hpaStmts = hpa;
  1146. lstrcpyn(this->szElseLabel, pszElseLabel, sizeof(this->szElseLabel));
  1147. lstrcpyn(this->szEndLabel, pszEndLabel, sizeof(this->szEndLabel));
  1148. }
  1149. *ppstmt = (PSTMT)this;
  1150. }
  1151. else
  1152. res = RES_E_INVALIDPARAM;
  1153. return res;
  1154. }
  1155. /*----------------------------------------------------------
  1156. Purpose: Creates a SetStmt object.
  1157. Returns: RES_OK
  1158. RES_E_OUTOFMEMORY
  1159. RES_E_INVALIDPARAM
  1160. Cond: --
  1161. */
  1162. RES PRIVATE SetStmt_New(
  1163. PVOID * ppv,
  1164. SETTYPE settype,
  1165. DWORD cbSize,
  1166. DWORD iLine)
  1167. {
  1168. RES res;
  1169. DBG_ENTER(SetStmt_New);
  1170. ASSERT(ppv);
  1171. ASSERT(sizeof(SETSTMT) <= cbSize);
  1172. if (ppv)
  1173. {
  1174. PSETSTMT this;
  1175. res = Ast_New(&this, AT_SET_STMT, cbSize, iLine);
  1176. if (RSUCCEEDED(res))
  1177. {
  1178. SetStmt_SetType(this, settype);
  1179. res = RES_OK;
  1180. }
  1181. *ppv = this;
  1182. }
  1183. else
  1184. res = RES_E_INVALIDPARAM;
  1185. DBG_EXIT_RES(SetStmt_New, res);
  1186. return res;
  1187. }
  1188. /*----------------------------------------------------------
  1189. Purpose: Creates a SetIPStmt object.
  1190. Returns: RES_OK
  1191. RES_E_OUTOFMEMORY
  1192. RES_E_INVALIDPARAM
  1193. Cond: --
  1194. */
  1195. RES PUBLIC SetIPStmt_New(
  1196. PSTMT * ppstmt,
  1197. PEXPR pexpr,
  1198. DWORD iLine)
  1199. {
  1200. RES res;
  1201. DBG_ENTER(SetIPStmt_New);
  1202. ASSERT(ppstmt);
  1203. ASSERT(pexpr);
  1204. if (ppstmt)
  1205. {
  1206. PSETIPSTMT this;
  1207. res = SetStmt_New(&this, ST_IPADDR, sizeof(*this), iLine);
  1208. if (RSUCCEEDED(res))
  1209. {
  1210. res = RES_OK; // assume success
  1211. this->pexpr = pexpr;
  1212. }
  1213. *ppstmt = (PSTMT)this;
  1214. }
  1215. else
  1216. res = RES_E_INVALIDPARAM;
  1217. DBG_EXIT_RES(SetIPStmt_New, res);
  1218. return res;
  1219. }
  1220. /*----------------------------------------------------------
  1221. Purpose: Creates a SetPortStmt object.
  1222. Returns: RES_OK
  1223. RES_E_OUTOFMEMORY
  1224. RES_E_INVALIDPARAM
  1225. Cond: --
  1226. */
  1227. RES PUBLIC SetPortStmt_New(
  1228. PSTMT * ppstmt,
  1229. PPORTSTATE pstate,
  1230. DWORD iLine)
  1231. {
  1232. RES res;
  1233. DBG_ENTER(SetPortStmt_New);
  1234. ASSERT(ppstmt);
  1235. ASSERT(pstate);
  1236. if (ppstmt && pstate)
  1237. {
  1238. PSETPORTSTMT this;
  1239. res = SetStmt_New(&this, ST_PORT, sizeof(*this), iLine);
  1240. if (RSUCCEEDED(res))
  1241. {
  1242. DWORD dwFlags = pstate->dwFlags;
  1243. res = RES_OK; // assume success
  1244. this->portstate.dwFlags = dwFlags;
  1245. if (IsFlagSet(dwFlags, SPF_DATABITS))
  1246. this->portstate.nDatabits = pstate->nDatabits;
  1247. if (IsFlagSet(dwFlags, SPF_STOPBITS))
  1248. this->portstate.nStopbits = pstate->nStopbits;
  1249. if (IsFlagSet(dwFlags, SPF_PARITY))
  1250. this->portstate.nParity = pstate->nParity;
  1251. }
  1252. *ppstmt = (PSTMT)this;
  1253. }
  1254. else
  1255. res = RES_E_INVALIDPARAM;
  1256. DBG_EXIT_RES(SetPortStmt_New, res);
  1257. return res;
  1258. }
  1259. /*----------------------------------------------------------
  1260. Purpose: Creates a SetScreenStmt object.
  1261. Returns: RES_OK
  1262. RES_E_OUTOFMEMORY
  1263. RES_E_INVALIDPARAM
  1264. Cond: --
  1265. */
  1266. RES PUBLIC SetScreenStmt_New(
  1267. PSTMT * ppstmt,
  1268. PSCREENSET pstate,
  1269. DWORD iLine)
  1270. {
  1271. RES res;
  1272. DBG_ENTER(SetScreenStmt_New);
  1273. ASSERT(ppstmt);
  1274. ASSERT(pstate);
  1275. if (ppstmt && pstate)
  1276. {
  1277. PSETSCREENSTMT this;
  1278. res = SetStmt_New(&this, ST_SCREEN, sizeof(*this), iLine);
  1279. if (RSUCCEEDED(res))
  1280. {
  1281. DWORD dwFlags = pstate->dwFlags;
  1282. res = RES_OK; // assume success
  1283. this->screenset.dwFlags = dwFlags;
  1284. if (IsFlagSet(dwFlags, SPF_KEYBRD))
  1285. this->screenset.fKBOn = pstate->fKBOn;
  1286. }
  1287. *ppstmt = (PSTMT)this;
  1288. }
  1289. else
  1290. res = RES_E_INVALIDPARAM;
  1291. DBG_EXIT_RES(SetScreenStmt_New, res);
  1292. return res;
  1293. }
  1294. //
  1295. // Decl
  1296. //
  1297. /*----------------------------------------------------------
  1298. Purpose: Callback for PADestroyEx.
  1299. Returns: --
  1300. Cond: --
  1301. */
  1302. void CALLBACK Decl_DeletePAPtr(
  1303. LPVOID pv,
  1304. LPARAM lparam)
  1305. {
  1306. Decl_Delete(pv);
  1307. }
  1308. /*----------------------------------------------------------
  1309. Purpose: Destroys a Decl.
  1310. Returns: RES_OK
  1311. RES_E_INVALIDPARAM
  1312. Cond: --
  1313. */
  1314. RES PUBLIC Decl_Delete(
  1315. PDECL this)
  1316. {
  1317. RES res;
  1318. DBG_ENTER(Decl_Delete);
  1319. if (this)
  1320. {
  1321. res = RES_OK;
  1322. switch (this->ast.asttype)
  1323. {
  1324. case AT_MODULE_DECL: {
  1325. PMODULEDECL pmd = (PMODULEDECL)this;
  1326. if (pmd->hpaProcs)
  1327. PADestroyEx(pmd->hpaProcs, Decl_DeletePAPtr, 0);
  1328. if (pmd->pst)
  1329. Symtab_Destroy(pmd->pst);
  1330. }
  1331. break;
  1332. case AT_PROC_DECL: {
  1333. PPROCDECL ppd = (PPROCDECL)this;
  1334. if (ppd->hpaStmts)
  1335. PADestroyEx(ppd->hpaStmts, Stmt_DeletePAPtr, 0);
  1336. if (ppd->pst)
  1337. Symtab_Destroy(ppd->pst);
  1338. if (ppd->pszIdent)
  1339. GSetString(&ppd->pszIdent, NULL); // free
  1340. }
  1341. break;
  1342. default:
  1343. ASSERT(0);
  1344. res = RES_E_INVALIDPARAM;
  1345. break;
  1346. }
  1347. if (RSUCCEEDED(res))
  1348. Ast_Delete((PAST)this);
  1349. }
  1350. else
  1351. res = RES_E_INVALIDPARAM;
  1352. DBG_EXIT_RES(Decl_Delete, res);
  1353. return res;
  1354. }
  1355. //
  1356. // ProcDecl
  1357. //
  1358. /*----------------------------------------------------------
  1359. Purpose: Creates a ProcDecl object.
  1360. Returns: RES_OK
  1361. RES_E_OUTOFMEMORY
  1362. RES_E_INVALIDPARAM
  1363. Cond: --
  1364. */
  1365. RES PUBLIC ProcDecl_New(
  1366. PDECL * ppdecl,
  1367. LPCSTR pszIdent,
  1368. HPA hpa,
  1369. PSYMTAB pst,
  1370. DWORD iLine)
  1371. {
  1372. RES res;
  1373. DBG_ENTER(ProcDecl_New);
  1374. ASSERT(ppdecl);
  1375. ASSERT(hpa);
  1376. ASSERT(pst);
  1377. if (ppdecl)
  1378. {
  1379. PPROCDECL this;
  1380. res = Ast_New(&this, AT_PROC_DECL, sizeof(*this), iLine);
  1381. if (RSUCCEEDED(res))
  1382. {
  1383. res = RES_OK; // assume success
  1384. if (!GSetString(&this->pszIdent, pszIdent))
  1385. res = RES_E_OUTOFMEMORY;
  1386. else
  1387. {
  1388. this->hpaStmts = hpa;
  1389. this->pst = pst;
  1390. }
  1391. if (RFAILED(res))
  1392. {
  1393. Decl_Delete((PDECL)this);
  1394. this = NULL;
  1395. }
  1396. }
  1397. *ppdecl = (PDECL)this;
  1398. }
  1399. else
  1400. res = RES_E_INVALIDPARAM;
  1401. DBG_EXIT_RES(ProcDecl_New, res);
  1402. return res;
  1403. }
  1404. //
  1405. // ModuleDecl
  1406. //
  1407. /*----------------------------------------------------------
  1408. Purpose: Creates a ModuleDecl object.
  1409. Returns: RES_OK
  1410. RES_E_OUTOFMEMORY
  1411. RES_E_INVALIDPARAM
  1412. Cond: --
  1413. */
  1414. RES PUBLIC ModuleDecl_New(
  1415. PDECL * ppdecl,
  1416. HPA hpa,
  1417. PSYMTAB pst,
  1418. DWORD iLine)
  1419. {
  1420. RES res;
  1421. DBG_ENTER(ModuleDecl_New);
  1422. ASSERT(ppdecl);
  1423. ASSERT(hpa);
  1424. ASSERT(pst);
  1425. if (ppdecl)
  1426. {
  1427. PMODULEDECL this;
  1428. res = Ast_New(&this, AT_MODULE_DECL, sizeof(*this), iLine);
  1429. if (RSUCCEEDED(res))
  1430. {
  1431. res = RES_OK; // assume success
  1432. this->hpaProcs = NULL;
  1433. if ( !PAClone(&this->hpaProcs, hpa) )
  1434. res = RES_E_OUTOFMEMORY;
  1435. else
  1436. {
  1437. this->pst = pst;
  1438. }
  1439. if (RFAILED(res))
  1440. {
  1441. Decl_Delete((PDECL)this);
  1442. this = NULL;
  1443. }
  1444. }
  1445. *ppdecl = (PDECL)this;
  1446. }
  1447. else
  1448. res = RES_E_INVALIDPARAM;
  1449. DBG_EXIT_RES(ModuleDecl_New, res);
  1450. return res;
  1451. }
  1452. //
  1453. // AST Exec block
  1454. //
  1455. #define SZ_SUCCESS "$SUCCESS"
  1456. #define SZ_FAILURE "$FAILURE"
  1457. /*----------------------------------------------------------
  1458. Purpose: Initialize the AST exec block.
  1459. Returns: RES_OK
  1460. Cond: --
  1461. */
  1462. RES PUBLIC Astexec_Init(
  1463. PASTEXEC this,
  1464. HANDLE hport,
  1465. PSESS_CONFIGURATION_INFO psci,
  1466. HSA hsaStxerr)
  1467. {
  1468. RES res;
  1469. ASSERT(this);
  1470. ASSERT(psci);
  1471. ASSERT(hsaStxerr);
  1472. // For this first version, we only support one module and one
  1473. // main procedure, so set the starting point on the first
  1474. // statement in that procedure.
  1475. if (this)
  1476. {
  1477. ZeroInit(this, ASTEXEC);
  1478. this->hport = hport;
  1479. this->psci = psci;
  1480. // Don't free hsaStxerr -- it belongs to the caller
  1481. this->hsaStxerr = hsaStxerr;
  1482. if ( !PACreate(&this->hpaPcode, 8) )
  1483. res = RES_E_OUTOFMEMORY;
  1484. else
  1485. {
  1486. res = Symtab_Create(&this->pstSystem, NULL);
  1487. if (RSUCCEEDED(res))
  1488. {
  1489. // Add the system variables
  1490. PSTE pste;
  1491. struct
  1492. {
  1493. LPCSTR pszIdent;
  1494. DATATYPE dt;
  1495. EVALRES er;
  1496. } s_rgvars[] =
  1497. {
  1498. { "$USERID", DATA_STRING, psci->szUserName },
  1499. { "$PASSWORD", DATA_STRING, psci->szPassword },
  1500. { SZ_SUCCESS, DATA_BOOL, (LPSTR)TRUE },
  1501. { SZ_FAILURE, DATA_BOOL, (LPSTR)FALSE },
  1502. };
  1503. int i;
  1504. for (i = 0; i < ARRAY_ELEMENTS(s_rgvars); i++)
  1505. {
  1506. res = STE_Create(&pste, s_rgvars[i].pszIdent, s_rgvars[i].dt);
  1507. if (RFAILED(res))
  1508. break;
  1509. pste->er.dw = s_rgvars[i].er.dw;
  1510. res = Symtab_InsertEntry(this->pstSystem, pste);
  1511. if (RFAILED(res))
  1512. break;
  1513. }
  1514. }
  1515. }
  1516. // Did something fail above?
  1517. if (RFAILED(res))
  1518. {
  1519. // Yes; clean up
  1520. Astexec_Destroy(this);
  1521. }
  1522. }
  1523. else
  1524. res = RES_E_INVALIDPARAM;
  1525. return res;
  1526. }
  1527. /*----------------------------------------------------------
  1528. Purpose: Destroys the AST exec block.
  1529. Returns: RES_OK
  1530. Cond: --
  1531. */
  1532. RES PUBLIC Astexec_Destroy(
  1533. PASTEXEC this)
  1534. {
  1535. RES res;
  1536. if (this)
  1537. {
  1538. if (this->hpaPcode)
  1539. {
  1540. PADestroy(this->hpaPcode);
  1541. this->hpaPcode = NULL;
  1542. }
  1543. if (this->pstSystem)
  1544. {
  1545. Symtab_Destroy(this->pstSystem);
  1546. this->pstSystem = NULL;
  1547. }
  1548. // ('this' was not allocated. Do not free it.)
  1549. // (hsaStxerr is not owned by this class. Do not free it.)
  1550. res = RES_OK;
  1551. }
  1552. else
  1553. res = RES_E_INVALIDPARAM;
  1554. return res;
  1555. }
  1556. /*----------------------------------------------------------
  1557. Purpose: Sets the success/failure code
  1558. Returns: --
  1559. Cond: --
  1560. */
  1561. void PUBLIC Astexec_SetError(
  1562. PASTEXEC this,
  1563. BOOL bSuccess, // TRUE: success
  1564. BOOL bFailure)
  1565. {
  1566. PSTE pste;
  1567. ASSERT(this);
  1568. if (RES_OK == Symtab_FindEntry(this->pstSystem, SZ_SUCCESS, STFF_DEFAULT, &pste, NULL))
  1569. {
  1570. // Set the code for success
  1571. pste->er.bVal = bSuccess;
  1572. if (RES_OK == Symtab_FindEntry(this->pstSystem, SZ_FAILURE, STFF_DEFAULT, &pste, NULL))
  1573. {
  1574. // Set the code for failure
  1575. pste->er.bVal = bFailure;
  1576. }
  1577. else
  1578. ASSERT(0);
  1579. }
  1580. else
  1581. ASSERT(0);
  1582. }
  1583. /*----------------------------------------------------------
  1584. Purpose: Adds the statement to the executable list.
  1585. Returns: RES_OK
  1586. RES_E_OUTOFMEMORY
  1587. Cond: --
  1588. */
  1589. RES PUBLIC Astexec_Add(
  1590. PASTEXEC this,
  1591. PSTMT pstmt)
  1592. {
  1593. RES res;
  1594. ASSERT(this);
  1595. ASSERT(pstmt);
  1596. if (PAInsertPtr(this->hpaPcode, PA_APPEND, pstmt))
  1597. res = RES_OK;
  1598. else
  1599. res = RES_E_OUTOFMEMORY;
  1600. return res;
  1601. }
  1602. /*----------------------------------------------------------
  1603. Purpose: Inserts a label into the executable list by recording
  1604. the current ipaCur into the label entry in the
  1605. symbol table.
  1606. Returns: RES_OK
  1607. Cond: --
  1608. */
  1609. RES PUBLIC Astexec_InsertLabel(
  1610. PASTEXEC this,
  1611. LPCSTR pszIdent,
  1612. PSYMTAB pst)
  1613. {
  1614. RES res;
  1615. DWORD ipa;
  1616. PSTE pste;
  1617. ASSERT(this);
  1618. ASSERT(pszIdent);
  1619. ASSERT(pst);
  1620. ipa = PAGetCount(this->hpaPcode);
  1621. if (RES_OK == Symtab_FindEntry(pst, pszIdent, STFF_DEFAULT, &pste, NULL))
  1622. {
  1623. // Set the current code location in the symbol table
  1624. pste->er.dw = ipa;
  1625. res = RES_OK;
  1626. }
  1627. else
  1628. {
  1629. ASSERT(0);
  1630. res = RES_E_FAIL;
  1631. }
  1632. return res;
  1633. }
  1634. /*----------------------------------------------------------
  1635. Purpose: Jumps to the given label.
  1636. Returns: RES_OK
  1637. Cond: --
  1638. */
  1639. RES PUBLIC Astexec_JumpToLabel(
  1640. PASTEXEC this,
  1641. LPCSTR pszIdent)
  1642. {
  1643. RES res;
  1644. PSTE pste;
  1645. ASSERT(pszIdent);
  1646. ASSERT(this);
  1647. ASSERT(this->pstCur);
  1648. if (RES_OK == Symtab_FindEntry(this->pstCur, pszIdent, STFF_DEFAULT, &pste, NULL))
  1649. {
  1650. EVALRES er;
  1651. STE_GetValue(pste, &er);
  1652. // Set instruction pointer
  1653. Astexec_SetIP(this, (DWORD) er.dw);
  1654. res = RES_OK;
  1655. }
  1656. else
  1657. {
  1658. // The label should have been in the symbol table!
  1659. ASSERT(0);
  1660. res = RES_E_FAIL;
  1661. }
  1662. return res;
  1663. }
  1664. /*----------------------------------------------------------
  1665. Purpose: Sends psz to the port (via hwnd)
  1666. Returns: --
  1667. Cond: --
  1668. */
  1669. void PUBLIC Astexec_SendString(
  1670. PASTEXEC this,
  1671. LPCSTR pszSend,
  1672. BOOL bRaw) // TRUE: send unformatted
  1673. {
  1674. // Send string
  1675. LPCSTR psz;
  1676. char ch;
  1677. HWND hwnd = this->hwnd;
  1678. // Send unformatted?
  1679. if (bRaw)
  1680. {
  1681. // Yes
  1682. for (psz = pszSend; *psz; )
  1683. {
  1684. ch = *psz;
  1685. psz++;
  1686. SendByte(hwnd, ch);
  1687. }
  1688. }
  1689. else
  1690. {
  1691. // No
  1692. DWORD dwFlags = 0;
  1693. for (psz = pszSend; *psz; )
  1694. {
  1695. psz = MyNextChar(psz, &ch, &dwFlags);
  1696. SendByte(hwnd, ch);
  1697. }
  1698. }
  1699. }
  1700. /*----------------------------------------------------------
  1701. Purpose: Destroy the find format handle
  1702. Returns: RES_OK
  1703. Cond: --
  1704. */
  1705. RES PUBLIC Astexec_DestroyFindFormat(
  1706. PASTEXEC this)
  1707. {
  1708. // Reset the pending statement so we can handle multiple
  1709. // expressions that can pend in a single evaluation.
  1710. Astexec_SetPending(this, NULL);
  1711. DestroyFindFormat(this->hFindFmt);
  1712. this->hFindFmt = NULL;
  1713. return RES_OK;
  1714. }
  1715. /*----------------------------------------------------------
  1716. Purpose: Make another pass at finding a string.
  1717. Returns: RES_OK (if string was found)
  1718. RES_FALSE (if the string was not found yet)
  1719. Cond: --
  1720. */
  1721. RES PUBLIC Astexec_FindFormat(
  1722. PASTEXEC this,
  1723. LPDWORD piFound)
  1724. {
  1725. RES res;
  1726. ASSERT(piFound);
  1727. while (TRUE)
  1728. {
  1729. // Did we get the IP address?
  1730. res = FindFormat(this->hwnd, this->hFindFmt, piFound);
  1731. if (RES_OK == res)
  1732. {
  1733. // Yes
  1734. this->nIter--;
  1735. ASSERT(0 <= this->nIter);
  1736. // Is this the right one?
  1737. if (0 >= this->nIter)
  1738. {
  1739. // Yes; reset the pending statement so we
  1740. // can handle multiple pending expressions
  1741. // in a single evaluation.
  1742. Astexec_DestroyFindFormat(this);
  1743. break;
  1744. }
  1745. }
  1746. else
  1747. {
  1748. // No; return read-pending RES_FALSE
  1749. if (RES_E_MOREDATA == res)
  1750. {
  1751. TRACE_MSG(TF_GENERAL, "Buffer to FindFormat is too small");
  1752. res = RES_OK; // don't blow up
  1753. }
  1754. break;
  1755. }
  1756. }
  1757. ASSERT(RSUCCEEDED(res));
  1758. return res;
  1759. }
  1760. /*----------------------------------------------------------
  1761. Purpose: Sets the IP address.
  1762. Returns: RES_OK
  1763. RES_E_FAIL (if IP address cannot be set)
  1764. Cond: --
  1765. */
  1766. RES PUBLIC Astexec_SetIPAddr(
  1767. PASTEXEC this,
  1768. LPCSTR psz)
  1769. {
  1770. DWORD dwRet;
  1771. ASSERT(this);
  1772. ASSERT(psz);
  1773. TRACE_MSG(TF_GENERAL, "Setting IP address to {%s}", psz);
  1774. #ifndef WINNT_RAS
  1775. //
  1776. // On NT, the IP address is set by calling RxSetIPAddress,
  1777. // which writes a new value to the phonebook if the connection uses SLIP.
  1778. //
  1779. dwRet = TerminalSetIP(this->hwnd, psz);
  1780. #else // !WINNT_RAS
  1781. dwRet = RxSetIPAddress(((SCRIPTDATA*)this->hwnd)->hscript, psz);
  1782. #endif // !WINNT_RAS
  1783. return ERROR_SUCCESS == dwRet ? RES_OK : RES_E_FAIL;
  1784. }
  1785. #define Astexec_Validate(this) ((this)->hpaPcode && (this)->psci)
  1786. /*----------------------------------------------------------
  1787. Purpose: Returns the source line number of the current
  1788. command that is executing.
  1789. Returns: see above
  1790. Cond: --
  1791. */
  1792. DWORD PUBLIC Astexec_GetCurLine(
  1793. PASTEXEC this)
  1794. {
  1795. DWORD iLine;
  1796. if (Astexec_Validate(this) &&
  1797. (this->ipaCur < PAGetCount(this->hpaPcode)))
  1798. {
  1799. PSTMT pstmt = PAFastGetPtr(this->hpaPcode, this->ipaCur);
  1800. iLine = Ast_GetLine(pstmt);
  1801. }
  1802. else
  1803. iLine = 0;
  1804. return iLine;
  1805. }
  1806. /*----------------------------------------------------------
  1807. Purpose: Execute a statement and process the results.
  1808. Returns: RES_OK
  1809. other error values
  1810. Cond: --
  1811. */
  1812. RES PRIVATE Astexec_ProcessStmt(
  1813. PASTEXEC this,
  1814. PSTMT pstmt)
  1815. {
  1816. RES res;
  1817. ASSERT(this);
  1818. ASSERT(pstmt);
  1819. // (Re-)Execute the (possibly pending) statement
  1820. res = Stmt_Exec(pstmt, this);
  1821. // Set the pending statement based on the return value
  1822. if (RES_OK == res)
  1823. Astexec_SetPending(this, NULL);
  1824. else if (RES_FALSE == res)
  1825. {
  1826. // (Re-set the current pending statement since
  1827. // it could have been reset in Stmt_Exec. For
  1828. // example, the evaluation of an expression could
  1829. // have continued on to the next sub-expression
  1830. // that caused another pending read.)
  1831. Astexec_SetPending(this, pstmt);
  1832. res = RES_OK;
  1833. }
  1834. else if (RFAILED(res))
  1835. {
  1836. Stxerr_ShowErrors(this->hsaStxerr, this->hwnd);
  1837. // Halt script
  1838. SetFlag(this->dwFlags, AEF_HALT);
  1839. }
  1840. return res;
  1841. }
  1842. /*----------------------------------------------------------
  1843. Purpose: Executes the next command in the AST.
  1844. Returns: RES_OK
  1845. RES_FALSE (if at end of script)
  1846. RES_HALT (if at end of script)
  1847. RES_E_FAIL (invalid command -- should never happen)
  1848. RES_E_INVALIDPARAM
  1849. Cond: --
  1850. */
  1851. RES PUBLIC Astexec_Next(
  1852. PASTEXEC this)
  1853. {
  1854. RES res;
  1855. DBG_ENTER(Astexec_Next);
  1856. if (this)
  1857. {
  1858. if (!Astexec_Validate(this))
  1859. {
  1860. // No script
  1861. res = RES_E_FAIL;
  1862. }
  1863. else if (Astexec_IsDone(this) || Astexec_IsHalted(this))
  1864. {
  1865. res = RES_HALT;
  1866. }
  1867. else if (Astexec_IsReadPending(this))
  1868. {
  1869. PSTMT pstmt = Astexec_GetPending(this);
  1870. // ("Read pending" and "Paused" are mutually exclusive)
  1871. ASSERT( !Astexec_IsPaused(this) );
  1872. res = Astexec_ProcessStmt(this, pstmt);
  1873. }
  1874. else if (Astexec_IsPaused(this))
  1875. {
  1876. // ("Read pending" and "Paused" are mutually exclusive)
  1877. ASSERT( !Astexec_IsReadPending(this) );
  1878. // Do nothing while we're paused
  1879. res = RES_OK;
  1880. }
  1881. else if (this->ipaCur < PAGetCount(this->hpaPcode))
  1882. {
  1883. PSTMT pstmt = PAFastGetPtr(this->hpaPcode, this->ipaCur++);
  1884. res = Astexec_ProcessStmt(this, pstmt);
  1885. }
  1886. else
  1887. {
  1888. // We reach here if there is an error in the script.
  1889. TRACE_MSG(TF_ASTEXEC, "Exec: (reached end of script)");
  1890. SetFlag(this->dwFlags, AEF_DONE);
  1891. res = RES_HALT;
  1892. }
  1893. }
  1894. else
  1895. res = RES_E_INVALIDPARAM;
  1896. DBG_EXIT_RES(Astexec_Next, res);
  1897. return res;
  1898. }