parcon.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863
  1. /*++
  2. Copyright (c) 2016 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. parcon.c
  9. Abstract:
  10. This module implements functions related to parser construction and
  11. finalization.
  12. Author:
  13. Evan Green 23-Apr-2016
  14. Environment:
  15. Build
  16. --*/
  17. //
  18. // ------------------------------------------------------------------- Includes
  19. //
  20. #include "yygenp.h"
  21. #include <assert.h>
  22. //
  23. // ---------------------------------------------------------------- Definitions
  24. //
  25. //
  26. // ------------------------------------------------------ Data Type Definitions
  27. //
  28. //
  29. // ----------------------------------------------- Internal Function Prototypes
  30. //
  31. PYYGEN_ACTION
  32. YypCreateParseActions (
  33. PYYGEN_CONTEXT Context,
  34. YY_STATE_INDEX StateIndex
  35. );
  36. PYYGEN_ACTION
  37. YypCreateShiftActions (
  38. PYYGEN_CONTEXT Context,
  39. YY_STATE_INDEX StateIndex
  40. );
  41. PYYGEN_ACTION
  42. YypCreateReductionActions (
  43. PYYGEN_CONTEXT Context,
  44. YY_STATE_INDEX StateIndex,
  45. PYYGEN_ACTION Actions
  46. );
  47. PYYGEN_ACTION
  48. YypCreateReductionAction (
  49. PYYGEN_CONTEXT Context,
  50. YY_RULE_INDEX RuleIndex,
  51. YY_VALUE Symbol,
  52. PYYGEN_ACTION Actions
  53. );
  54. VOID
  55. YypFindFinalState (
  56. PYYGEN_CONTEXT Context
  57. );
  58. YY_STATUS
  59. YypRemoveConflicts (
  60. PYYGEN_CONTEXT Context
  61. );
  62. VOID
  63. YypNoticeUnusedRules (
  64. PYYGEN_CONTEXT Context
  65. );
  66. YY_STATUS
  67. YypCreateDefaultReductions (
  68. PYYGEN_CONTEXT Context
  69. );
  70. YY_RULE_INDEX
  71. YypFindSoleReduction (
  72. PYYGEN_CONTEXT Context,
  73. YY_STATE_INDEX StateIndex
  74. );
  75. VOID
  76. YypPrintAction (
  77. PYYGEN_CONTEXT Context,
  78. PYYGEN_ACTION Action,
  79. YY_STATE_INDEX StateIndex
  80. );
  81. //
  82. // -------------------------------------------------------------------- Globals
  83. //
  84. //
  85. // ------------------------------------------------------------------ Functions
  86. //
  87. YY_STATUS
  88. YypBuildParser (
  89. PYYGEN_CONTEXT Context
  90. )
  91. /*++
  92. Routine Description:
  93. This routine generates the parser data structures based on the LALR(1)
  94. construction.
  95. Arguments:
  96. Context - Supplies a pointer to the generator context.
  97. Return Value:
  98. YY status.
  99. --*/
  100. {
  101. YY_STATE_INDEX Index;
  102. YY_STATUS YyStatus;
  103. Context->Parser = YypAllocate(Context->StateCount * sizeof(PYYGEN_ACTION));
  104. if (Context->Parser == NULL) {
  105. YyStatus = YyStatusNoMemory;
  106. goto BuildParserEnd;
  107. }
  108. for (Index = 0; Index < Context->StateCount; Index += 1) {
  109. Context->Parser[Index] = YypCreateParseActions(Context, Index);
  110. if (Context->Parser[Index] == NULL) {
  111. YyStatus = YyStatusNoMemory;
  112. goto BuildParserEnd;
  113. }
  114. }
  115. YypFindFinalState(Context);
  116. YyStatus = YypRemoveConflicts(Context);
  117. if (YyStatus != YyStatusSuccess) {
  118. goto BuildParserEnd;
  119. }
  120. YypNoticeUnusedRules(Context);
  121. YyStatus = YypCreateDefaultReductions(Context);
  122. BuildParserEnd:
  123. return YyStatus;
  124. }
  125. //
  126. // --------------------------------------------------------- Internal Functions
  127. //
  128. PYYGEN_ACTION
  129. YypCreateParseActions (
  130. PYYGEN_CONTEXT Context,
  131. YY_STATE_INDEX StateIndex
  132. )
  133. /*++
  134. Routine Description:
  135. This routine creates the parser actions for a given state.
  136. Arguments:
  137. Context - Supplies a pointer to the generator context.
  138. StateIndex - Supplies the state index.
  139. Return Value:
  140. Returns a pointer to the new action list on success.
  141. NULL on allocation failure.
  142. --*/
  143. {
  144. PYYGEN_ACTION Actions;
  145. Actions = YypCreateShiftActions(Context, StateIndex);
  146. Actions = YypCreateReductionActions(Context, StateIndex, Actions);
  147. if ((Context->Flags & YYGEN_FLAG_DEBUG) != 0) {
  148. YypPrintAction(Context, Actions, StateIndex);
  149. }
  150. return Actions;
  151. }
  152. PYYGEN_ACTION
  153. YypCreateShiftActions (
  154. PYYGEN_CONTEXT Context,
  155. YY_STATE_INDEX StateIndex
  156. )
  157. /*++
  158. Routine Description:
  159. This routine creates the parser shift actions for a given state.
  160. Arguments:
  161. Context - Supplies a pointer to the generator context.
  162. StateIndex - Supplies the state index.
  163. Return Value:
  164. Returns a pointer to the new shift action list on success.
  165. NULL on allocation failure.
  166. --*/
  167. {
  168. PYYGEN_ACTION Actions;
  169. YY_STATE_INDEX DestinationState;
  170. ULONG Flags;
  171. PYYGEN_ACTION NewAction;
  172. YY_VALUE ShiftIndex;
  173. PYYGEN_SHIFTS Shifts;
  174. PYY_STATE_INDEX States;
  175. YY_VALUE Symbol;
  176. YY_STATUS YyStatus;
  177. Actions = NULL;
  178. Shifts = Context->ShiftTable[StateIndex];
  179. if (Shifts != NULL) {
  180. States = Shifts->States;
  181. //
  182. // Look through all the shifts for this state. Add actions for all
  183. // shifts based on terminals.
  184. //
  185. for (ShiftIndex = Shifts->Count - 1; ShiftIndex >= 0; ShiftIndex -= 1) {
  186. DestinationState = States[ShiftIndex];
  187. Symbol = Context->AccessingSymbol[DestinationState];
  188. if (Symbol < Context->TokenCount) {
  189. NewAction = YypAllocate(sizeof(YYGEN_ACTION));
  190. if (NewAction == NULL) {
  191. YyStatus = YyStatusNoMemory;
  192. goto CreateShiftActionsEnd;
  193. }
  194. NewAction->Next = Actions;
  195. NewAction->Symbol = Symbol;
  196. NewAction->Number = DestinationState;
  197. NewAction->Precedence = Context->Elements[Symbol].Precedence;
  198. Flags = Context->Elements[Symbol].Flags;
  199. if (Flags != 0) {
  200. if ((Flags & YY_ELEMENT_LEFT_ASSOCIATIVE) != 0) {
  201. NewAction->Associativity = YyLeftAssociative;
  202. } else if ((Flags & YY_ELEMENT_RIGHT_ASSOCIATIVE) != 0) {
  203. NewAction->Associativity = YyRightAssociative;
  204. } else if ((Flags & YY_ELEMENT_NON_ASSOCIATIVE) != 0) {
  205. NewAction->Associativity = YyNonAssociative;
  206. }
  207. }
  208. NewAction->Code = YyActionShift;
  209. Actions = NewAction;
  210. }
  211. }
  212. }
  213. YyStatus = YyStatusSuccess;
  214. CreateShiftActionsEnd:
  215. if (YyStatus != YyStatusSuccess) {
  216. while (Actions != NULL) {
  217. NewAction = Actions->Next;
  218. YypFree(Actions);
  219. Actions = NewAction;
  220. }
  221. }
  222. return Actions;
  223. }
  224. PYYGEN_ACTION
  225. YypCreateReductionActions (
  226. PYYGEN_CONTEXT Context,
  227. YY_STATE_INDEX StateIndex,
  228. PYYGEN_ACTION Actions
  229. )
  230. /*++
  231. Routine Description:
  232. This routine creates the parser reduction actions for a given state.
  233. Arguments:
  234. Context - Supplies a pointer to the generator context.
  235. StateIndex - Supplies the state index.
  236. Actions - Supplies the head of the list of actions already created by the
  237. shifts.
  238. Return Value:
  239. Returns a pointer to the new complete action list on success.
  240. NULL on allocation failure.
  241. --*/
  242. {
  243. YY_VALUE End;
  244. YY_VALUE Lookahead;
  245. PULONG Row;
  246. YY_RULE_INDEX RuleIndex;
  247. YY_VALUE Token;
  248. ULONG TokenSetSize;
  249. TokenSetSize = YYGEN_BITMAP_WORD_COUNT(Context->TokenCount);
  250. Lookahead = Context->Lookaheads[StateIndex];
  251. End = Context->Lookaheads[StateIndex + 1];
  252. while (Lookahead < End) {
  253. RuleIndex = Context->LookaheadRule[Lookahead];
  254. Row = Context->LookaheadSets + (Lookahead * TokenSetSize);
  255. for (Token = Context->TokenCount - 1; Token >= 0; Token -= 1) {
  256. if (YYGEN_BITMAP_IS_SET(Row, Token)) {
  257. Actions = YypCreateReductionAction(Context,
  258. RuleIndex,
  259. Token,
  260. Actions);
  261. if (Actions == NULL) {
  262. return NULL;
  263. }
  264. }
  265. }
  266. Lookahead += 1;
  267. }
  268. return Actions;
  269. }
  270. PYYGEN_ACTION
  271. YypCreateReductionAction (
  272. PYYGEN_CONTEXT Context,
  273. YY_RULE_INDEX RuleIndex,
  274. YY_VALUE Symbol,
  275. PYYGEN_ACTION Actions
  276. )
  277. /*++
  278. Routine Description:
  279. This routine creates a parser reduction action for a given rule and token.
  280. Arguments:
  281. Context - Supplies a pointer to the generator context.
  282. RuleIndex - Supplies the rule index.
  283. Symbol - Supplies the lookahead symbol.
  284. Actions - Supplies the head of the list of actions already created by the
  285. shifts.
  286. Return Value:
  287. Returns a pointer to the new complete action list on success.
  288. NULL on allocation failure.
  289. --*/
  290. {
  291. PYYGEN_ACTION NewAction;
  292. PYYGEN_ACTION Next;
  293. PYYGEN_ACTION Previous;
  294. YY_STATUS YyStatus;
  295. YyStatus = YyStatusNoMemory;
  296. //
  297. // Keep everything sorted by finding the right spot to insert this here.
  298. //
  299. Previous = NULL;
  300. Next = Actions;
  301. while ((Next != NULL) && (Next->Symbol < Symbol)) {
  302. Previous = Next;
  303. Next = Next->Next;
  304. }
  305. //
  306. // Let shifts with the same symbol be first.
  307. //
  308. while ((Next != NULL) && (Next->Symbol == Symbol) &&
  309. (Next->Code == YyActionShift)) {
  310. Previous = Next;
  311. Next = Next->Next;
  312. }
  313. //
  314. // Let reductions with the same symbol and an earlier rule number be first.
  315. //
  316. while ((Next != NULL) && (Next->Symbol == Symbol) &&
  317. (Next->Code == YyActionReduce) && (Next->Number < RuleIndex)) {
  318. Previous = Next;
  319. Next = Next->Next;
  320. }
  321. NewAction = YypAllocate(sizeof(YYGEN_ACTION));
  322. if (NewAction == NULL) {
  323. goto CreateReductionActionEnd;
  324. }
  325. NewAction->Next = Next;
  326. NewAction->Symbol = Symbol;
  327. NewAction->Number = RuleIndex;
  328. NewAction->Precedence = Context->Rules[RuleIndex].Precedence;
  329. NewAction->Associativity = Context->Rules[RuleIndex].Associativity;
  330. NewAction->Code = YyActionReduce;
  331. if (Previous != NULL) {
  332. Previous->Next = NewAction;
  333. } else {
  334. Actions = NewAction;
  335. }
  336. YyStatus = YyStatusSuccess;
  337. CreateReductionActionEnd:
  338. if (YyStatus != YyStatusSuccess) {
  339. while (Actions != NULL) {
  340. NewAction = Actions->Next;
  341. YypFree(Actions);
  342. Actions = NewAction;
  343. }
  344. }
  345. return Actions;
  346. }
  347. VOID
  348. YypFindFinalState (
  349. PYYGEN_CONTEXT Context
  350. )
  351. /*++
  352. Routine Description:
  353. This routine locates the acceptance state.
  354. Arguments:
  355. Context - Supplies a pointer to the generator context.
  356. Return Value:
  357. None.
  358. --*/
  359. {
  360. YY_STATE_INDEX FinalState;
  361. YY_VALUE Goal;
  362. YY_VALUE ShiftIndex;
  363. PYYGEN_SHIFTS Shifts;
  364. PYY_STATE_INDEX ToState;
  365. Shifts = Context->ShiftTable[0];
  366. ToState = Shifts->States;
  367. Goal = Context->Items[1];
  368. for (ShiftIndex = Shifts->Count - 1; ShiftIndex >= 0; ShiftIndex -= 1) {
  369. FinalState = ToState[ShiftIndex];
  370. if (Context->AccessingSymbol[FinalState] == Goal) {
  371. Context->FinalState = FinalState;
  372. break;
  373. }
  374. }
  375. assert(Context->FinalState != 0);
  376. return;
  377. }
  378. YY_STATUS
  379. YypRemoveConflicts (
  380. PYYGEN_CONTEXT Context
  381. )
  382. /*++
  383. Routine Description:
  384. This routine picks a solution for and notes grammar conflicts.
  385. Arguments:
  386. Context - Supplies a pointer to the generator context.
  387. Return Value:
  388. YY Status.
  389. --*/
  390. {
  391. PYYGEN_ACTION Action;
  392. PYYGEN_ACTION Preferred;
  393. YY_VALUE ReduceCount;
  394. YY_VALUE ShiftCount;
  395. YY_STATE_INDEX StateIndex;
  396. YY_VALUE Symbol;
  397. YY_STATUS YyStatus;
  398. YyStatus = YyStatusNoMemory;
  399. Context->ShiftReduceConflictCount = 0;
  400. Context->ReduceReduceConflictCount = 0;
  401. Context->ShiftReduceConflicts =
  402. YypAllocate(Context->StateCount * sizeof(YY_VALUE));
  403. if (Context->ShiftReduceConflicts == NULL) {
  404. goto RemoveConflictsEnd;
  405. }
  406. Context->ReduceReduceConflicts =
  407. YypAllocate(Context->StateCount * sizeof(YY_VALUE));
  408. if (Context->ReduceReduceConflicts == NULL) {
  409. goto RemoveConflictsEnd;
  410. }
  411. for (StateIndex = 0; StateIndex < Context->StateCount; StateIndex += 1) {
  412. ShiftCount = 0;
  413. ReduceCount = 0;
  414. Symbol = -1;
  415. Action = Context->Parser[StateIndex];
  416. Preferred = NULL;
  417. while (Action != NULL) {
  418. //
  419. // The first action is the preferred action.
  420. //
  421. if (Action->Symbol != Symbol) {
  422. Preferred = Action;
  423. Symbol = Action->Symbol;
  424. } else if ((StateIndex == Context->FinalState) && (Symbol == 0)) {
  425. ShiftCount += 1;
  426. Action->Suppression = YySuppressedNoisily;
  427. } else if ((Preferred != NULL) &&
  428. (Preferred->Code == YyActionShift)) {
  429. //
  430. // Resolve the conflict with precedences.
  431. //
  432. if ((Preferred->Precedence > 0) && (Action->Precedence > 0)) {
  433. if (Preferred->Precedence < Action->Precedence) {
  434. Preferred->Suppression = YySuppressedQuietly;
  435. Preferred = Action;
  436. } else if (Preferred->Precedence > Action->Precedence) {
  437. Action->Suppression = YySuppressedQuietly;
  438. } else if (Preferred->Associativity == YyLeftAssociative) {
  439. Preferred->Suppression = YySuppressedQuietly;
  440. Preferred = Action;
  441. } else if (Preferred->Associativity == YyRightAssociative) {
  442. Action->Suppression = YySuppressedQuietly;
  443. } else {
  444. Preferred->Suppression = YySuppressedQuietly;
  445. Action->Suppression = YySuppressedQuietly;
  446. }
  447. //
  448. // Add a shift reduce conflict.
  449. //
  450. } else {
  451. ShiftCount += 1;
  452. Action->Suppression = YySuppressedNoisily;
  453. }
  454. } else {
  455. assert((Preferred != NULL) &&
  456. (Preferred->Code == YyActionReduce));
  457. ReduceCount += 1;
  458. Action->Suppression = YySuppressedNoisily;
  459. }
  460. Action = Action->Next;
  461. }
  462. Context->ShiftReduceConflictCount += ShiftCount;
  463. Context->ReduceReduceConflictCount += ReduceCount;
  464. Context->ShiftReduceConflicts[StateIndex] = ShiftCount;
  465. Context->ReduceReduceConflicts[StateIndex] = ReduceCount;
  466. }
  467. YyStatus = YyStatusSuccess;
  468. RemoveConflictsEnd:
  469. return YyStatus;
  470. }
  471. VOID
  472. YypNoticeUnusedRules (
  473. PYYGEN_CONTEXT Context
  474. )
  475. /*++
  476. Routine Description:
  477. This routine sets the context variable of how many rules never reduced.
  478. Arguments:
  479. Context - Supplies a pointer to the generator context.
  480. Return Value:
  481. None.
  482. --*/
  483. {
  484. PYYGEN_ACTION Action;
  485. YY_RULE_INDEX RuleIndex;
  486. YY_STATE_INDEX StateIndex;
  487. Context->UnusedRules = 0;
  488. for (StateIndex = 0; StateIndex < Context->StateCount; StateIndex += 1) {
  489. Action = Context->Parser[StateIndex];
  490. while (Action != NULL) {
  491. if ((Action->Code == YyActionReduce) &&
  492. (Action->Suppression == YyNotSuppressed)) {
  493. Context->Rules[Action->Number].Used = TRUE;
  494. }
  495. Action = Action->Next;
  496. }
  497. }
  498. Context->UnusedRules = 0;
  499. for (RuleIndex = 3; RuleIndex < Context->RuleCount; RuleIndex += 1) {
  500. if (Context->Rules[RuleIndex].Used == FALSE) {
  501. Context->UnusedRules += 1;
  502. }
  503. }
  504. return;
  505. }
  506. YY_STATUS
  507. YypCreateDefaultReductions (
  508. PYYGEN_CONTEXT Context
  509. )
  510. /*++
  511. Routine Description:
  512. This routine creates the default reductions table for states with only
  513. one move: to reduce.
  514. Arguments:
  515. Context - Supplies a pointer to the generator context.
  516. Return Value:
  517. YY Status.
  518. --*/
  519. {
  520. PYY_RULE_INDEX DefaultReductions;
  521. YY_STATE_INDEX StateIndex;
  522. DefaultReductions =
  523. YypAllocate(Context->StateCount * sizeof(YY_RULE_INDEX));
  524. if (DefaultReductions == NULL) {
  525. return YyStatusNoMemory;
  526. }
  527. for (StateIndex = 0; StateIndex < Context->StateCount; StateIndex += 1) {
  528. DefaultReductions[StateIndex] = YypFindSoleReduction(Context,
  529. StateIndex);
  530. }
  531. Context->DefaultReductions = DefaultReductions;
  532. return YyStatusSuccess;
  533. }
  534. YY_RULE_INDEX
  535. YypFindSoleReduction (
  536. PYYGEN_CONTEXT Context,
  537. YY_STATE_INDEX StateIndex
  538. )
  539. /*++
  540. Routine Description:
  541. This routine determines the rule by which to reduce if the given state's
  542. only action is to reduce.
  543. Arguments:
  544. Context - Supplies a pointer to the generator context.
  545. StateIndex - Supplies the state to examine.
  546. Return Value:
  547. 0 if the state does not simply reduce as its only action.
  548. Returns the index of the rule to reduce by if the state simply reduces.
  549. --*/
  550. {
  551. PYYGEN_ACTION Action;
  552. ULONG Count;
  553. YY_RULE_INDEX Rule;
  554. Count = 0;
  555. Rule = 0;
  556. Action = Context->Parser[StateIndex];
  557. while (Action != NULL) {
  558. if (Action->Suppression == YyNotSuppressed) {
  559. if (Action->Code == YyActionShift) {
  560. return 0;
  561. } else if (Action->Code == YyActionReduce) {
  562. //
  563. // Bail if there are multiple possible reductions.
  564. //
  565. if ((Rule > 0) && (Action->Number != Rule)) {
  566. return 0;
  567. }
  568. if (Action->Symbol != -1) {
  569. Count += 1;
  570. }
  571. Rule = Action->Number;
  572. }
  573. }
  574. Action = Action->Next;
  575. }
  576. if (Count == 0) {
  577. return 0;
  578. }
  579. return Rule;
  580. }
  581. VOID
  582. YypPrintAction (
  583. PYYGEN_CONTEXT Context,
  584. PYYGEN_ACTION Action,
  585. YY_STATE_INDEX StateIndex
  586. )
  587. /*++
  588. Routine Description:
  589. This routine prints the given list of actions.
  590. Arguments:
  591. Context - Supplies a pointer to the generator context.
  592. Action - Supplies the head of the action list.
  593. StateIndex - Supplies the state index.
  594. Return Value:
  595. None.
  596. --*/
  597. {
  598. PSTR Verb;
  599. printf("\nActions for state %d:\n", StateIndex);
  600. while (Action) {
  601. Verb = "Shift";
  602. if (Action->Code == YyActionReduce) {
  603. Verb = "Reduce";
  604. }
  605. printf(" %s on %s to %d\n",
  606. Verb,
  607. Context->Elements[Action->Symbol].Name,
  608. Action->Number);
  609. Action = Action->Next;
  610. }
  611. return;
  612. }