1 /*
2 ** The author of this program disclaims copyright.
3 */
4 
5 #include <stdio.h>
6 #include <stdarg.h>
7 #include <string.h>
8 #include <ctype.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 
12 #include "lemon_dims.h"
13 #include "lemon_option.h"
14 #include "lemon_structs.h"
15 #include "lemon_string.h"
16 #include "lemon_set.h"
17 #include "lemon_report.h"
18 #include "lemon_symbol.h"
19 #include "lemon_state_table.h"
20 #include "lemon_fsm.h"
21 #include "lemon_parse.h"
22 
23 // ----------------------------------------------------------------
24 static int nDefine = 0;      /* Number of -D options on the command line */
25 static char **azDefine = 0;  /* Name of the -D macros */
26 
27 /* This routine is called with the argument to each -D command-line option.
28 ** Add the macro defined to the azDefine array.
29 */
handle_D_option(char * z)30 static void handle_D_option(char *z) {
31 	char **paz;
32 	nDefine++;
33 	azDefine = realloc(azDefine, sizeof(azDefine[0])*nDefine);
34 	if (azDefine == 0) {
35 		fprintf(stderr,"out of memory\n");
36 		exit(1);
37 	}
38 	paz = &azDefine[nDefine-1];
39 	*paz = malloc (strlen(z)+1) ;
40 	if (*paz == 0) {
41 		fprintf(stderr, "out of memory\n");
42 		exit(1);
43 	}
44 	strcpy(*paz, z);
45 	for(z=*paz; *z && *z!='='; z++){}
46 	*z = 0;
47 }
48 
49 
50 /* Lemon entry point */
main(int argc,char ** argv)51 int main(int argc, char **argv) {
52 	static int version    = 0;
53 	static int rpflag     = 0;
54 	static int basisflag  = 0;
55 	static int compress   = 0;
56 	static int quiet      = 0;
57 	static int statistics = 0;
58 	static int mhflag     = 0;
59 	static int suppress_line_directives = 0;
60 
61 	static struct s_options options[] = {
62 		{OPT_FLAG, "b", (char*)&basisflag,      "Print only the basis in report."},
63 		{OPT_FLAG, "c", (char*)&compress,       "Don't compress the action table."},
64 		{OPT_FSTR, "D", (char*)handle_D_option, "Define an %ifdef macro."},
65 		{OPT_FLAG, "g", (char*)&rpflag,         "Print grammar without actions."},
66 		{OPT_FLAG, "m", (char*)&mhflag,         "Output a makeheaders compatible file"},
67 		{OPT_FLAG, "q", (char*)&quiet,          "(Quiet) Don't print the report file."},
68 		{OPT_FLAG, "s", (char*)&statistics,     "Print parser stats to standard output."},
69 		{OPT_FLAG, "l", (char*)&suppress_line_directives,     "Don't put #line directives in autogenned code."},
70 		{OPT_FLAG, "x", (char*)&version,        "Print the version number."},
71 		{OPT_FLAG,0,0,0}
72 	};
73 	int i;
74 	struct lemon lem;
75 
76 	OptInit(argv, options, stderr);
77 	if (version) {
78 		 printf("Lemon version 1.0.1\n");
79 		 exit(0);
80 	}
81 	if (OptNArgs()!=1) {
82 		fprintf(stderr,"Exactly one filename argument is required.\n");
83 		exit(1);
84 	}
85 	lem.errorcnt = 0;
86 
87 	/* Initialize the machine */
88 	Strsafe_init();
89 	Symbol_init();
90 	State_init();
91 	lem.argv0 = argv[0];
92 	lem.filename = OptArg(0);
93 	lem.basisflag = basisflag;
94 	lem.has_fallback = 0;
95 	lem.nconflict = 0;
96 	lem.name = lem.include = lem.arg = lem.tokentype = lem.start = 0;
97 	lem.vartype = 0;
98 	lem.stacksize = 0;
99 	lem.error = lem.overflow = lem.failure = lem.accept = lem.tokendest =
100 		 lem.tokenprefix = lem.outname = lem.extracode = 0;
101 	lem.vardest = 0;
102 	lem.tablesize = 0;
103 	Symbol_new("$");
104 	lem.errsym = Symbol_new("error");
105 
106 	/* Parse the input file */
107 	Parse(&lem, nDefine, azDefine);
108 	if (lem.errorcnt)
109 		exit(lem.errorcnt);
110 	if (lem.rule==0) {
111 		fprintf(stderr, "Empty grammar.\n");
112 		exit(1);
113 	}
114 
115 	/* Count and index the symbols of the grammar */
116 	lem.nsymbol = Symbol_count();
117 	Symbol_new("{default}");
118 	lem.symbols = Symbol_arrayof();
119 	for (i = 0; i <= lem.nsymbol; i++)
120 		lem.symbols[i]->index = i;
121 	qsort(lem.symbols,lem.nsymbol+1,sizeof(struct symbol*), (int(*)())Symbolcmpp);
122 	for (i = 0; i <= lem.nsymbol; i++)
123 		lem.symbols[i]->index = i;
124 	for (i = 1; isupper(lem.symbols[i]->name[0]); i++)
125 		;
126 	lem.nterminal = i;
127 
128 	/* Generate a reprint of the grammar, if requested on the command line */
129 	if (rpflag) {
130 		Reprint(&lem);
131 	} else {
132 		/* Initialize the size for all follow and first sets */
133 		SetSize(lem.nterminal);
134 
135 		/* Find the precedence for every production rule (that has one) */
136 		FindRulePrecedences(&lem);
137 
138 		/* Compute the lambda-nonterminals and the first-sets for every
139 		** nonterminal */
140 		FindFirstSets(&lem);
141 
142 		/* Compute all LR(0) states.  Also record follow-set propagation
143 		** links so that the follow-set can be computed later */
144 		lem.nstate = 0;
145 		FindStates(&lem);
146 		lem.sorted = State_arrayof();
147 
148 		/* Tie up loose ends on the propagation links */
149 		FindLinks(&lem);
150 
151 		/* Compute the follow set of every reducible configuration */
152 		FindFollowSets(&lem);
153 
154 		/* Compute the action tables */
155 		FindActions(&lem);
156 
157 		/* Compress the action tables */
158 		if (compress==0)
159 			CompressTables(&lem);
160 
161 		/* Generate a report of the parser generated (the "y.output" file) */
162 		if (!quiet)
163 			ReportOutput(&lem);
164 
165 		/* Generate the source code for the parser */
166 		ReportTable(&lem, mhflag, suppress_line_directives);
167 
168 		/* Produce a header file for use by the scanner.  (This step is
169 		** omitted if the "-m" option is used because makeheaders will
170 		** generate the file for us.) */
171 		if (!mhflag)
172 			ReportHeader(&lem);
173 	}
174 	if (statistics) {
175 		printf("Parser statistics: %d terminals, %d nonterminals, %d rules\n",
176 			lem.nterminal, lem.nsymbol - lem.nterminal, lem.nrule);
177 		printf("                   %d states, %d parser table entries, %d conflicts\n",
178 			lem.nstate, lem.tablesize, lem.nconflict);
179 	}
180 	if (lem.nconflict) {
181 		fprintf(stderr,"%d resolvable parsing conflicts.\n",lem.nconflict);
182 	}
183 	//exit(lem.errorcnt + lem.nconflict);
184 	// JRK 2016-05-23
185 	// According to the manual, these conflicts are resolved by taking the first match.
186 	// This is OK for my purposes.
187 	//return (lem.errorcnt + lem.nconflict);
188 	return (lem.errorcnt);
189 }
190