Ablstmt.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. //===========================================================================//
  2. // Copyright (C) Microsoft Corporation. All rights reserved. //
  3. //===========================================================================//
  4. //***************************************************************************
  5. //
  6. // ABLSTMT.CPP
  7. //
  8. //***************************************************************************
  9. #include <stdio.h>
  10. #ifndef ABLGEN_H
  11. #include "ablgen.h"
  12. #endif
  13. #ifndef ABLERR_H
  14. #include "ablerr.h"
  15. #endif
  16. #ifndef ABLSCAN_H
  17. #include "ablscan.h"
  18. #endif
  19. #ifndef ABLSYMT_H
  20. #include "ablsymt.h"
  21. #endif
  22. #ifndef ABLPARSE_H
  23. #include "ablparse.h"
  24. #endif
  25. #ifndef ABLEXEC_H
  26. #include "ablexec.h"
  27. #endif
  28. //***************************************************************************
  29. extern TokenCodeType curToken;
  30. extern char tokenString[];
  31. extern char wordString[];
  32. extern Literal curLiteral;
  33. extern TokenCodeType statementStartList[];
  34. extern TokenCodeType statementEndList[];
  35. extern SymTableNodePtr symTableDisplay[];
  36. extern long level;
  37. extern char* codeBuffer;
  38. extern TypePtr IntegerTypePtr;
  39. extern TypePtr RealTypePtr;
  40. extern TypePtr BooleanTypePtr;
  41. extern TypePtr CharTypePtr;
  42. extern Type DummyType;
  43. extern SymTableNodePtr CurRoutineIdPtr;
  44. extern SymTableNodePtr SymTableDisplay[MAX_NESTING_LEVEL];
  45. extern bool AssertEnabled;
  46. extern bool PrintEnabled;
  47. extern bool StringFunctionsEnabled;
  48. extern bool Crunch;
  49. extern long NumOrderCalls;
  50. //--------
  51. // GLOBALS
  52. TokenCodeType FollowSwitchExpressionList[] = {
  53. TKN_CASE,
  54. TKN_SEMICOLON,
  55. TKN_NONE
  56. };
  57. TokenCodeType FollowCaseLabelList[] = {
  58. TKN_COLON,
  59. TKN_SEMICOLON,
  60. TKN_NONE
  61. };
  62. TokenCodeType CaseLabelStartList[] = {
  63. TKN_IDENTIFIER,
  64. TKN_NUMBER,
  65. TKN_PLUS,
  66. TKN_MINUS,
  67. TKN_STRING,
  68. TKN_NONE
  69. };
  70. SymTableNodePtr forwardState (char* stateName);
  71. //***************************************************************************
  72. void assignmentStatement (SymTableNodePtr varIdPtr) {
  73. //-----------------------------------
  74. // Grab the variable we're setting...
  75. TypePtr varType = variable(varIdPtr);
  76. ifTokenGetElseError(TKN_EQUAL, ABL_ERR_SYNTAX_MISSING_EQUAL);
  77. //---------------------------------------------------------
  78. // Now, get the expression we're setting the variable to...
  79. TypePtr exprType = expression();
  80. //----------------------------------------
  81. // They better be assignment compatible...
  82. if (!isAssignTypeCompatible(varType, exprType))
  83. syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_ASSIGNMENT);
  84. }
  85. //***************************************************************************
  86. void repeatStatement (void) {
  87. getToken();
  88. if (curToken != TKN_UNTIL) {
  89. do {
  90. statement();
  91. while (curToken == TKN_SEMICOLON)
  92. getToken();
  93. if (curToken == TKN_UNTIL)
  94. break;
  95. } while (tokenIn(statementStartList));
  96. }
  97. ifTokenGetElseError(TKN_UNTIL, ABL_ERR_SYNTAX_MISSING_UNTIL);
  98. TypePtr exprType = expression();
  99. if (exprType != BooleanTypePtr)
  100. syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
  101. }
  102. //***************************************************************************
  103. void whileStatement (void) {
  104. // NEW STYLE, using endwhile keyword...
  105. getToken();
  106. char* loopEndLocation = crunchAddressMarker(NULL);
  107. TypePtr exprType = expression();
  108. if (exprType != BooleanTypePtr)
  109. syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
  110. //---------------------------------------
  111. // Let's not use a DO keyword, for now...
  112. ifTokenGetElseError(TKN_DO, ABL_ERR_SYNTAX_MISSING_DO);
  113. if (curToken != TKN_END_WHILE)
  114. do {
  115. statement();
  116. while (curToken == TKN_SEMICOLON)
  117. getToken();
  118. if (curToken == TKN_END_WHILE)
  119. break;
  120. } while (tokenIn(statementStartList));
  121. ifTokenGetElseError(TKN_END_WHILE, ABL_ERR_SYNTAX_MISSING_END_WHILE);
  122. fixupAddressMarker(loopEndLocation);
  123. }
  124. //***************************************************************************
  125. void ifStatement (void) {
  126. getToken();
  127. char* falseLocation = crunchAddressMarker(NULL);
  128. TypePtr exprType = expression();
  129. if (exprType != BooleanTypePtr)
  130. syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
  131. ifTokenGetElseError(TKN_THEN, ABL_ERR_SYNTAX_MISSING_THEN);
  132. if ((curToken != TKN_END_IF) && (curToken != TKN_ELSE))
  133. do {
  134. statement();
  135. while (curToken == TKN_SEMICOLON)
  136. getToken();
  137. if ((curToken == TKN_END_IF) || (curToken == TKN_ELSE))
  138. break;
  139. } while (tokenIn(statementStartList));
  140. fixupAddressMarker(falseLocation);
  141. //-----------------------------
  142. // ELSE branch, if necessary...
  143. if (curToken == TKN_ELSE) {
  144. getToken();
  145. char* ifEndLocation = crunchAddressMarker(NULL);
  146. if (curToken != TKN_END_IF)
  147. do {
  148. statement();
  149. while (curToken == TKN_SEMICOLON)
  150. getToken();
  151. if (curToken == TKN_END_IF)
  152. break;
  153. } while (tokenIn(statementStartList));
  154. fixupAddressMarker(ifEndLocation);
  155. }
  156. ifTokenGetElseError(TKN_END_IF, ABL_ERR_SYNTAX_MISSING_END_IF);
  157. }
  158. //***************************************************************************
  159. void forStatement (void) {
  160. getToken();
  161. char* loopEndLocation = crunchAddressMarker(NULL);
  162. TypePtr forType = NULL;
  163. if (curToken == TKN_IDENTIFIER) {
  164. SymTableNodePtr forIdPtr = NULL;
  165. searchAndFindAllSymTables(forIdPtr);
  166. crunchSymTableNodePtr(forIdPtr);
  167. if (/*(forIdPtr->level != level) ||*/ (forIdPtr->defn.key != DFN_VAR))
  168. syntaxError(ABL_ERR_SYNTAX_INVALID_FOR_CONTROL);
  169. forType = forIdPtr->typePtr;
  170. getToken();
  171. //------------------------------------------------------------------
  172. // If we end up adding a CHAR type, this line needs to be changed...
  173. if ((forType != IntegerTypePtr) && /*(forType != CharTypePtr) &&*/ (forType->form != FRM_ENUM))
  174. syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
  175. }
  176. else {
  177. syntaxError(ABL_ERR_SYNTAX_MISSING_IDENTIFIER);
  178. forType = &DummyType;
  179. }
  180. ifTokenGetElseError(TKN_EQUAL, ABL_ERR_SYNTAX_MISSING_EQUAL);
  181. TypePtr exprType = expression();
  182. if (!isAssignTypeCompatible(forType, exprType))
  183. syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
  184. if (curToken == TKN_TO)
  185. getToken();
  186. else
  187. syntaxError(ABL_ERR_SYNTAX_MISSING_TO);
  188. exprType = expression();
  189. if (!isAssignTypeCompatible(forType, exprType))
  190. syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
  191. //-----------------------------------------
  192. // For now, let's use the DO keyword...
  193. ifTokenGetElseError(TKN_DO, ABL_ERR_SYNTAX_MISSING_DO);
  194. if (curToken != TKN_END_FOR)
  195. do {
  196. statement();
  197. while (curToken == TKN_SEMICOLON)
  198. getToken();
  199. if (curToken == TKN_END_FOR)
  200. break;
  201. } while (tokenIn(statementStartList));
  202. ifTokenGetElseError(TKN_END_FOR, ABL_ERR_SYNTAX_MISSING_END_FOR);
  203. fixupAddressMarker(loopEndLocation);
  204. }
  205. //***************************************************************************
  206. TypePtr caseLabel (CaseItemPtr& caseItemHead, CaseItemPtr& caseItemTail, long& caseLabelCount) {
  207. CaseItemPtr newCaseItem = (CaseItemPtr)ABLStackMallocCallback(sizeof(CaseItem));
  208. if (!newCaseItem)
  209. ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc case item ");
  210. if (caseItemHead) {
  211. caseItemTail->next = newCaseItem;
  212. caseItemTail = newCaseItem;
  213. }
  214. else
  215. caseItemHead = caseItemTail = newCaseItem;
  216. newCaseItem->next = NULL;
  217. caseLabelCount++;
  218. TokenCodeType sign = TKN_PLUS;
  219. bool sawSign = false;
  220. if ((curToken == TKN_PLUS) || (curToken == TKN_MINUS)) {
  221. sign = curToken;
  222. sawSign = true;
  223. getToken();
  224. }
  225. if (curToken == TKN_NUMBER) {
  226. SymTableNodePtr thisNode = searchSymTable(tokenString, SymTableDisplay[1]);
  227. if (!thisNode)
  228. thisNode = enterSymTable(tokenString, &SymTableDisplay[1]);
  229. crunchSymTableNodePtr(thisNode);
  230. if (curLiteral.type == LIT_INTEGER)
  231. newCaseItem->labelValue = (sign == TKN_PLUS) ? curLiteral.value.integer : -curLiteral.value.integer;
  232. else
  233. syntaxError(ABL_ERR_SYNTAX_INVALID_CONSTANT);
  234. return(IntegerTypePtr);
  235. }
  236. else if (curToken == TKN_IDENTIFIER) {
  237. SymTableNodePtr idPtr;
  238. searchAllSymTables(idPtr);
  239. crunchSymTableNodePtr(idPtr);
  240. if (!idPtr) {
  241. syntaxError(ABL_ERR_SYNTAX_UNDEFINED_IDENTIFIER);
  242. return(&DummyType);
  243. }
  244. else if (idPtr->defn.key != DFN_CONST) {
  245. syntaxError(ABL_ERR_SYNTAX_NOT_A_CONSTANT_IDENTIFIER);
  246. return(&DummyType);
  247. }
  248. else if (idPtr->typePtr == IntegerTypePtr) {
  249. newCaseItem->labelValue = (sign == TKN_PLUS ? idPtr->defn.info.constant.value.integer : -idPtr->defn.info.constant.value.integer);
  250. return(IntegerTypePtr);
  251. }
  252. else if (idPtr->typePtr == CharTypePtr) {
  253. if (sawSign)
  254. syntaxError(ABL_ERR_SYNTAX_INVALID_CONSTANT);
  255. newCaseItem->labelValue = idPtr->defn.info.constant.value.character;
  256. return(CharTypePtr);
  257. }
  258. else if (idPtr->typePtr->form == FRM_ENUM) {
  259. if (sawSign)
  260. syntaxError(ABL_ERR_SYNTAX_INVALID_CONSTANT);
  261. newCaseItem->labelValue = idPtr->defn.info.constant.value.integer;
  262. return(idPtr->typePtr);
  263. }
  264. else
  265. return(&DummyType);
  266. }
  267. else if (curToken == TKN_STRING) {
  268. // STRING/CHAR TYPE...
  269. }
  270. else {
  271. syntaxError(ABL_ERR_SYNTAX_INVALID_CONSTANT);
  272. return(&DummyType);
  273. }
  274. return(&DummyType);
  275. }
  276. //---------------------------------------------------------------------------
  277. void caseBranch (CaseItemPtr& caseItemHead, CaseItemPtr& caseItemTail, long& caseLabelCount, TypePtr expressionType) {
  278. //static CaseItemPtr oldCaseItemTail = NULL;
  279. CaseItemPtr oldCaseItemTail = caseItemTail;
  280. bool anotherLabel;
  281. do {
  282. TypePtr labelType = caseLabel(caseItemHead, caseItemTail, caseLabelCount);
  283. if (expressionType != labelType)
  284. syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
  285. getToken();
  286. if (curToken == TKN_COMMA) {
  287. getToken();
  288. if (tokenIn(CaseLabelStartList))
  289. anotherLabel = true;
  290. else {
  291. syntaxError(ABL_ERR_SYNTAX_MISSING_CONSTANT);
  292. anotherLabel = false;
  293. }
  294. }
  295. else
  296. anotherLabel = false;
  297. } while (anotherLabel);
  298. //--------------
  299. // Error sync...
  300. synchronize(FollowCaseLabelList, statementStartList, NULL);
  301. ifTokenGetElseError(TKN_COLON, ABL_ERR_SYNTAX_MISSING_COLON);
  302. //-----------------------------------------------------------------
  303. // Fill in the branch location for each CaseItem for this branch...
  304. CaseItemPtr caseItem = (!oldCaseItemTail ? caseItemHead : oldCaseItemTail->next);
  305. //oldCaseItemTail = CaseItemTail;
  306. while (caseItem) {
  307. caseItem->branchLocation = codeBufferPtr;
  308. caseItem = caseItem->next;
  309. }
  310. if (curToken != TKN_END_CASE)
  311. do {
  312. statement();
  313. while (curToken == TKN_SEMICOLON)
  314. getToken();
  315. if (curToken == TKN_END_CASE)
  316. break;
  317. } while (tokenIn(statementStartList));
  318. ifTokenGetElseError(TKN_END_CASE, ABL_ERR_SYNTAX_MISSING_END_CASE);
  319. ifTokenGetElseError(TKN_SEMICOLON, ABL_ERR_SYNTAX_MISSING_SEMICOLON);
  320. }
  321. //---------------------------------------------------------------------------
  322. void switchStatement (void) {
  323. //-------------------------
  324. // Init the branch table...
  325. getToken();
  326. char* branchTableLocation = crunchAddressMarker(NULL);
  327. CaseItemPtr caseItemHead = NULL;
  328. CaseItemPtr caseItemTail = NULL;
  329. long caseLabelCount = 0;
  330. //CaseItemHead = CaseItemTail = NULL;
  331. //CaseLabelCount = 0;
  332. TypePtr expressionType = expression();
  333. //-----------------------------------------------------------------------------
  334. // NOTE: If we have subranges in ABL, we'll have to check in the following line
  335. // for a subrange, as well...
  336. if (((expressionType->form != FRM_SCALAR) && (expressionType->form != FRM_ENUM)) || (expressionType == RealTypePtr))
  337. syntaxError(ABL_ERR_SYNTAX_INCOMPATIBLE_TYPES);
  338. synchronize(FollowSwitchExpressionList, NULL, NULL);
  339. //----------------------------
  340. // Process each CASE branch...
  341. bool moreBranches = (curToken == TKN_CASE);
  342. char* caseEndChain = NULL;
  343. while (moreBranches) {
  344. getToken();
  345. if (tokenIn(CaseLabelStartList))
  346. caseBranch(caseItemHead, caseItemTail, caseLabelCount, expressionType);
  347. //---------------------------------------------------
  348. // Link another address marker at the end of the CASE
  349. // branch to point to the end of the CASE block...
  350. caseEndChain = crunchAddressMarker(caseEndChain);
  351. moreBranches = (curToken == TKN_CASE);
  352. }
  353. //if (curToken == TKN_DEFAULT) {
  354. //}
  355. //-------------------------
  356. // Emit the branch table...
  357. fixupAddressMarker(branchTableLocation);
  358. crunchInteger(caseLabelCount);
  359. CaseItemPtr caseItem = caseItemHead;
  360. while (caseItem) {
  361. crunchInteger(caseItem->labelValue);
  362. crunchOffset(caseItem->branchLocation);
  363. CaseItemPtr nextCaseItem = caseItem->next;
  364. ABLStackFreeCallback(caseItem);
  365. caseItem = nextCaseItem;
  366. }
  367. ifTokenGetElseError(TKN_END_SWITCH, ABL_ERR_SYNTAX_MISSING_END_SWITCH);
  368. //--------------------------------------------
  369. // Patch up the case branch address markers...
  370. while (caseEndChain)
  371. caseEndChain = fixupAddressMarker(caseEndChain);
  372. }
  373. //***************************************************************************
  374. void transStatement (void) {
  375. getToken();
  376. ifTokenGetElseError(TKN_IDENTIFIER, ABL_ERR_MISSING_STATE_IDENTIFIER);
  377. SymTableNodePtr IdPtr = searchSymTableForState(wordString, SymTableDisplay[1]);
  378. if (!IdPtr) {
  379. // New symbol, so let's assume it's a state defined later. We'll make it
  380. IdPtr = forwardState(wordString);
  381. }
  382. if (!IdPtr || (IdPtr->defn.key != DFN_FUNCTION) || ((IdPtr->defn.info.routine.flags & ROUTINE_FLAG_STATE) == 0))
  383. syntaxError(ABL_ERR_MISSING_STATE_IDENTIFIER);
  384. crunchSymTableNodePtr(IdPtr);
  385. // getToken();
  386. }
  387. //***************************************************************************
  388. void transBackStatement (void) {
  389. getToken();
  390. }
  391. //***************************************************************************
  392. void statement (void) {
  393. //-------------------------------------------------------------------
  394. // NOTE: Since we currently don't support generic BEGIN/END (compound
  395. // statement) blocks...
  396. if ((curToken != TKN_CODE) /*&& (curToken != TKN_BEGIN)*/)
  397. crunchStatementMarker();
  398. switch (curToken) {
  399. case TKN_IDENTIFIER: {
  400. SymTableNodePtr IdPtr = NULL;
  401. //--------------------------------------------------------------
  402. // First, do we have an assignment statement or a function call?
  403. searchAndFindAllSymTables(IdPtr);
  404. if ((IdPtr->defn.key == DFN_FUNCTION)/* || (IdPtr->defn.key == DFN_MODULE)*/) {
  405. RoutineKey key = IdPtr->defn.info.routine.key;
  406. if ((key == RTN_ASSERT) || (key == RTN_PRINT) || (key == RTN_CONCAT)) {
  407. bool uncrunch = ((key == RTN_ASSERT) && !AssertEnabled) ||
  408. ((key == RTN_PRINT) && !PrintEnabled) ||
  409. ((key == RTN_CONCAT) && !StringFunctionsEnabled);
  410. if (uncrunch) {
  411. uncrunchStatementMarker();
  412. Crunch = false;
  413. }
  414. }
  415. crunchSymTableNodePtr(IdPtr);
  416. if (IdPtr->defn.info.routine.flags & ROUTINE_FLAG_ORDER) {
  417. if (NumOrderCalls == MAX_ORDERS)
  418. syntaxError(ABL_ERR_SYNTAX_TOO_MANY_ORDERS);
  419. crunchByte(NumOrderCalls / 32);
  420. crunchByte(NumOrderCalls % 32);
  421. NumOrderCalls++;
  422. }
  423. getToken();
  424. SymTableNodePtr thisRoutineIdPtr = CurRoutineIdPtr;
  425. routineCall(IdPtr, 1);
  426. CurRoutineIdPtr = thisRoutineIdPtr;
  427. Crunch = true;
  428. }
  429. else
  430. assignmentStatement(IdPtr);
  431. }
  432. break;
  433. case TKN_REPEAT:
  434. repeatStatement();
  435. break;
  436. case TKN_WHILE:
  437. whileStatement();
  438. break;
  439. case TKN_IF:
  440. ifStatement();
  441. break;
  442. case TKN_FOR:
  443. forStatement();
  444. break;
  445. case TKN_SWITCH:
  446. switchStatement();
  447. break;
  448. case TKN_TRANS:
  449. transStatement();
  450. break;
  451. case TKN_TRANS_BACK:
  452. transBackStatement();
  453. break;
  454. }
  455. //---------------------------------------------------------------------
  456. // Now, make sure the statement is closed off with the proper block end
  457. // statement, if necessary (which is usually the case :).
  458. synchronize(statementEndList, NULL, NULL);
  459. if (tokenIn(statementStartList))
  460. syntaxError(ABL_ERR_SYNTAX_MISSING_SEMICOLON);
  461. }
  462. //***************************************************************************