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.

2172 lines
50 KiB

  1. //
  2. // Copyright (c) Microsoft Corporation 1995
  3. //
  4. // parser.c
  5. //
  6. // This file contains the parsing functions.
  7. //
  8. // Conventions:
  9. //
  10. // <Foo> where Foo is a non-terminal
  11. // { Bar } where there are 0 or more occurrences of Bar
  12. // "x" where x is the literal character/string
  13. // CAPS where CAPS is a token type
  14. //
  15. // The grammar is as follows:
  16. //
  17. // <ModuleDecl> ::= { <ProcDecl> }
  18. // <ProcDecl> ::= proc IDENT { <VarDecl> } <StmtBlock> endproc
  19. // <VarDecl> ::= <VarType> IDENT [ = <Expr> ]
  20. // <VarType> ::= integer | string | boolean
  21. //
  22. // <StmtBlock> ::= { <Stmt> }
  23. // <Stmt> ::= <HaltStmt> | <WaitforStmt> | <TransmitStmt> |
  24. // <DelayStmt> | <SetStmt> | <LabelStmt> |
  25. // <GotoStmt> | <AssignStmt> | <WhileStmt> |
  26. // <IfStmt>
  27. //
  28. // <HaltStmt> ::= halt
  29. // <WaitforStmt> ::= waitfor <Expr> [ , matchcase ]
  30. // [ then IDENT
  31. // { , <Expr> [ , matchcase ] then IDENT } ]
  32. // [ until <Expr> ]
  33. // <TransmitStmt> ::= transmit <Expr> [ , raw ]
  34. // <DelayStmt> ::= delay <Expr>
  35. // <SetStmt> ::= set <SetParam>
  36. // <AssignStmt> ::= IDENT = <Expr>
  37. // <LabelStmt> ::= IDENT :
  38. // <GotoStmt> ::= goto IDENT
  39. // <WhileStmt> ::= while <Expr> do <StmtBlock> endwhile
  40. // <IfStmt> ::= if <Expr> then <StmtBlock> endif
  41. //
  42. // <SetParam> ::= ipaddr <Expr> | port <PortData> |
  43. // screen <ScreenSet>
  44. // <PortData> ::= databits <DataBitsExpr> | parity <ParityExpr> |
  45. // stopbits <StopBitsExpr>
  46. // <ScreenSet> ::= keyboard <KeybrdExpr>
  47. //
  48. // <ExprList> ::= <Expr> { , <Expr> }
  49. // <Expr> ::= <ConjExpr> { or <ConjExpr> }
  50. // <ConjExpr> ::= <TestExpr> { and <TestExpr> }
  51. // <TestExpr> ::= <Sum> <RelOp> <Sum> | <Sum>
  52. // <RelOp> ::= <= | != | < | >= | > | ==
  53. // <Sum> ::= <Term> { (+|-) <Term> }
  54. // <Term> ::= <Factor> { (*|/) <Factor> }
  55. // <Factor> ::= - <Factor> | INT | "(" <Expr> ")" | IDENT |
  56. // STRING | <GetIPExpr> | "TRUE" | "FALSE" |
  57. // ! <Factor>
  58. // <GetIPExpr> ::= getip [ <Expr> ]
  59. //
  60. // <DataBitsExpr> ::= 5 | 6 | 7 | 8
  61. // <ParityExpr> ::= none | odd | even | mark | space
  62. // <StopBitsExpr> ::= 1 | 2
  63. // <KeybrdExpr> ::= on | off
  64. //
  65. //
  66. // History:
  67. // 05-20-95 ScottH Created
  68. //
  69. #include "proj.h"
  70. #include "rcids.h"
  71. RES PRIVATE StmtBlock_Parse(HPA hpa, PSCANNER pscanner, PSYMTAB pstProc, SYM symEnd);
  72. /*----------------------------------------------------------
  73. Purpose: Parses the next token as an identifier. If the
  74. token is an identifier, it is returned in *pptok
  75. and the function returns RES_OK.
  76. Otherwise, *pptok is NULL and an error is returned.
  77. Returns: RES_OK
  78. RES_E_IDENTMISSING
  79. Cond: The caller must destroy *pptok if RES_OK is returned.
  80. */
  81. RES PRIVATE Ident_Parse(
  82. PSCANNER pscanner,
  83. PTOK * pptok)
  84. {
  85. RES res;
  86. PTOK ptok;
  87. *pptok = NULL;
  88. res = Scanner_GetToken(pscanner, &ptok);
  89. if (RSUCCEEDED(res))
  90. {
  91. if (SYM_IDENT == Tok_GetSym(ptok))
  92. {
  93. res = RES_OK;
  94. *pptok = ptok;
  95. }
  96. else
  97. {
  98. res = Scanner_AddError(pscanner, NULL, RES_E_IDENTMISSING);
  99. Tok_Delete(ptok);
  100. }
  101. }
  102. return res;
  103. }
  104. /*----------------------------------------------------------
  105. Purpose: Adds an identifier to the symbol table. If the
  106. identifier has already been defined in this scope,
  107. this function adds the error to the error list,
  108. and returns the error value.
  109. Returns: RES_OK
  110. RES_E_REDEFINED
  111. RES_E_OUTOFMEMORY
  112. Cond: --
  113. */
  114. RES PRIVATE Ident_Add(
  115. LPCSTR pszIdent,
  116. DATATYPE dt,
  117. PTOK ptok,
  118. PSCANNER pscanner,
  119. PSYMTAB pst)
  120. {
  121. RES res;
  122. // Is this identifier unique?
  123. if (RES_OK == Symtab_FindEntry(pst, pszIdent, STFF_DEFAULT, NULL, NULL))
  124. {
  125. // No; we have a redefinition
  126. res = Scanner_AddError(pscanner, ptok, RES_E_REDEFINED);
  127. }
  128. else
  129. {
  130. // Yes; add to symbol table
  131. PSTE pste;
  132. res = STE_Create(&pste, pszIdent, dt);
  133. if (RSUCCEEDED(res))
  134. {
  135. res = Symtab_InsertEntry(pst, pste);
  136. }
  137. }
  138. return res;
  139. }
  140. //
  141. // Exprs
  142. //
  143. RES PRIVATE Expr_Parse(PEXPR * ppexpr, PSCANNER pscanner, PSYMTAB pst);
  144. /*----------------------------------------------------------
  145. Purpose: Look ahead to see if the next token indicates an
  146. expression of some kind.
  147. Returns: TRUE if the next token is a leader to an expression
  148. Cond: --
  149. */
  150. BOOL PRIVATE IsExprSneakPeek(
  151. PSCANNER pscanner)
  152. {
  153. BOOL bRet;
  154. SYM sym;
  155. Scanner_Peek(pscanner, &sym);
  156. switch (sym)
  157. {
  158. case SYM_MINUS:
  159. case SYM_NOT:
  160. case SYM_INT_LITERAL:
  161. case SYM_LPAREN:
  162. case SYM_STRING_LITERAL:
  163. case SYM_GETIP:
  164. case SYM_IDENT:
  165. case SYM_TRUE:
  166. case SYM_FALSE:
  167. bRet = TRUE;
  168. break;
  169. default:
  170. bRet = FALSE;
  171. break;
  172. }
  173. return bRet;
  174. }
  175. /*----------------------------------------------------------
  176. Purpose: Parses a factor expression.
  177. Grammar is:
  178. <Factor> ::= - <Factor> | INT | "(" <Expr> ")" | IDENT |
  179. STRING | <GetIPExpr> | TRUE | FALSE |
  180. ! <Factor>
  181. <GetIPExpr> ::= getip [ <Expr> ]
  182. Returns: RES_OK
  183. Cond: --
  184. */
  185. RES PRIVATE FactorExpr_Parse(
  186. PEXPR * ppexpr,
  187. PSCANNER pscanner,
  188. PSYMTAB pst)
  189. {
  190. RES res;
  191. PEXPR pexpr;
  192. PTOK ptok;
  193. DWORD iLine = Scanner_GetLine(pscanner);
  194. DBG_ENTER(FactorExpr_Parse);
  195. ASSERT(ppexpr);
  196. ASSERT(pscanner);
  197. *ppexpr = NULL;
  198. if (RES_OK == Scanner_CondReadToken(pscanner, SYM_MINUS, NULL))
  199. {
  200. // Negation
  201. res = FactorExpr_Parse(&pexpr, pscanner, pst);
  202. if (RSUCCEEDED(res))
  203. {
  204. res = UnOpExpr_New(ppexpr, UOT_NEG, pexpr, iLine);
  205. if (RFAILED(res))
  206. Expr_Delete(pexpr);
  207. }
  208. }
  209. else if (RES_OK == Scanner_CondReadToken(pscanner, SYM_NOT, NULL))
  210. {
  211. // One's complement
  212. res = FactorExpr_Parse(&pexpr, pscanner, pst);
  213. if (RSUCCEEDED(res))
  214. {
  215. res = UnOpExpr_New(ppexpr, UOT_NOT, pexpr, iLine);
  216. if (RFAILED(res))
  217. Expr_Delete(pexpr);
  218. }
  219. }
  220. else if (RES_OK == Scanner_CondReadToken(pscanner, SYM_LPAREN, NULL))
  221. {
  222. // "("
  223. res = Expr_Parse(ppexpr, pscanner, pst);
  224. if (RSUCCEEDED(res))
  225. {
  226. if (RES_OK != Scanner_ReadToken(pscanner, SYM_RPAREN))
  227. {
  228. Expr_Delete(*ppexpr);
  229. res = Scanner_AddError(pscanner, NULL, RES_E_RPARENMISSING);
  230. }
  231. }
  232. }
  233. else if (RES_OK == Scanner_CondReadToken(pscanner, SYM_INT_LITERAL, &ptok))
  234. {
  235. // Integer literal
  236. res = IntExpr_New(ppexpr, TokInt_GetVal(ptok), iLine);
  237. Tok_Delete(ptok);
  238. }
  239. else if (RES_OK == Scanner_CondReadToken(pscanner, SYM_STRING_LITERAL, &ptok))
  240. {
  241. res = StrExpr_New(ppexpr, TokSz_GetSz(ptok), iLine);
  242. Tok_Delete(ptok);
  243. }
  244. else if (RES_OK == Scanner_CondReadToken(pscanner, SYM_TRUE, &ptok))
  245. {
  246. res = BoolExpr_New(ppexpr, TRUE, iLine);
  247. Tok_Delete(ptok);
  248. }
  249. else if (RES_OK == Scanner_CondReadToken(pscanner, SYM_FALSE, &ptok))
  250. {
  251. res = BoolExpr_New(ppexpr, FALSE, iLine);
  252. Tok_Delete(ptok);
  253. }
  254. else if (RES_OK == Scanner_CondReadToken(pscanner, SYM_IDENT, &ptok))
  255. {
  256. res = VarExpr_New(ppexpr, Tok_GetLexeme(ptok), iLine);
  257. Tok_Delete(ptok);
  258. }
  259. else if (RES_OK == Scanner_CondReadToken(pscanner, SYM_GETIP, NULL))
  260. {
  261. // 'getip'
  262. // Parse optional nth parameter
  263. if (IsExprSneakPeek(pscanner))
  264. {
  265. res = Expr_Parse(&pexpr, pscanner, pst);
  266. if (RSUCCEEDED(res))
  267. {
  268. res = UnOpExpr_New(ppexpr, UOT_GETIP, pexpr, iLine);
  269. }
  270. }
  271. else
  272. {
  273. // Default to 1st IP address
  274. res = IntExpr_New(&pexpr, 1, iLine);
  275. if (RSUCCEEDED(res))
  276. res = UnOpExpr_New(ppexpr, UOT_GETIP, pexpr, iLine);
  277. }
  278. }
  279. else
  280. res = Scanner_AddError(pscanner, NULL, RES_E_SYNTAXERROR);
  281. DBG_EXIT_RES(FactorExpr_Parse, res);
  282. return res;
  283. }
  284. /*----------------------------------------------------------
  285. Purpose: Parses a term expression.
  286. Grammar is:
  287. <Term> ::= <Factor> { (*|/) <Factor> }
  288. Returns: RES_OK
  289. Cond: --
  290. */
  291. RES PRIVATE TermExpr_Parse(
  292. PEXPR * ppexpr,
  293. PSCANNER pscanner,
  294. PSYMTAB pst)
  295. {
  296. RES res;
  297. PEXPR pexpr1;
  298. DBG_ENTER(TermExpr_Parse);
  299. ASSERT(ppexpr);
  300. ASSERT(pscanner);
  301. *ppexpr = NULL;
  302. // Parse factor expression
  303. res = FactorExpr_Parse(&pexpr1, pscanner, pst);
  304. if (RSUCCEEDED(res))
  305. {
  306. DWORD iLine = Scanner_GetLine(pscanner);
  307. PEXPR pexprTerm = pexpr1;
  308. SYM sym;
  309. // Parse optional factor operator
  310. Scanner_Peek(pscanner, &sym);
  311. while (SYM_MULT == sym || SYM_DIV == sym)
  312. {
  313. PEXPR pexpr2;
  314. Scanner_ReadToken(pscanner, sym);
  315. res = FactorExpr_Parse(&pexpr2, pscanner, pst);
  316. if (RSUCCEEDED(res))
  317. {
  318. BINOPTYPE binoptype = sym - SYM_PLUS + BOT_PLUS;
  319. res = BinOpExpr_New(&pexprTerm, binoptype, pexpr1, pexpr2, iLine);
  320. if (RFAILED(res))
  321. {
  322. Expr_Delete(pexpr2);
  323. break;
  324. }
  325. }
  326. else
  327. break;
  328. pexpr1 = pexprTerm;
  329. Scanner_Peek(pscanner, &sym);
  330. }
  331. if (RFAILED(res))
  332. {
  333. Expr_Delete(pexpr1); // pexpr1 by design
  334. pexprTerm = NULL; // pexprTerm by design
  335. }
  336. *ppexpr = pexprTerm;
  337. }
  338. DBG_EXIT_RES(TermExpr_Parse, res);
  339. return res;
  340. }
  341. /*----------------------------------------------------------
  342. Purpose: Parses a sum expression.
  343. Grammar is:
  344. <Sum> ::= <Term> { (+|-) <Term> }
  345. Returns: RES_OK
  346. Cond: --
  347. */
  348. RES PRIVATE SumExpr_Parse(
  349. PEXPR * ppexpr,
  350. PSCANNER pscanner,
  351. PSYMTAB pst)
  352. {
  353. RES res;
  354. PEXPR pexpr1;
  355. DBG_ENTER(SumExpr_Parse);
  356. ASSERT(ppexpr);
  357. ASSERT(pscanner);
  358. *ppexpr = NULL;
  359. // Parse term expression
  360. res = TermExpr_Parse(&pexpr1, pscanner, pst);
  361. if (RSUCCEEDED(res))
  362. {
  363. DWORD iLine = Scanner_GetLine(pscanner);
  364. PEXPR pexprSum = pexpr1;
  365. SYM sym;
  366. // Parse optional sum operator
  367. Scanner_Peek(pscanner, &sym);
  368. while (SYM_PLUS == sym || SYM_MINUS == sym)
  369. {
  370. PEXPR pexpr2;
  371. Scanner_ReadToken(pscanner, sym);
  372. res = TermExpr_Parse(&pexpr2, pscanner, pst);
  373. if (RSUCCEEDED(res))
  374. {
  375. BINOPTYPE binoptype = sym - SYM_PLUS + BOT_PLUS;
  376. res = BinOpExpr_New(&pexprSum, binoptype, pexpr1, pexpr2, iLine);
  377. if (RFAILED(res))
  378. {
  379. Expr_Delete(pexpr2);
  380. break;
  381. }
  382. }
  383. else
  384. break;
  385. pexpr1 = pexprSum;
  386. Scanner_Peek(pscanner, &sym);
  387. }
  388. if (RFAILED(res))
  389. {
  390. Expr_Delete(pexpr1);
  391. pexprSum = NULL;
  392. }
  393. *ppexpr = pexprSum;
  394. }
  395. DBG_EXIT_RES(SumExpr_Parse, res);
  396. return res;
  397. }
  398. /*----------------------------------------------------------
  399. Purpose: Parses a test expression.
  400. Grammar is:
  401. <TestExpr> ::= <Sum> <RelOp> <Sum> | <Sum>
  402. <RelOp> ::= <= | != | < | >= | > | ==
  403. Returns: RES_OK
  404. Cond: --
  405. */
  406. RES PRIVATE TestExpr_Parse(
  407. PEXPR * ppexpr,
  408. PSCANNER pscanner,
  409. PSYMTAB pst)
  410. {
  411. RES res;
  412. PEXPR pexpr;
  413. DBG_ENTER(TestExpr_Parse);
  414. ASSERT(ppexpr);
  415. ASSERT(pscanner);
  416. *ppexpr = NULL;
  417. // Parse sum expression
  418. res = SumExpr_Parse(&pexpr, pscanner, pst);
  419. if (RSUCCEEDED(res))
  420. {
  421. DWORD iLine = Scanner_GetLine(pscanner);
  422. PEXPR pexpr2;
  423. SYM sym;
  424. // Parse optional relational operator
  425. Scanner_Peek(pscanner, &sym);
  426. switch (sym)
  427. {
  428. case SYM_LEQ:
  429. case SYM_NEQ:
  430. case SYM_LT:
  431. case SYM_GEQ:
  432. case SYM_GT:
  433. case SYM_EQ:
  434. Scanner_ReadToken(pscanner, sym);
  435. res = SumExpr_Parse(&pexpr2, pscanner, pst);
  436. if (RSUCCEEDED(res))
  437. {
  438. BINOPTYPE binoptype = sym - SYM_LEQ + BOT_LEQ;
  439. res = BinOpExpr_New(ppexpr, binoptype, pexpr, pexpr2, iLine);
  440. if (RFAILED(res))
  441. Expr_Delete(pexpr2);
  442. }
  443. break;
  444. default:
  445. *ppexpr = pexpr;
  446. break;
  447. }
  448. if (RFAILED(res))
  449. Expr_Delete(pexpr);
  450. }
  451. DBG_EXIT_RES(TestExpr_Parse, res);
  452. return res;
  453. }
  454. /*----------------------------------------------------------
  455. Purpose: Parses a conjunction expression.
  456. Grammar is:
  457. <ConjExpr> ::= <TestExpr> { and <TestExpr> }
  458. Returns: RES_OK
  459. Cond: --
  460. */
  461. RES PRIVATE ConjExpr_Parse(
  462. PEXPR * ppexpr,
  463. PSCANNER pscanner,
  464. PSYMTAB pst)
  465. {
  466. RES res;
  467. PEXPR pexpr1;
  468. DBG_ENTER(ConjExpr_Parse);
  469. ASSERT(ppexpr);
  470. ASSERT(pscanner);
  471. *ppexpr = NULL;
  472. // Parse test expression
  473. res = TestExpr_Parse(&pexpr1, pscanner, pst);
  474. if (RSUCCEEDED(res))
  475. {
  476. DWORD iLine = Scanner_GetLine(pscanner);
  477. PEXPR pexprConj = pexpr1;
  478. SYM sym;
  479. Scanner_Peek(pscanner, &sym);
  480. while (SYM_AND == sym)
  481. {
  482. PEXPR pexpr2;
  483. Scanner_ReadToken(pscanner, sym);
  484. res = TestExpr_Parse(&pexpr2, pscanner, pst);
  485. if (RSUCCEEDED(res))
  486. {
  487. res = BinOpExpr_New(&pexprConj, BOT_AND, pexpr1, pexpr2, iLine);
  488. if (RFAILED(res))
  489. {
  490. Expr_Delete(pexpr2);
  491. break;
  492. }
  493. }
  494. else
  495. break;
  496. pexpr1 = pexprConj;
  497. Scanner_Peek(pscanner, &sym);
  498. }
  499. if (RFAILED(res))
  500. {
  501. Expr_Delete(pexpr1);
  502. pexprConj = NULL;
  503. }
  504. *ppexpr = pexprConj;
  505. }
  506. DBG_EXIT_RES(ConjExpr_Parse, res);
  507. return res;
  508. }
  509. /*----------------------------------------------------------
  510. Purpose: Parses an expression.
  511. Grammar is:
  512. <Expr> ::= <ConjExpr> { or <ConjExpr> }
  513. Returns: RES_OK
  514. Cond: --
  515. */
  516. RES PRIVATE Expr_Parse(
  517. PEXPR * ppexpr,
  518. PSCANNER pscanner,
  519. PSYMTAB pst)
  520. {
  521. RES res;
  522. PEXPR pexpr1;
  523. DBG_ENTER(Expr_Parse);
  524. ASSERT(ppexpr);
  525. ASSERT(pscanner);
  526. *ppexpr = NULL;
  527. // Parse conjunction expression
  528. res = ConjExpr_Parse(&pexpr1, pscanner, pst);
  529. if (RSUCCEEDED(res))
  530. {
  531. DWORD iLine = Scanner_GetLine(pscanner);
  532. PEXPR pexprDisj = pexpr1;
  533. SYM sym;
  534. // Parse optional 'or'
  535. Scanner_Peek(pscanner, &sym);
  536. while (SYM_OR == sym)
  537. {
  538. PEXPR pexpr2;
  539. Scanner_ReadToken(pscanner, sym);
  540. res = ConjExpr_Parse(&pexpr2, pscanner, pst);
  541. if (RSUCCEEDED(res))
  542. {
  543. res = BinOpExpr_New(&pexprDisj, BOT_OR, pexpr1, pexpr2, iLine);
  544. if (RFAILED(res))
  545. {
  546. Expr_Delete(pexpr2);
  547. break;
  548. }
  549. }
  550. else
  551. break;
  552. pexpr1 = pexprDisj;
  553. Scanner_Peek(pscanner, &sym);
  554. }
  555. if (RFAILED(res))
  556. {
  557. Expr_Delete(pexpr1);
  558. pexprDisj = NULL;
  559. }
  560. *ppexpr = pexprDisj;
  561. }
  562. DBG_EXIT_RES(Expr_Parse, res);
  563. return res;
  564. }
  565. /*----------------------------------------------------------
  566. Purpose: Parses the 'set port' statement
  567. Grammar is:
  568. <PortData> ::= databits <DataBitsExpr> | parity <ParityExpr> |
  569. stopbits <StopBitsExpr>
  570. <DataBitsExpr> ::= 5 | 6 | 7 | 8
  571. <ParityExpr> ::= none | odd | even | mark | space
  572. <StopBitsExpr> ::= 1 | 2
  573. Returns: RES_OK
  574. Cond: --
  575. */
  576. RES PRIVATE PortData_Parse(
  577. PSTMT * ppstmt,
  578. PSCANNER pscanner,
  579. PSYMTAB pst)
  580. {
  581. RES res;
  582. DWORD iLine = Scanner_GetLine(pscanner);
  583. PORTSTATE ps;
  584. PTOK ptok;
  585. DBG_ENTER(PortData_Parse);
  586. ASSERT(ppstmt);
  587. ASSERT(pscanner);
  588. // Parse 'databits'
  589. if (RES_OK == Scanner_CondReadToken(pscanner, SYM_DATABITS, NULL))
  590. {
  591. ps.dwFlags = SPF_DATABITS;
  592. // Parse 5 | 6 | 7 | 8
  593. res = Scanner_GetToken(pscanner, &ptok);
  594. if (RSUCCEEDED(res))
  595. {
  596. if (TT_INT == Tok_GetType(ptok))
  597. {
  598. DWORD dwVal = TokInt_GetVal(ptok);
  599. if (InRange(dwVal, 5, 8))
  600. {
  601. // Create object
  602. ps.nDatabits = LOBYTE(LOWORD(dwVal));
  603. res = SetPortStmt_New(ppstmt, &ps, iLine);
  604. }
  605. else
  606. res = Scanner_AddError(pscanner, ptok, RES_E_INVALIDRANGE);
  607. }
  608. else
  609. res = Scanner_AddError(pscanner, ptok, RES_E_SYNTAXERROR);
  610. Tok_Delete(ptok);
  611. }
  612. else
  613. res = Scanner_AddError(pscanner, ptok, RES_E_INTMISSING);
  614. }
  615. // Parse 'parity'
  616. else if (RES_OK == Scanner_CondReadToken(pscanner, SYM_PARITY, NULL))
  617. {
  618. SYM sym;
  619. ps.dwFlags = SPF_PARITY;
  620. res = RES_OK; // assume success
  621. Scanner_Peek(pscanner, &sym);
  622. switch (sym)
  623. {
  624. case SYM_NONE:
  625. ps.nParity = NOPARITY;
  626. break;
  627. case SYM_ODD:
  628. ps.nParity = ODDPARITY;
  629. break;
  630. case SYM_EVEN:
  631. ps.nParity = EVENPARITY;
  632. break;
  633. case SYM_MARK:
  634. ps.nParity = MARKPARITY;
  635. break;
  636. case SYM_SPACE:
  637. ps.nParity = SPACEPARITY;
  638. break;
  639. default:
  640. res = Scanner_AddError(pscanner, NULL, RES_E_SYNTAXERROR);
  641. break;
  642. }
  643. if (RES_OK == res)
  644. {
  645. res = SetPortStmt_New(ppstmt, &ps, iLine);
  646. // eat token
  647. Scanner_GetToken(pscanner, &ptok);
  648. Tok_Delete(ptok);
  649. }
  650. }
  651. else if (RES_OK == Scanner_CondReadToken(pscanner, SYM_STOPBITS, NULL))
  652. {
  653. PTOK ptok;
  654. ps.dwFlags = SPF_STOPBITS;
  655. // Parse 1 | 2
  656. res = Scanner_GetToken(pscanner, &ptok);
  657. if (RSUCCEEDED(res))
  658. {
  659. if (TT_INT == Tok_GetType(ptok))
  660. {
  661. DWORD dwVal = TokInt_GetVal(ptok);
  662. if (InRange(dwVal, 1, 2))
  663. {
  664. // Create object
  665. ps.nStopbits = LOBYTE(LOWORD(dwVal));
  666. res = SetPortStmt_New(ppstmt, &ps, iLine);
  667. }
  668. else
  669. res = Scanner_AddError(pscanner, ptok, RES_E_INVALIDRANGE);
  670. }
  671. else
  672. res = Scanner_AddError(pscanner, ptok, RES_E_SYNTAXERROR);
  673. Tok_Delete(ptok);
  674. }
  675. else
  676. res = Scanner_AddError(pscanner, ptok, RES_E_INTMISSING);
  677. }
  678. else
  679. res = Scanner_AddError(pscanner, NULL, RES_E_INVALIDPORTPARAM);
  680. DBG_EXIT_RES(PortData_Parse, res);
  681. return res;
  682. }
  683. /*----------------------------------------------------------
  684. Purpose: Parses the 'set screen' statement
  685. Grammar is:
  686. <ScreenSet> ::= keyboard <KeybrdExpr>
  687. <KeybrdExpr> ::= on | off
  688. Returns: RES_OK
  689. Cond: --
  690. */
  691. RES PRIVATE ScreenSet_Parse(
  692. PSTMT * ppstmt,
  693. PSCANNER pscanner,
  694. PSYMTAB pst)
  695. {
  696. RES res;
  697. DWORD iLine = Scanner_GetLine(pscanner);
  698. SCREENSET ss;
  699. PTOK ptok;
  700. DBG_ENTER(ScreenSet_Parse);
  701. ASSERT(ppstmt);
  702. ASSERT(pscanner);
  703. // Parse 'keyboard'
  704. if (RES_OK == Scanner_CondReadToken(pscanner, SYM_KEYBRD, NULL))
  705. {
  706. SYM sym;
  707. ss.dwFlags = SPF_KEYBRD;
  708. res = RES_OK; // assume success
  709. Scanner_Peek(pscanner, &sym);
  710. switch (sym)
  711. {
  712. case SYM_ON:
  713. ss.fKBOn = TRUE;
  714. break;
  715. case SYM_OFF:
  716. ss.fKBOn = FALSE;
  717. break;
  718. default:
  719. res = Scanner_AddError(pscanner, NULL, RES_E_SYNTAXERROR);
  720. break;
  721. }
  722. if (RES_OK == res)
  723. {
  724. res = SetScreenStmt_New(ppstmt, &ss, iLine);
  725. // eat token
  726. Scanner_GetToken(pscanner, &ptok);
  727. Tok_Delete(ptok);
  728. }
  729. }
  730. else
  731. res = Scanner_AddError(pscanner, NULL, RES_E_INVALIDSCRNPARAM);
  732. DBG_EXIT_RES(ScreenSet_Parse, res);
  733. return res;
  734. }
  735. //
  736. // Stmt
  737. //
  738. /*----------------------------------------------------------
  739. Purpose: Parse the case-portion of the 'waitfor' statement.
  740. This portion is:
  741. <Expr> [ , matchcase ] [ then IDENT ]
  742. and:
  743. <Expr> [ , matchcase ] then IDENT
  744. Set bThenOptional to TRUE to parse the first case,
  745. FALSE to parse the second case.
  746. Returns: RES_OK
  747. RES_FALSE (if bThenOptional and "[ then IDENT ]" was not parsed)
  748. Cond: --
  749. */
  750. RES PUBLIC WaitforStmt_ParseCase(
  751. HSA hsa,
  752. PSCANNER pscanner,
  753. PSYMTAB pst,
  754. BOOL bThenOptional)
  755. {
  756. RES res;
  757. PEXPR pexpr;
  758. // Parse string expression
  759. res = Expr_Parse(&pexpr, pscanner, pst);
  760. if (RSUCCEEDED(res))
  761. {
  762. BOOL bParseThen;
  763. DWORD dwFlags = WCF_DEFAULT;
  764. // Parse optional ", matchcase"
  765. if (RES_OK == Scanner_CondReadToken(pscanner, SYM_COMMA, NULL))
  766. {
  767. if (RES_OK == Scanner_ReadToken(pscanner, SYM_MATCHCASE))
  768. SetFlag(dwFlags, WCF_MATCHCASE);
  769. else
  770. res = Scanner_AddError(pscanner, NULL, RES_E_SYNTAXERROR);
  771. }
  772. // Is 'then IDENT' optional?
  773. if (bThenOptional)
  774. {
  775. // Yes; determine whether to parse it
  776. SYM sym;
  777. Scanner_Peek(pscanner, &sym);
  778. bParseThen = (SYM_THEN == sym);
  779. if (!bParseThen)
  780. res = RES_FALSE;
  781. }
  782. else
  783. {
  784. // No; we don't have a choice, parse it
  785. bParseThen = TRUE;
  786. }
  787. if (bParseThen)
  788. {
  789. res = Scanner_ReadToken(pscanner, SYM_THEN);
  790. if (RSUCCEEDED(res))
  791. {
  792. PTOK ptok;
  793. // Parse identifier
  794. res = Ident_Parse(pscanner, &ptok);
  795. if (RSUCCEEDED(res))
  796. {
  797. // (Wait until typechecking phase to check for
  798. // existence of identifier)
  799. LPSTR pszIdent = Tok_GetLexeme(ptok);
  800. // Add this case to the list
  801. res = Waitcase_Add(hsa, pexpr, pszIdent, dwFlags);
  802. Tok_Delete(ptok);
  803. }
  804. }
  805. else
  806. res = Scanner_AddError(pscanner, NULL, RES_E_SYNTAXERROR);
  807. }
  808. else
  809. {
  810. // Add this case to the list
  811. res = Waitcase_Add(hsa, pexpr, NULL, dwFlags);
  812. }
  813. }
  814. return res;
  815. }
  816. /*----------------------------------------------------------
  817. Purpose: Parses the 'waitfor' statement
  818. Grammar is:
  819. <WaitforStmt> ::= waitfor <Expr> [ , matchcase ]
  820. [ then IDENT
  821. { , <Expr> [ , matchcase ] then IDENT } ]
  822. [ until <Expr> ]
  823. Returns: RES_OK
  824. Cond: --
  825. */
  826. RES PRIVATE WaitforStmt_Parse(
  827. PSTMT * ppstmt,
  828. PSCANNER pscanner,
  829. PSYMTAB pst)
  830. {
  831. RES res;
  832. DWORD iLine;
  833. HSA hsa;
  834. DBG_ENTER(WaitforStmt_Parse);
  835. ASSERT(ppstmt);
  836. ASSERT(pscanner);
  837. ASSERT(pst);
  838. iLine = Scanner_GetLine(pscanner);
  839. *ppstmt = NULL;
  840. // Parse 'waitfor'
  841. res = Scanner_ReadToken(pscanner, SYM_WAITFOR);
  842. ASSERT(RES_OK == res);
  843. res = Waitcase_Create(&hsa);
  844. if (RSUCCEEDED(res))
  845. {
  846. // Parse <Expr> [ , matchcase ] [ then IDENT { , <Expr> [ , matchcase ] then IDENT } ]
  847. // (Note we explicitly check for RES_OK only)
  848. res = WaitforStmt_ParseCase(hsa, pscanner, pst, TRUE);
  849. if (RES_OK == res)
  850. {
  851. // Parse { , <Expr> then IDENT }
  852. while (RES_OK == Scanner_CondReadToken(pscanner, SYM_COMMA, NULL))
  853. {
  854. res = WaitforStmt_ParseCase(hsa, pscanner, pst, FALSE);
  855. if (RFAILED(res))
  856. break;
  857. }
  858. }
  859. if (RSUCCEEDED(res))
  860. {
  861. PEXPR pexprUntil = NULL;
  862. // Parse optional 'until <Expr>'
  863. if (RES_OK == Scanner_CondReadToken(pscanner, SYM_UNTIL, NULL))
  864. {
  865. res = Expr_Parse(&pexprUntil, pscanner, pst);
  866. }
  867. if (RSUCCEEDED(res))
  868. {
  869. // Create object
  870. res = WaitforStmt_New(ppstmt, hsa, pexprUntil, iLine);
  871. }
  872. }
  873. if (RFAILED(res))
  874. Waitcase_Destroy(hsa);
  875. }
  876. DBG_EXIT_RES(WaitforStmt_Parse, res);
  877. return res;
  878. }
  879. /*----------------------------------------------------------
  880. Purpose: Parses the 'transmit' statement
  881. Grammar is:
  882. <TransmitStmt> ::= transmit <Expr> [ , raw ]
  883. Returns: RES_OK
  884. Cond: --
  885. */
  886. RES PRIVATE TransmitStmt_Parse(
  887. PSTMT * ppstmt,
  888. PSCANNER pscanner,
  889. PSYMTAB pst)
  890. {
  891. RES res;
  892. PEXPR pexpr;
  893. DWORD iLine;
  894. DWORD dwFlags = TSF_DEFAULT;
  895. DBG_ENTER(TransmitStmt_Parse);
  896. ASSERT(ppstmt);
  897. ASSERT(pscanner);
  898. ASSERT(pst);
  899. iLine = Scanner_GetLine(pscanner);
  900. *ppstmt = NULL;
  901. // Parse 'transmit'
  902. res = Scanner_ReadToken(pscanner, SYM_TRANSMIT);
  903. ASSERT(RES_OK == res);
  904. // Parse string expression
  905. res = Expr_Parse(&pexpr, pscanner, pst);
  906. if (RSUCCEEDED(res))
  907. {
  908. // Parse optional ", raw" parameter
  909. if (RES_OK == Scanner_CondReadToken(pscanner, SYM_COMMA, NULL))
  910. {
  911. if (RSUCCEEDED(Scanner_ReadToken(pscanner, SYM_RAW)))
  912. SetFlag(dwFlags, TSF_RAW);
  913. else
  914. res = Scanner_AddError(pscanner, NULL, RES_E_SYNTAXERROR);
  915. }
  916. if (RSUCCEEDED(res))
  917. {
  918. // Create object
  919. res = TransmitStmt_New(ppstmt, pexpr, dwFlags, iLine);
  920. }
  921. }
  922. else
  923. res = Scanner_AddError(pscanner, NULL, RES_E_STRINGMISSING);
  924. DBG_EXIT_RES(TransmitStmt_Parse, res);
  925. return res;
  926. }
  927. /*----------------------------------------------------------
  928. Purpose: Parses the 'delay' statement
  929. Grammar is:
  930. <DelayStmt> ::= delay <Expr>
  931. Returns: RES_OK
  932. Cond: --
  933. */
  934. RES PRIVATE DelayStmt_Parse(
  935. PSTMT * ppstmt,
  936. PSCANNER pscanner,
  937. PSYMTAB pst)
  938. {
  939. RES res;
  940. PEXPR pexpr;
  941. DWORD iLine = Scanner_GetLine(pscanner);
  942. DBG_ENTER(DelayStmt_Parse);
  943. ASSERT(ppstmt);
  944. ASSERT(pscanner);
  945. ASSERT(pst);
  946. *ppstmt = NULL;
  947. // Parse 'delay'
  948. res = Scanner_ReadToken(pscanner, SYM_DELAY);
  949. ASSERT(RES_OK == res);
  950. // Parse expression
  951. res = Expr_Parse(&pexpr, pscanner, pst);
  952. if (RSUCCEEDED(res))
  953. {
  954. res = DelayStmt_New(ppstmt, pexpr, iLine);
  955. }
  956. DBG_EXIT_RES(DelayStmt_Parse, res);
  957. return res;
  958. }
  959. /*----------------------------------------------------------
  960. Purpose: Parses the 'while' statement
  961. Grammar is:
  962. <WhileStmt> ::= while <Expr> do <StmtBlock> endwhile
  963. Returns: RES_OK
  964. Cond: --
  965. */
  966. RES PRIVATE WhileStmt_Parse(
  967. PSTMT * ppstmt,
  968. PSCANNER pscanner,
  969. PSYMTAB pst)
  970. {
  971. RES res;
  972. PEXPR pexpr;
  973. DWORD iLine;
  974. HPA hpa;
  975. DBG_ENTER(WhileStmt_Parse);
  976. ASSERT(ppstmt);
  977. ASSERT(pscanner);
  978. ASSERT(pst);
  979. iLine = Scanner_GetLine(pscanner);
  980. *ppstmt = NULL;
  981. if (PACreate(&hpa, 8))
  982. {
  983. // Parse 'while'
  984. res = Scanner_ReadToken(pscanner, SYM_WHILE);
  985. ASSERT(RES_OK == res);
  986. // Parse <Expr>
  987. res = Expr_Parse(&pexpr, pscanner, pst);
  988. if (RSUCCEEDED(res))
  989. {
  990. // Parse 'do'
  991. res = Scanner_ReadToken(pscanner, SYM_DO);
  992. if (RSUCCEEDED(res))
  993. {
  994. char szTop[MAX_BUF_KEYWORD];
  995. char szEnd[MAX_BUF_KEYWORD];
  996. // Generate unique label names
  997. res = Symtab_NewLabel(pst, szTop);
  998. if (RSUCCEEDED(res))
  999. {
  1000. res = Symtab_NewLabel(pst, szEnd);
  1001. if (RSUCCEEDED(res))
  1002. {
  1003. // Parse statement block
  1004. res = StmtBlock_Parse(hpa, pscanner, pst, SYM_ENDWHILE);
  1005. if (RSUCCEEDED(res))
  1006. {
  1007. PSTMT pstmtT;
  1008. // Add a goto statement to loop to the top again
  1009. res = GotoStmt_New(&pstmtT, szTop, Scanner_GetLine(pscanner));
  1010. if (RSUCCEEDED(res))
  1011. {
  1012. if (!PAInsertPtr(hpa, PA_APPEND, pstmtT))
  1013. res = RES_E_OUTOFMEMORY;
  1014. else
  1015. {
  1016. // Create object
  1017. res = WhileStmt_New(ppstmt, pexpr, hpa, szTop, szEnd, iLine);
  1018. }
  1019. }
  1020. }
  1021. }
  1022. }
  1023. }
  1024. else
  1025. res = Scanner_AddError(pscanner, NULL, RES_E_SYNTAXERROR);
  1026. }
  1027. }
  1028. else
  1029. res = RES_E_OUTOFMEMORY;
  1030. DBG_EXIT_RES(WhileStmt_Parse, res);
  1031. return res;
  1032. }
  1033. /*----------------------------------------------------------
  1034. Purpose: Parses the 'if' statement
  1035. Grammar is:
  1036. <IfStmt> ::= if <Expr> then <StmtBlock> endif
  1037. Returns: RES_OK
  1038. Cond: --
  1039. */
  1040. RES PRIVATE IfStmt_Parse(
  1041. PSTMT * ppstmt,
  1042. PSCANNER pscanner,
  1043. PSYMTAB pst)
  1044. {
  1045. RES res;
  1046. PEXPR pexpr;
  1047. DWORD iLine;
  1048. HPA hpa;
  1049. DBG_ENTER(IfStmt_Parse);
  1050. ASSERT(ppstmt);
  1051. ASSERT(pscanner);
  1052. ASSERT(pst);
  1053. iLine = Scanner_GetLine(pscanner);
  1054. *ppstmt = NULL;
  1055. if (PACreate(&hpa, 8))
  1056. {
  1057. // Parse 'if'
  1058. res = Scanner_ReadToken(pscanner, SYM_IF);
  1059. ASSERT(RES_OK == res);
  1060. // Parse <Expr>
  1061. res = Expr_Parse(&pexpr, pscanner, pst);
  1062. if (RSUCCEEDED(res))
  1063. {
  1064. // Parse 'then'
  1065. res = Scanner_ReadToken(pscanner, SYM_THEN);
  1066. if (RFAILED(res))
  1067. res = Scanner_AddError(pscanner, NULL, RES_E_SYNTAXERROR);
  1068. }
  1069. }
  1070. else
  1071. res = RES_E_OUTOFMEMORY;
  1072. if (RSUCCEEDED(res))
  1073. {
  1074. char szElse[MAX_BUF_KEYWORD];
  1075. char szEnd[MAX_BUF_KEYWORD];
  1076. // Generate unique label names
  1077. res = Symtab_NewLabel(pst, szElse);
  1078. if (RSUCCEEDED(res))
  1079. {
  1080. res = Symtab_NewLabel(pst, szEnd);
  1081. if (RSUCCEEDED(res))
  1082. {
  1083. // Parse statement block for the 'then' block
  1084. res = StmtBlock_Parse(hpa, pscanner, pst, SYM_ENDIF);
  1085. if (RSUCCEEDED(res))
  1086. {
  1087. // Create object
  1088. res = IfStmt_New(ppstmt, pexpr, hpa, szElse, szEnd, iLine);
  1089. }
  1090. }
  1091. }
  1092. }
  1093. DBG_EXIT_RES(IfStmt_Parse, res);
  1094. return res;
  1095. }
  1096. /*----------------------------------------------------------
  1097. Purpose: Parses the 'halt' statement
  1098. Grammar is:
  1099. <HaltStmt> ::= halt
  1100. Returns: RES_OK
  1101. Cond: --
  1102. */
  1103. RES PRIVATE HaltStmt_Parse(
  1104. PSTMT * ppstmt,
  1105. PSCANNER pscanner,
  1106. PSYMTAB pst)
  1107. {
  1108. RES res;
  1109. DWORD iLine = Scanner_GetLine(pscanner);
  1110. DBG_ENTER(HaltStmt_Parse);
  1111. ASSERT(ppstmt);
  1112. ASSERT(pscanner);
  1113. ASSERT(pst);
  1114. *ppstmt = NULL;
  1115. // Parse 'halt'
  1116. res = Scanner_ReadToken(pscanner, SYM_HALT);
  1117. ASSERT(RES_OK == res);
  1118. // Create object
  1119. res = HaltStmt_New(ppstmt, iLine);
  1120. DBG_EXIT_RES(HaltStmt_Parse, res);
  1121. return res;
  1122. }
  1123. /*----------------------------------------------------------
  1124. Purpose: Parses the assignment statement
  1125. Grammar is:
  1126. <AssignStmt> ::= IDENT = <Expr>
  1127. Returns: RES_OK
  1128. Cond: --
  1129. */
  1130. RES PRIVATE AssignStmt_Parse(
  1131. PSTMT * ppstmt,
  1132. PTOK ptok,
  1133. PSCANNER pscanner,
  1134. PSYMTAB pst)
  1135. {
  1136. RES res;
  1137. DWORD iLine;
  1138. PEXPR pexpr;
  1139. DBG_ENTER(AssignStmt_Parse);
  1140. ASSERT(ppstmt);
  1141. ASSERT(ptok);
  1142. ASSERT(pscanner);
  1143. ASSERT(pst);
  1144. iLine = Scanner_GetLine(pscanner);
  1145. // (We already have the IDENT in the ptok passed in. We
  1146. // also already parsed the '='. Skip parsing these.)
  1147. // Parse <Expr>
  1148. res = Expr_Parse(&pexpr, pscanner, pst);
  1149. if (RSUCCEEDED(res))
  1150. {
  1151. // (Wait until typechecking phase to check for existence
  1152. // of identifier)
  1153. LPSTR pszIdent = Tok_GetLexeme(ptok);
  1154. // Create object
  1155. res = AssignStmt_New(ppstmt, pszIdent, pexpr, iLine);
  1156. }
  1157. DBG_EXIT_RES(AssignStmt_Parse, res);
  1158. return res;
  1159. }
  1160. /*----------------------------------------------------------
  1161. Purpose: Parses the label statement
  1162. Grammar is:
  1163. <LabelStmt> ::= IDENT :
  1164. Returns: RES_OK
  1165. Cond: --
  1166. */
  1167. RES PRIVATE LabelStmt_Parse(
  1168. PSTMT * ppstmt,
  1169. PTOK ptok,
  1170. PSCANNER pscanner,
  1171. PSYMTAB pst)
  1172. {
  1173. RES res;
  1174. DWORD iLine;
  1175. LPSTR pszIdent;
  1176. DBG_ENTER(LabelStmt_Parse);
  1177. ASSERT(ppstmt);
  1178. ASSERT(ptok);
  1179. ASSERT(pscanner);
  1180. ASSERT(pst);
  1181. iLine = Scanner_GetLine(pscanner);
  1182. pszIdent = Tok_GetLexeme(ptok);
  1183. res = Ident_Add(pszIdent, DATA_LABEL, ptok, pscanner, pst);
  1184. if (RSUCCEEDED(res))
  1185. {
  1186. // Create label object
  1187. res = LabelStmt_New(ppstmt, pszIdent, iLine);
  1188. }
  1189. DBG_EXIT_RES(LabelStmt_Parse, res);
  1190. return res;
  1191. }
  1192. /*----------------------------------------------------------
  1193. Purpose: Parses the 'goto' statement
  1194. Grammar is:
  1195. <GotoStmt> ::= goto IDENT
  1196. Returns: RES_OK
  1197. Cond: --
  1198. */
  1199. RES PRIVATE GotoStmt_Parse(
  1200. PSTMT * ppstmt,
  1201. PSCANNER pscanner,
  1202. PSYMTAB pst)
  1203. {
  1204. RES res;
  1205. DWORD iLine = Scanner_GetLine(pscanner);
  1206. PTOK ptok;
  1207. DBG_ENTER(GotoStmt_Parse);
  1208. ASSERT(ppstmt);
  1209. ASSERT(pscanner);
  1210. ASSERT(pst);
  1211. // Parse 'goto'
  1212. res = Scanner_ReadToken(pscanner, SYM_GOTO);
  1213. ASSERT(RES_OK == res);
  1214. // Parse identifier
  1215. res = Ident_Parse(pscanner, &ptok);
  1216. if (RSUCCEEDED(res))
  1217. {
  1218. // (Wait until typechecking phase to check for existence
  1219. // of identifier)
  1220. LPSTR pszIdent = Tok_GetLexeme(ptok);
  1221. // Create object
  1222. res = GotoStmt_New(ppstmt, pszIdent, iLine);
  1223. Tok_Delete(ptok);
  1224. }
  1225. DBG_EXIT_RES(GotoStmt_Parse, res);
  1226. return res;
  1227. }
  1228. /*----------------------------------------------------------
  1229. Purpose: Parses the 'set' statement
  1230. Grammar is:
  1231. <SetStmt> ::= set <SetParam>
  1232. <SetParam> ::= ipaddr <Expr> | port <PortData> |
  1233. screen <ScreenSet>
  1234. Returns: RES_OK
  1235. Cond: --
  1236. */
  1237. RES PRIVATE SetStmt_Parse(
  1238. PSTMT * ppstmt,
  1239. PSCANNER pscanner,
  1240. PSYMTAB pst)
  1241. {
  1242. RES res;
  1243. DBG_ENTER(SetStmt_Parse);
  1244. ASSERT(ppstmt);
  1245. ASSERT(pscanner);
  1246. ASSERT(pst);
  1247. *ppstmt = NULL;
  1248. // Parse 'set'
  1249. res = Scanner_ReadToken(pscanner, SYM_SET);
  1250. ASSERT(RES_OK == res);
  1251. // Parse set parameter
  1252. if (RES_OK == Scanner_CondReadToken(pscanner, SYM_IPADDR, NULL))
  1253. {
  1254. // Parse <Expr>
  1255. PEXPR pexpr;
  1256. DWORD iLine = Scanner_GetLine(pscanner);
  1257. res = Expr_Parse(&pexpr, pscanner, pst);
  1258. if (RSUCCEEDED(res))
  1259. {
  1260. res = SetIPStmt_New(ppstmt, pexpr, iLine);
  1261. }
  1262. }
  1263. else if (RES_OK == Scanner_CondReadToken(pscanner, SYM_PORT, NULL))
  1264. {
  1265. res = PortData_Parse(ppstmt, pscanner, pst);
  1266. }
  1267. else if (RES_OK == Scanner_CondReadToken(pscanner, SYM_SCREEN, NULL))
  1268. {
  1269. res = ScreenSet_Parse(ppstmt, pscanner, pst);
  1270. }
  1271. else
  1272. {
  1273. res = Scanner_AddError(pscanner, NULL, RES_E_INVALIDSETPARAM);
  1274. }
  1275. DBG_EXIT_RES(SetStmt_Parse, res);
  1276. return res;
  1277. }
  1278. /*----------------------------------------------------------
  1279. Purpose: Parses a statement.
  1280. Grammar is:
  1281. <Stmt> ::= <HaltStmt> | <WaitforStmt> | <TransmitStmt> |
  1282. <DelayStmt> | <SetStmt> | <LabelStmt> |
  1283. <GotoStmt> | <AssignStmt> | <WhileStmt> |
  1284. <IfStmt>
  1285. Returns: RES_OK
  1286. Cond: --
  1287. */
  1288. RES PRIVATE Stmt_Parse(
  1289. PSTMT * ppstmt,
  1290. PSCANNER pscanner,
  1291. PSYMTAB pst)
  1292. {
  1293. RES res;
  1294. SYM sym;
  1295. PTOK ptok;
  1296. DBG_ENTER(Stmt_Parse);
  1297. ASSERT(ppstmt);
  1298. ASSERT(pscanner);
  1299. ASSERT(pst);
  1300. *ppstmt = NULL;
  1301. Scanner_Peek(pscanner, &sym);
  1302. switch (sym)
  1303. {
  1304. case SYM_WHILE:
  1305. res = WhileStmt_Parse(ppstmt, pscanner, pst);
  1306. break;
  1307. case SYM_IF:
  1308. res = IfStmt_Parse(ppstmt, pscanner, pst);
  1309. break;
  1310. case SYM_WAITFOR:
  1311. res = WaitforStmt_Parse(ppstmt, pscanner, pst);
  1312. break;
  1313. case SYM_TRANSMIT:
  1314. res = TransmitStmt_Parse(ppstmt, pscanner, pst);
  1315. break;
  1316. case SYM_DELAY:
  1317. res = DelayStmt_Parse(ppstmt, pscanner, pst);
  1318. break;
  1319. case SYM_HALT:
  1320. res = HaltStmt_Parse(ppstmt, pscanner, pst);
  1321. break;
  1322. case SYM_SET:
  1323. res = SetStmt_Parse(ppstmt, pscanner, pst);
  1324. break;
  1325. case SYM_IDENT:
  1326. // This can be a label or an assignment
  1327. res = Scanner_GetToken(pscanner, &ptok);
  1328. ASSERT(RES_OK == res);
  1329. if (RSUCCEEDED(res))
  1330. {
  1331. // Is this a label?
  1332. if (RES_OK == Scanner_CondReadToken(pscanner, SYM_COLON, NULL))
  1333. {
  1334. // Yes
  1335. res = LabelStmt_Parse(ppstmt, ptok, pscanner, pst);
  1336. }
  1337. // Is this an assignment?
  1338. else if (RES_OK == Scanner_CondReadToken(pscanner, SYM_ASSIGN, NULL))
  1339. {
  1340. // Yes
  1341. res = AssignStmt_Parse(ppstmt, ptok, pscanner, pst);
  1342. }
  1343. else
  1344. {
  1345. res = Scanner_AddError(pscanner, NULL, RES_E_SYNTAXERROR);
  1346. }
  1347. Tok_Delete(ptok);
  1348. }
  1349. break;
  1350. case SYM_GOTO:
  1351. res = GotoStmt_Parse(ppstmt, pscanner, pst);
  1352. break;
  1353. case SYM_EOF:
  1354. res = Scanner_AddError(pscanner, NULL, RES_E_EOFUNEXPECTED);
  1355. break;
  1356. default:
  1357. res = Scanner_AddError(pscanner, NULL, RES_E_SYNTAXERROR);
  1358. break;
  1359. }
  1360. DBG_EXIT_RES(Stmt_Parse, res);
  1361. return res;
  1362. }
  1363. //
  1364. // ProcDecl
  1365. //
  1366. /*----------------------------------------------------------
  1367. Purpose: Parse the variable declarations for the proc decl.
  1368. Grammar is:
  1369. <VarDecl> ::= <VarType> IDENT [ = <Expr> ]
  1370. <VarType> ::= integer | string | boolean
  1371. Returns: RES_OK
  1372. Cond: --
  1373. */
  1374. RES PRIVATE ProcDecl_ParseVarDecl(
  1375. HPA hpa,
  1376. PSCANNER pscanner,
  1377. PSYMTAB pst)
  1378. {
  1379. RES res = RES_OK;
  1380. PTOK ptok;
  1381. DATATYPE dt;
  1382. // Parse the variable decl block
  1383. while (RES_OK == res)
  1384. {
  1385. SYM sym;
  1386. Scanner_Peek(pscanner, &sym);
  1387. switch (sym)
  1388. {
  1389. case SYM_BOOLEAN:
  1390. case SYM_STRING:
  1391. case SYM_INTEGER:
  1392. if (RES_OK == Scanner_CondReadToken(pscanner, SYM_INTEGER, NULL))
  1393. dt = DATA_INT;
  1394. else if (RES_OK == Scanner_CondReadToken(pscanner, SYM_STRING, NULL))
  1395. dt = DATA_STRING;
  1396. else if (RES_OK == Scanner_CondReadToken(pscanner, SYM_BOOLEAN, NULL))
  1397. dt = DATA_BOOL;
  1398. else
  1399. ASSERT(0);
  1400. res = Ident_Parse(pscanner, &ptok);
  1401. if (RSUCCEEDED(res))
  1402. {
  1403. LPSTR pszIdent = Tok_GetLexeme(ptok);
  1404. res = Ident_Add(pszIdent, dt, ptok, pscanner, pst);
  1405. // Parse optional '= <Expr>'
  1406. if (RES_OK == Scanner_CondReadToken(pscanner, SYM_ASSIGN, NULL))
  1407. {
  1408. PEXPR pexpr;
  1409. PSTMT pstmt;
  1410. DWORD iLine = Scanner_GetLine(pscanner);
  1411. res = Expr_Parse(&pexpr, pscanner, pst);
  1412. if (RSUCCEEDED(res))
  1413. {
  1414. res = AssignStmt_New(&pstmt, pszIdent, pexpr, iLine);
  1415. if (RSUCCEEDED(res))
  1416. {
  1417. if (!PAInsertPtr(hpa, PA_APPEND, pstmt))
  1418. res = RES_E_OUTOFMEMORY;
  1419. }
  1420. }
  1421. }
  1422. Tok_Delete(ptok);
  1423. }
  1424. break;
  1425. default:
  1426. // Continue on with further parsing
  1427. res = RES_FALSE;
  1428. break;
  1429. }
  1430. }
  1431. return res;
  1432. }
  1433. /*----------------------------------------------------------
  1434. Purpose: Parse a statement block
  1435. Returns: RES_OK
  1436. Cond: --
  1437. */
  1438. RES PRIVATE StmtBlock_Parse(
  1439. HPA hpa,
  1440. PSCANNER pscanner,
  1441. PSYMTAB pstProc,
  1442. SYM symEnd)
  1443. {
  1444. RES res = RES_OK;
  1445. // Parse the statement block
  1446. while (RES_OK == res)
  1447. {
  1448. SYM sym;
  1449. PSTMT pstmt;
  1450. Scanner_Peek(pscanner, &sym);
  1451. switch (sym)
  1452. {
  1453. case SYM_EOF:
  1454. res = Scanner_AddError(pscanner, NULL, RES_E_EOFUNEXPECTED);
  1455. break;
  1456. default:
  1457. // Is this the end of the block?
  1458. if (symEnd == sym)
  1459. {
  1460. // Yes
  1461. Scanner_ReadToken(pscanner, symEnd);
  1462. res = RES_FALSE;
  1463. }
  1464. else
  1465. {
  1466. // No
  1467. res = Stmt_Parse(&pstmt, pscanner, pstProc);
  1468. if (RSUCCEEDED(res))
  1469. {
  1470. if (!PAInsertPtr(hpa, PA_APPEND, pstmt))
  1471. res = RES_E_OUTOFMEMORY;
  1472. }
  1473. }
  1474. break;
  1475. }
  1476. }
  1477. return res;
  1478. }
  1479. /*----------------------------------------------------------
  1480. Purpose: Work function that parses the proc declaration.
  1481. Returns: RES_OK
  1482. Cond: --
  1483. */
  1484. RES PRIVATE ProcDecl_PrivParse(
  1485. PPROCDECL * ppprocdecl,
  1486. PSCANNER pscanner,
  1487. HPA hpa,
  1488. PSYMTAB pstProc,
  1489. PSYMTAB pst)
  1490. {
  1491. RES res;
  1492. PTOK ptok;
  1493. DWORD iLine = Scanner_GetLine(pscanner);
  1494. // Parse 'proc'
  1495. res = Scanner_ReadToken(pscanner, SYM_PROC);
  1496. ASSERT(RES_OK == res);
  1497. // Parse the proc name
  1498. res = Scanner_GetToken(pscanner, &ptok);
  1499. if (RSUCCEEDED(res))
  1500. {
  1501. if (SYM_IDENT == Tok_GetSym(ptok))
  1502. {
  1503. LPCSTR pszIdent = Tok_GetLexeme(ptok);
  1504. // Add the identifier to the symbol table
  1505. res = Ident_Add(pszIdent, DATA_PROC, ptok, pscanner, pst);
  1506. // Parse the variable declaration block
  1507. if (RSUCCEEDED(res))
  1508. res = ProcDecl_ParseVarDecl(hpa, pscanner, pstProc);
  1509. // Parse the statement block
  1510. if (RSUCCEEDED(res))
  1511. res = StmtBlock_Parse(hpa, pscanner, pstProc, SYM_ENDPROC);
  1512. if (RSUCCEEDED(res))
  1513. {
  1514. // Create object
  1515. PDECL pdecl;
  1516. res = ProcDecl_New(&pdecl, pszIdent, hpa, pstProc, iLine);
  1517. *ppprocdecl = (PPROCDECL)pdecl;
  1518. }
  1519. }
  1520. else
  1521. res = Scanner_AddError(pscanner, ptok, RES_E_IDENTMISSING);
  1522. Tok_Delete(ptok);
  1523. }
  1524. else
  1525. res = Scanner_AddError(pscanner, NULL, RES_E_IDENTMISSING);
  1526. return res;
  1527. }
  1528. /*----------------------------------------------------------
  1529. Purpose: Parses the proc declaration
  1530. Grammar is:
  1531. <ProcDecl> ::= proc IDENT { <VarDecl> } <StmtBlock> endproc
  1532. <StmtBlock> ::= {<Stmt>}*
  1533. Returns: RES_OK
  1534. Cond: --
  1535. */
  1536. RES PRIVATE ProcDecl_Parse(
  1537. PPROCDECL * ppprocdecl,
  1538. PSCANNER pscanner,
  1539. PSYMTAB pst)
  1540. {
  1541. RES res;
  1542. HPA hpa;
  1543. PSYMTAB pstProc;
  1544. DBG_ENTER(ProcDecl_Parse);
  1545. ASSERT(ppprocdecl);
  1546. ASSERT(pscanner);
  1547. *ppprocdecl = NULL;
  1548. if (PACreate(&hpa, 8))
  1549. {
  1550. res = Symtab_Create(&pstProc, pst);
  1551. if (RSUCCEEDED(res))
  1552. {
  1553. PSTMT pstmtT;
  1554. DWORD iLine = Scanner_GetLine(pscanner);
  1555. // Add the prolog
  1556. res = EnterStmt_New(&pstmtT, pstProc, iLine);
  1557. if (RSUCCEEDED(res))
  1558. {
  1559. if (!PAInsertPtr(hpa, PA_APPEND, pstmtT))
  1560. {
  1561. res = RES_E_OUTOFMEMORY;
  1562. Stmt_Delete(pstmtT);
  1563. }
  1564. else
  1565. {
  1566. res = ProcDecl_PrivParse(ppprocdecl, pscanner, hpa, pstProc, pst);
  1567. if (RSUCCEEDED(res))
  1568. {
  1569. // Add the epilog
  1570. res = LeaveStmt_New(&pstmtT, Scanner_GetLine(pscanner));
  1571. if (RSUCCEEDED(res))
  1572. {
  1573. if (!PAInsertPtr(hpa, PA_APPEND, pstmtT))
  1574. {
  1575. res = RES_E_OUTOFMEMORY;
  1576. Stmt_Delete(pstmtT);
  1577. }
  1578. }
  1579. }
  1580. }
  1581. }
  1582. // Did something fail up above?
  1583. if (RFAILED(res))
  1584. {
  1585. // Yes; cleanup
  1586. Symtab_Destroy(pstProc);
  1587. }
  1588. }
  1589. // Clean up
  1590. if (RFAILED(res))
  1591. PADestroyEx(hpa, Stmt_DeletePAPtr, 0);
  1592. }
  1593. else
  1594. res = RES_E_OUTOFMEMORY;
  1595. DBG_EXIT_RES(ProcDecl_Parse, res);
  1596. return res;
  1597. }
  1598. //
  1599. // ModuleDecl
  1600. //
  1601. /*----------------------------------------------------------
  1602. Purpose: Parses the script at the module level.
  1603. Grammar is:
  1604. <ModuleDecl> ::= {<ProcDecl>}*
  1605. Returns: RES_OK
  1606. RES_E_OUTOFMEMORY
  1607. Cond: --
  1608. */
  1609. RES PUBLIC ModuleDecl_Parse(
  1610. PMODULEDECL * ppmoduledecl,
  1611. PSCANNER pscanner,
  1612. PSYMTAB pstSystem) // May be NULL
  1613. {
  1614. RES res = RES_OK;
  1615. HPA hpa;
  1616. DBG_ENTER(ModuleDecl_Parse);
  1617. ASSERT(ppmoduledecl);
  1618. ASSERT(pscanner);
  1619. TRACE_MSG(TF_GENERAL, "Parsing...");
  1620. *ppmoduledecl = NULL;
  1621. if (PACreate(&hpa, 8))
  1622. {
  1623. PSYMTAB pst;
  1624. PDECL pdecl = NULL;
  1625. res = Symtab_Create(&pst, pstSystem);
  1626. if (RSUCCEEDED(res))
  1627. {
  1628. // Parse the module block
  1629. while (RES_OK == res)
  1630. {
  1631. SYM sym;
  1632. Scanner_Peek(pscanner, &sym);
  1633. switch (sym)
  1634. {
  1635. case SYM_EOF:
  1636. res = RES_FALSE; // Time to stop
  1637. break;
  1638. case SYM_PROC:
  1639. {
  1640. PPROCDECL pprocdecl;
  1641. res = ProcDecl_Parse(&pprocdecl, pscanner, pst);
  1642. if (RSUCCEEDED(res))
  1643. {
  1644. if (!PAInsertPtr(hpa, PA_APPEND, pprocdecl))
  1645. res = RES_E_OUTOFMEMORY;
  1646. }
  1647. }
  1648. break;
  1649. default:
  1650. res = Scanner_AddError(pscanner, NULL, RES_E_SYNTAXERROR);
  1651. break;
  1652. }
  1653. }
  1654. if (RSUCCEEDED(res))
  1655. {
  1656. DWORD iLine = Scanner_GetLine(pscanner);
  1657. res = ModuleDecl_New(&pdecl, hpa, pst, iLine);
  1658. #ifdef DEBUG
  1659. if (RSUCCEEDED(res))
  1660. Ast_Dump((PAST)pdecl);
  1661. #endif
  1662. }
  1663. // Clean up after parsing
  1664. if (RSUCCEEDED(res))
  1665. PADestroy(hpa); // keep pointer elements allocated for pdecl
  1666. else
  1667. {
  1668. // Something failed
  1669. PADestroyEx(hpa, Decl_DeletePAPtr, 0);
  1670. Symtab_Destroy(pst);
  1671. // Parse errors were added to the scanner's list
  1672. // of errors already. However, errors such as
  1673. // out of memory still need to be added.
  1674. if (FACILITY_PARSE != RFACILITY(res))
  1675. Scanner_AddError(pscanner, NULL, res);
  1676. }
  1677. // Now typecheck the script
  1678. if (pdecl)
  1679. {
  1680. res = ModuleDecl_Typecheck((PMODULEDECL)pdecl, Scanner_GetStxerrHandle(pscanner));
  1681. if (RFAILED(res))
  1682. {
  1683. Decl_Delete(pdecl);
  1684. pdecl = NULL;
  1685. }
  1686. }
  1687. }
  1688. *ppmoduledecl = (PMODULEDECL)pdecl;
  1689. }
  1690. else
  1691. res = RES_E_OUTOFMEMORY;
  1692. DBG_EXIT_RES(ModuleDecl_Parse, res);
  1693. return res;
  1694. }