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