yygen.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541
  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. yygen.c
  9. Abstract:
  10. This module implements the Minoca grammar generator.
  11. Author:
  12. Evan Green 9-Apr-2016
  13. Environment:
  14. Build
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include "yygenp.h"
  20. #include <stdlib.h>
  21. #include <string.h>
  22. //
  23. // ---------------------------------------------------------------- Definitions
  24. //
  25. //
  26. // ------------------------------------------------------ Data Type Definitions
  27. //
  28. //
  29. // ----------------------------------------------- Internal Function Prototypes
  30. //
  31. YY_STATUS
  32. YypInitializeGeneratorContext (
  33. PYYGEN_CONTEXT Context
  34. );
  35. //
  36. // -------------------------------------------------------------------- Globals
  37. //
  38. //
  39. // ------------------------------------------------------------------ Functions
  40. //
  41. YY_STATUS
  42. YyGenerateGrammar (
  43. PYY_GRAMMAR_DESCRIPTION Description,
  44. ULONG Flags,
  45. PYYGEN_CONTEXT *NewContext
  46. )
  47. /*++
  48. Routine Description:
  49. This routine converts a given grammar description into an LALR(1) grammar.
  50. Arguments:
  51. Description - Supplies a pointer to the grammar description.
  52. Flags - Supplies a bitfield of flags. See YYGEN_FLAG_* definitions.
  53. NewContext - Supplies a pointer where a pointer to the grammar context will
  54. be returned on success.
  55. Return Value:
  56. YY status.
  57. --*/
  58. {
  59. PYYGEN_CONTEXT Context;
  60. YY_STATUS YyStatus;
  61. Context = YypAllocate(sizeof(YYGEN_CONTEXT));
  62. if (Context == NULL) {
  63. YyStatus = YyStatusNoMemory;
  64. goto GenerateGrammarEnd;
  65. }
  66. memset(Context, 0, sizeof(YYGEN_CONTEXT));
  67. Context->Flags = Flags;
  68. Context->Elements = Description->Elements;
  69. Context->TokenCount = Description->TokenCount;
  70. Context->SymbolCount = Description->SymbolCount;
  71. Context->ExpectedShiftReduceConflicts =
  72. Description->ExpectedShiftReduceConflicts;
  73. Context->ExpectedReduceReduceConflicts =
  74. Description->ExpectedReduceReduceConflicts;
  75. Context->VariablePrefix = Description->VariablePrefix;
  76. Context->OutputFileName = Description->OutputFileName;
  77. YyStatus = YypInitializeGeneratorContext(Context);
  78. if (YyStatus != YyStatusSuccess) {
  79. goto GenerateGrammarEnd;
  80. }
  81. //
  82. // Start by creating the LR(0) parser.
  83. //
  84. YyStatus = YypGenerateLr0Grammar(Context);
  85. if (YyStatus != YyStatusSuccess) {
  86. goto GenerateGrammarEnd;
  87. }
  88. //
  89. // Augment with lookaheads to produce an LALR(1) parser.
  90. //
  91. YyStatus = YypGenerateLalr(Context);
  92. if (YyStatus != YyStatusSuccess) {
  93. goto GenerateGrammarEnd;
  94. }
  95. //
  96. // Allocate and initialize the parser constructs.
  97. //
  98. YyStatus = YypBuildParser(Context);
  99. if (YyStatus != YyStatusSuccess) {
  100. goto GenerateGrammarEnd;
  101. }
  102. GenerateGrammarEnd:
  103. if (YyStatus != YyStatusSuccess) {
  104. if (Context != NULL) {
  105. YyDestroyGeneratorContext(Context);
  106. Context = NULL;
  107. }
  108. }
  109. *NewContext = Context;
  110. return YyStatus;
  111. }
  112. VOID
  113. YyDestroyGeneratorContext (
  114. PYYGEN_CONTEXT Context
  115. )
  116. /*++
  117. Routine Description:
  118. This routine destroys a grammar generator context structure.
  119. Arguments:
  120. Context - Supplies a pointer to the generator context.
  121. Return Value:
  122. None.
  123. --*/
  124. {
  125. PYYGEN_ACTION Action;
  126. YY_VALUE Index;
  127. PVOID Next;
  128. PYYGEN_REDUCTIONS Reduction;
  129. PYYGEN_SHIFTS Shift;
  130. PYYGEN_STATE State;
  131. if (Context->Nullable != NULL) {
  132. YypFree(Context->Nullable);
  133. }
  134. if (Context->Items != NULL) {
  135. YypFree(Context->Items);
  136. }
  137. if (Context->Rules != NULL) {
  138. YypFree(Context->Rules);
  139. }
  140. if (Context->Derives != NULL) {
  141. YypFree(Context->Derives);
  142. }
  143. if (Context->ItemSet != NULL) {
  144. YypFree(Context->ItemSet);
  145. }
  146. if (Context->RuleSet != NULL) {
  147. YypFree(Context->RuleSet);
  148. }
  149. if (Context->FirstDerives != NULL) {
  150. YypFree(Context->FirstDerives);
  151. }
  152. if (Context->StateTable != NULL) {
  153. YypFree(Context->StateTable);
  154. }
  155. State = Context->FirstState;
  156. while (State != NULL) {
  157. Next = State->Next;
  158. YypFree(State);
  159. State = Next;
  160. }
  161. if (Context->ShiftTable != NULL) {
  162. YypFree(Context->ShiftTable);
  163. }
  164. Shift = Context->FirstShift;
  165. while (Shift != NULL) {
  166. Next = Shift->Next;
  167. YypFree(Shift);
  168. Shift = Next;
  169. }
  170. if (Context->ReductionTable != NULL) {
  171. YypFree(Context->ReductionTable);
  172. }
  173. Reduction = Context->FirstReduction;
  174. while (Reduction != NULL) {
  175. Next = Reduction->Next;
  176. YypFree(Reduction);
  177. Reduction = Next;
  178. }
  179. if (Context->Lookaheads != NULL) {
  180. YypFree(Context->Lookaheads);
  181. }
  182. if (Context->LookaheadSets != NULL) {
  183. YypFree(Context->LookaheadSets);
  184. }
  185. if (Context->LookaheadRule != NULL) {
  186. YypFree(Context->LookaheadRule);
  187. }
  188. if (Context->GotoMap != NULL) {
  189. YypFree(Context->GotoMap);
  190. }
  191. if (Context->FromState != NULL) {
  192. YypFree(Context->FromState);
  193. }
  194. if (Context->ToState != NULL) {
  195. YypFree(Context->ToState);
  196. }
  197. if (Context->Parser != NULL) {
  198. for (Index = 0; Index < Context->StateCount; Index += 1) {
  199. Action = Context->Parser[Index];
  200. while (Action != NULL) {
  201. Next = Action->Next;
  202. YypFree(Action);
  203. Action = Next;
  204. }
  205. }
  206. YypFree(Context->Parser);
  207. }
  208. if (Context->ShiftReduceConflicts != NULL) {
  209. YypFree(Context->ShiftReduceConflicts);
  210. }
  211. if (Context->ReduceReduceConflicts != NULL) {
  212. YypFree(Context->ReduceReduceConflicts);
  213. }
  214. if (Context->DefaultReductions != NULL) {
  215. YypFree(Context->DefaultReductions);
  216. }
  217. YypFree(Context);
  218. return;
  219. }
  220. VOID
  221. YyGetConflictCounts (
  222. PYYGEN_CONTEXT Context,
  223. PYY_VALUE ShiftReduceConflicts,
  224. PYY_VALUE ReduceReduceConflicts
  225. )
  226. /*++
  227. Routine Description:
  228. This routine returns the number of conflicts in the grammar, minus the
  229. number of expected conflicts.
  230. Arguments:
  231. Context - Supplies a pointer to the generator context.
  232. ShiftReduceConflicts - Supplies an optional pointer where the number of
  233. shift-reduce conflicts will be returned.
  234. ReduceReduceConflicts - Supplies an optional pointer where the number of
  235. reduce-reduce conflicts will be returned.
  236. Return Value:
  237. None.
  238. --*/
  239. {
  240. if (ShiftReduceConflicts != NULL) {
  241. *ShiftReduceConflicts = Context->ShiftReduceConflictCount -
  242. Context->ExpectedShiftReduceConflicts;
  243. }
  244. if (ReduceReduceConflicts != NULL) {
  245. *ReduceReduceConflicts = Context->ReduceReduceConflictCount -
  246. Context->ExpectedReduceReduceConflicts;
  247. }
  248. return;
  249. }
  250. PVOID
  251. YypAllocate (
  252. UINTN Size
  253. )
  254. /*++
  255. Routine Description:
  256. This routine allocates and clears a region of memory.
  257. Arguments:
  258. Size - Supplies the size in bytes of the allocation.
  259. Return Value:
  260. Returns a pointer to the new memory on success.
  261. NULL on failure.
  262. --*/
  263. {
  264. PVOID Allocation;
  265. Allocation = calloc(Size, 1);
  266. return Allocation;
  267. }
  268. PVOID
  269. YypReallocate (
  270. PVOID Allocation,
  271. UINTN NewSize
  272. )
  273. /*++
  274. Routine Description:
  275. This routine reallocates previously allocated memory.
  276. Arguments:
  277. Allocation - Supplies an optional pointer to the memory to reallocate.
  278. NewSize - Supplies the desired size of the allocation.
  279. Return Value:
  280. Returns a pointer to the newly sized buffer on success. This might be the
  281. same buffer passed in or a new buffer. The old buffer will be invalid
  282. after this.
  283. NULL on reallocation failure. The old buffer will remain valid and still
  284. needs to be freed.
  285. --*/
  286. {
  287. PVOID NewAllocation;
  288. NewAllocation = realloc(Allocation, NewSize);
  289. return NewAllocation;
  290. }
  291. VOID
  292. YypFree (
  293. PVOID Allocation
  294. )
  295. /*++
  296. Routine Description:
  297. This routine frees a previously allocated region of memory.
  298. Arguments:
  299. Allocation - Supplies a pointer to the allocation to free.
  300. Return Value:
  301. None.
  302. --*/
  303. {
  304. free(Allocation);
  305. return;
  306. }
  307. //
  308. // --------------------------------------------------------- Internal Functions
  309. //
  310. YY_STATUS
  311. YypInitializeGeneratorContext (
  312. PYYGEN_CONTEXT Context
  313. )
  314. /*++
  315. Routine Description:
  316. This routine initializes a grammar context structure.
  317. Arguments:
  318. Context - Supplies a pointer to the generator context.
  319. Return Value:
  320. YY status.
  321. --*/
  322. {
  323. PYY_VALUE Components;
  324. YY_VALUE ElementIndex;
  325. YY_VALUE ItemCount;
  326. YY_VALUE RuleCount;
  327. //
  328. // Verify that the tokens do not have productions.
  329. //
  330. for (ElementIndex = 0;
  331. ElementIndex < Context->TokenCount;
  332. ElementIndex += 1) {
  333. if (Context->Elements[ElementIndex].Components != NULL) {
  334. return YyStatusInvalidSpecification;
  335. }
  336. }
  337. if (Context->SymbolCount <= Context->TokenCount) {
  338. return YyStatusInvalidSpecification;
  339. }
  340. if (Context->Elements[ElementIndex].Components != NULL) {
  341. return YyStatusInvalidSpecification;
  342. }
  343. //
  344. // Count the productions and items. There are 3 extra rules:
  345. // Rule 0 is invalid (since it can't be negated).
  346. // Rule 1 is empty.
  347. // Rule 2 is the start rule.
  348. // Token zero is always assumed to be the end-of-file marker.
  349. //
  350. ItemCount = 4;
  351. RuleCount = 3;
  352. for (ElementIndex = Context->TokenCount + 1;
  353. ElementIndex < Context->SymbolCount;
  354. ElementIndex += 1) {
  355. if ((Context->Elements[ElementIndex].Flags & YY_ELEMENT_START) != 0) {
  356. if (Context->StartSymbol != 0) {
  357. return YyStatusInvalidSpecification;
  358. }
  359. Context->StartSymbol = ElementIndex;
  360. }
  361. Components = Context->Elements[ElementIndex].Components;
  362. if (Components == NULL) {
  363. return YyStatusInvalidSpecification;
  364. }
  365. while (*Components != 0) {
  366. if (*Components < 0) {
  367. RuleCount += 1;
  368. }
  369. ItemCount += 1;
  370. Components += 1;
  371. }
  372. }
  373. Context->ItemCount = ItemCount;
  374. Context->RuleCount = RuleCount;
  375. //
  376. // The first symbol is the start symbol.
  377. //
  378. Context->NonTerminalCount = Context->SymbolCount - Context->TokenCount;
  379. return YyStatusSuccess;
  380. }