1 /**
2 
3 	MultiMarkdown 6 -- Lightweight markup processor to produce HTML, LaTeX, and more.
4 
5 	@file parser.y
6 
7 	@brief Use a cleaned copy of the parser grammar to allow "fuzz" testing with
8 	combinations of every line type to find combinations that can't be parsed.
9 	NOTE: This does not mean that each of these combinations is properly parsed,
10 	simply that it does not cause the parser to fail.  Use the test suite to ensure
11 	that input text is properly being parsed.
12 
13 
14 	@author	Fletcher T. Penney
15 	@bug
16 
17 **/
18 
19 /*
20 
21 	Copyright © 2016 - 2017 Fletcher T. Penney.
22 
23 
24 	The `MultiMarkdown 6` project is released under the MIT License..
25 
26 	GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project:
27 
28 		https://github.com/fletcher/MultiMarkdown-4/
29 
30 	MMD 4 is released under both the MIT License and GPL.
31 
32 
33 	CuTest is released under the zlib/libpng license. See CuTest.c for the text
34 	of the license.
35 
36 
37 	## The MIT License ##
38 
39 	Permission is hereby granted, free of charge, to any person obtaining a copy
40 	of this software and associated documentation files (the "Software"), to deal
41 	in the Software without restriction, including without limitation the rights
42 	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
43 	copies of the Software, and to permit persons to whom the Software is
44 	furnished to do so, subject to the following conditions:
45 
46 	The above copyright notice and this permission notice shall be included in
47 	all copies or substantial portions of the Software.
48 
49 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
50 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
51 	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
52 	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
53 	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
54 	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
55 	THE SOFTWARE.
56 
57 */
58 
59 
60 
61 //
62 // Language grammar here
63 //
64 
65 %token_type { int }
66 
67 
68 // Manually copy fallbacks from `parser.y` here
69 
70 %fallback LINE_HR LINE_SETEXT_1 LINE_SETEXT_2.
71 
72 //%fallback LINE_PLAIN LINE_TABLE_SEPARATOR.
73 
74 %fallback LINE_CONTINUATION LINE_INDENTED_TAB LINE_INDENTED_SPACE LINE_TABLE LINE_TABLE_SEPARATOR.
75 
76 %fallback LINE_HTML LINE_ATX_1 LINE_ATX_2 LINE_ATX_3 LINE_ATX_4 LINE_ATX_5 LINE_ATX_6 LINE_BLOCKQUOTE
77 LINE_LIST_BULLETED LINE_LIST_ENUMERATED LINE_DEF_ABBREVIATION LINE_DEF_CITATION LINE_DEF_FOOTNOTE
78 LINE_DEF_GLOSSARY LINE_DEF_LINK LINE_FENCE_BACKTICK LINE_FENCE_BACKTICK_START.
79 
80 
81 // Copy clean grammar via `lemon -g parser.y` here
82 
83 doc ::= blocks.
84 blocks ::= blocks block.
85 blocks ::= block.
86 block ::= LINE_ATX_1.
87 block ::= LINE_ATX_2.
88 block ::= LINE_ATX_3.
89 block ::= LINE_ATX_4.
90 block ::= LINE_ATX_5.
91 block ::= LINE_ATX_6.
92 block ::= LINE_HR.
93 block ::= LINE_TOC.
94 block ::= blockquote.
95 block ::= def_abbreviation.
96 block ::= def_citation.
97 block ::= def_footnote.
98 block ::= def_glossary.
99 block ::= def_link.
100 block ::= definition_block.
101 block ::= empty.
102 block ::= fenced_block.
103 block ::= html_block.
104 block ::= indented_code.
105 block ::= list_bullet.
106 block ::= list_enum.
107 block ::= meta_block.
108 block ::= para.
109 block ::= setext_1.
110 block ::= setext_2.
111 block ::= table.
112 chunk ::= chunk chunk_line.
113 nested_chunks ::= nested_chunks nested_chunk.
114 nested_chunk ::= empty indented_line chunk.
115 nested_chunk ::= empty indented_line.
116 ext_chunk ::= chunk nested_chunks.
117 opt_ext_chunk ::= chunk nested_chunks.
118 blockquote ::= blockquote quote_line.
119 def_citation ::= LINE_DEF_CITATION tail.
120 def_footnote ::= LINE_DEF_FOOTNOTE tail.
121 def_glossary ::= LINE_DEF_GLOSSARY tail.
122 def_link ::= LINE_DEF_LINK chunk.
123 def_abbreviation ::= LINE_DEF_ABBREVIATION chunk.
124 definition_block ::= para defs.
125 defs ::= defs def.
126 def ::= LINE_DEFINITION tail.
127 def ::= LINE_DEFINITION.
128 empty ::= empty LINE_EMPTY.
129 fenced_block ::= fenced_3 LINE_FENCE_BACKTICK_3.
130 fenced_block ::= fenced_3 LINE_FENCE_BACKTICK_4.
131 fenced_block ::= fenced_3 LINE_FENCE_BACKTICK_5.
132 fenced_3 ::= fenced_3 fenced_line.
133 fenced_block ::= fenced_4 LINE_FENCE_BACKTICK_4.
134 fenced_block ::= fenced_4 LINE_FENCE_BACKTICK_5.
135 fenced_4 ::= fenced_4 fenced_line.
136 fenced_4 ::= fenced_4 LINE_FENCE_BACKTICK_3.
137 fenced_4 ::= fenced_4 LINE_FENCE_BACKTICK_START_3.
138 fenced_block ::= fenced_5 LINE_FENCE_BACKTICK_5.
139 fenced_5 ::= fenced_5 fenced_line.
140 fenced_5 ::= fenced_5 LINE_FENCE_BACKTICK_3.
141 fenced_5 ::= fenced_5 LINE_FENCE_BACKTICK_START_3.
142 fenced_5 ::= fenced_5 LINE_FENCE_BACKTICK_4.
143 fenced_5 ::= fenced_5 LINE_FENCE_BACKTICK_START_4.
144 html_block ::= html_block html_line.
145 indented_code ::= indented_code indented_line.
146 indented_code ::= indented_code LINE_EMPTY.
147 list_bullet ::= list_bullet item_bullet.
148 item_bullet ::= LINE_LIST_BULLETED ext_chunk.
149 item_bullet ::= LINE_LIST_BULLETED chunk.
150 item_bullet ::= LINE_LIST_BULLETED nested_chunks.
151 item_bullet ::= LINE_LIST_BULLETED.
152 list_enum ::= list_enum item_enum.
153 item_enum ::= LINE_LIST_ENUMERATED ext_chunk.
154 item_enum ::= LINE_LIST_ENUMERATED chunk.
155 item_enum ::= LINE_LIST_ENUMERATED nested_chunks.
156 item_enum ::= LINE_LIST_ENUMERATED.
157 meta_block ::= meta_block meta_line.
158 para ::= LINE_PLAIN chunk.
159 setext_1 ::= para LINE_SETEXT_1.
160 setext_2 ::= para LINE_SETEXT_2.
161 table ::= table_header table_body.
162 table_header ::= header_rows LINE_TABLE_SEPARATOR.
163 header_rows ::= header_rows LINE_TABLE.
164 table_body ::= table_body table_section.
165 table_section ::= all_rows LINE_EMPTY.
166 table_section ::= all_rows.
167 all_rows ::= all_rows row.
168 para ::= all_rows.
169 chunk ::= chunk_line.
170 chunk_line ::= LINE_CONTINUATION.
171 nested_chunks ::= nested_chunk.
172 nested_chunk ::= empty.
173 indented_line ::= LINE_INDENTED_TAB.
174 indented_line ::= LINE_INDENTED_SPACE.
175 opt_ext_chunk ::= chunk.
176 tail ::= opt_ext_chunk.
177 tail ::= nested_chunks.
178 blockquote ::= LINE_BLOCKQUOTE.
179 quote_line ::= LINE_BLOCKQUOTE.
180 quote_line ::= LINE_CONTINUATION.
181 def_citation ::= LINE_DEF_CITATION.
182 def_footnote ::= LINE_DEF_FOOTNOTE.
183 def_glossary ::= LINE_DEF_GLOSSARY.
184 def_link ::= LINE_DEF_LINK.
185 def_abbreviation ::= LINE_DEF_ABBREVIATION.
186 defs ::= def.
187 empty ::= LINE_EMPTY.
188 fenced_block ::= fenced_3.
189 fenced_3 ::= LINE_FENCE_BACKTICK_3.
190 fenced_3 ::= LINE_FENCE_BACKTICK_START_3.
191 fenced_block ::= fenced_4.
192 fenced_4 ::= LINE_FENCE_BACKTICK_4.
193 fenced_4 ::= LINE_FENCE_BACKTICK_START_4.
194 fenced_block ::= fenced_5.
195 fenced_5 ::= LINE_FENCE_BACKTICK_5.
196 fenced_5 ::= LINE_FENCE_BACKTICK_START_5.
197 fenced_line ::= LINE_CONTINUATION.
198 fenced_line ::= LINE_EMPTY.
199 fenced_line ::= LINE_SETEXT_1.
200 fenced_line ::= LINE_SETEXT_2.
201 html_block ::= LINE_HTML.
202 html_line ::= LINE_CONTINUATION.
203 html_line ::= LINE_HTML.
204 indented_code ::= indented_line.
205 list_bullet ::= item_bullet.
206 list_enum ::= item_enum.
207 meta_block ::= LINE_META.
208 meta_line ::= LINE_META.
209 meta_line ::= LINE_CONTINUATION.
210 para ::= LINE_PLAIN.
211 table ::= table_header.
212 header_rows ::= LINE_TABLE.
213 table_body ::= table_section.
214 all_rows ::= row.
215 row ::= header_rows.
216 row ::= LINE_TABLE_SEPARATOR.
217 para ::= defs.
218 
219 
220 //
221 // Additional Configuration
222 //
223 
224 %include {
225 	#include <assert.h>
226 	#include <stdio.h>
227 	#include <stdlib.h>
228 	#include "parser_test.h"
229 
230 	// Basic parser function declarations
231 	void * ParseAlloc();
232 	void Parse();
233 	void ParseFree();
234 	void ParseTrace();
235 
236 	#define kMaxToken 36
237 
238 	int i,j,k,l,m, n;
239 
main(int argc,char ** argv)240 int main(int argc, char** argv) {
241 
242 	void* pParser = ParseAlloc (malloc);		// Create a parser (for lemon)
243 
244 #ifndef NDEBUG
245 	ParseTrace(stderr, "parser >>");
246 #endif
247 
248 
249 	fprintf(stderr, "Single line tests\n");
250 
251 	i = 0;
252 	j = 0;
253 	k = 0;
254 	l = 0;
255 	m = 0;
256 	n = 0;
257 
258 	for (i = 1; i <= kMaxToken; ++i)
259 	{
260 		// LINE_CONTINUATION can't be the first line
261 		if (i == LINE_CONTINUATION)
262 			break;
263 
264 		Parse(pParser, i, NULL);
265 
266 		Parse(pParser, 0, NULL);
267 	}
268 
269 	fprintf(stderr, "\nDouble line tests\n");
270 
271 	i = 0;
272 	j = 0;
273 	k = 0;
274 	l = 0;
275 	m = 0;
276 
277 	for (i = 1; i <= kMaxToken; ++i)
278 	{
279 		// LINE_CONTINUATION can't be the first line
280 		if (i == LINE_CONTINUATION)
281 			break;
282 
283 		for (j = 1; j <= kMaxToken; ++j) {
284 
285 			Parse(pParser, i, NULL);
286 			Parse(pParser, j, NULL);
287 
288 			Parse(pParser, 0, NULL);
289 		}
290 	}
291 
292 	fprintf(stderr, "\nTriple line tests\n");
293 
294 	i = 0;
295 	j = 0;
296 	k = 0;
297 	l = 0;
298 	m = 0;
299 
300 	for (i = 1; i <= kMaxToken; ++i)
301 	{
302 		// LINE_CONTINUATION can't be the first line
303 		if (i == LINE_CONTINUATION)
304 			break;
305 
306 		for (j = 1; j <= kMaxToken; ++j) {
307 
308 			for (k = 1; k <= kMaxToken; ++k) {
309 
310 				Parse(pParser, i, NULL);
311 				Parse(pParser, j, NULL);
312 				Parse(pParser, k, NULL);
313 
314 				Parse(pParser, 0, NULL);
315 			}
316 		}
317 	}
318 
319 //	return(0);
320 
321 	fprintf(stderr, "\nQuad line tests\n");
322 
323 	i = 0;
324 	j = 0;
325 	k = 0;
326 	l = 0;
327 	m = 0;
328 
329 	for (i = 1; i <= kMaxToken; ++i)
330 	{
331 		// LINE_CONTINUATION can't be the first line
332 		if (i == LINE_CONTINUATION)
333 			break;
334 
335 		for (j = 1; j <= kMaxToken; ++j) {
336 
337 			for (k = 1; k <= kMaxToken; ++k) {
338 
339 				for (l = 1; l <= kMaxToken; ++l) {
340 
341 					Parse(pParser, i, NULL);
342 					Parse(pParser, j, NULL);
343 					Parse(pParser, k, NULL);
344 					Parse(pParser, l, NULL);
345 
346 					Parse(pParser, 0, NULL);
347 				}
348 			}
349 		}
350 	}
351 
352 //	return(0);
353 
354 	fprintf(stderr, "\nFive line tests\n");
355 
356 	i = 0;
357 	j = 0;
358 	k = 0;
359 	l = 0;
360 	m = 0;
361 
362 	for (i = 1; i <= kMaxToken; ++i)
363 	{
364 		// LINE_CONTINUATION can't be the first line
365 		if (i == LINE_CONTINUATION)
366 			break;
367 
368 		for (j = 1; j <= kMaxToken; ++j) {
369 
370 			for (k = 1; k <= kMaxToken; ++k) {
371 
372 				for (l = 1; l <= kMaxToken; ++l) {
373 
374 					for (m = 1; m <= kMaxToken; ++m) {
375 
376 						Parse(pParser, i, NULL);
377 						Parse(pParser, j, NULL);
378 						Parse(pParser, k, NULL);
379 						Parse(pParser, l, NULL);
380 						Parse(pParser, m, NULL);
381 
382 						Parse(pParser, 0, NULL);
383 					}
384 				}
385 			}
386 		}
387 	}
388 
389 	return(0);
390 
391 	// Six cycles takes quite a while
392 
393 	fprintf(stderr, "\nSix line tests\n");
394 
395 	i = 0;
396 	j = 0;
397 	k = 0;
398 	l = 0;
399 	m = 0;
400 	n = 0;
401 
402 	for (i = 1; i <= kMaxToken; ++i)
403 	{
404 		// LINE_CONTINUATION can't be the first line
405 		if (i == LINE_CONTINUATION)
406 			break;
407 
408 		fprintf(stderr, "%d\n", i);
409 
410 		for (j = 1; j <= kMaxToken; ++j) {
411 
412 			for (k = 1; k <= kMaxToken; ++k) {
413 
414 				for (l = 1; l <= kMaxToken; ++l) {
415 
416 					for (m = 1; m <= kMaxToken; ++m) {
417 
418 						for (n = 1; n <= kMaxToken; ++n) {
419 							Parse(pParser, i, NULL);
420 							Parse(pParser, j, NULL);
421 							Parse(pParser, k, NULL);
422 							Parse(pParser, l, NULL);
423 							Parse(pParser, m, NULL);
424 							Parse(pParser, n, NULL);
425 
426 							Parse(pParser, 0, NULL);
427 						}
428 					}
429 				}
430 			}
431 		}
432 	}
433 }
434 
435 }
436 
437 
438 // Improved error messages for debugging:
439 //	http://stackoverflow.com/questions/11705737/expected-token-using-lemon-parser-generator
440 
441 %syntax_error {
442 #ifndef NDEBUG
443 	fprintf(stderr,"Parser syntax error.\n");
444 	int n = sizeof(yyTokenName) / sizeof(yyTokenName[0]);
445 	for (i = 0; i < n; ++i) {
446 		int a = yy_find_shift_action(yypParser, (YYCODETYPE)i);
447 		if (a < YYNSTATE + YYNRULE) {
448 			fprintf(stderr,"expected token: %s\n", yyTokenName[i]);
449 		}
450 	}
451 #endif
452 }
453 
454 %parse_failure {
455 	fprintf(stderr, "%d:%d:%d:%d:%d:%d Parser failed to successfully parse.\n", i, j, k, l, m, n);
456 }
457 
458