Pristine Ack-5.5
[Ack-5.5.git] / util / LLgen / src / main.c
1 /* Copyright (c) 1991 by the Vrije Universiteit, Amsterdam, the Netherlands.
2  * For full copyright and restrictions on use see the file COPYING in the top
3  * level of the LLgen tree.
4  */
5
6 /*
7  *  L L G E N
8  *
9  *  An Extended LL(1) Parser Generator
10  *
11  *  Author : Ceriel J.H. Jacobs
12  */
13
14 /*
15  * main.c
16  * Contains main program, and some error message routines
17  */
18
19 # include "types.h"
20 # include "io.h"
21 # include "extern.h"
22 # include "sets.h"
23 # include "assert.h"
24
25 # ifndef NORCSID
26 static string rcsid6 = "$Id: main.c,v 2.26 2002/09/11 13:32:57 ceriel Exp $";
27 # endif
28
29 /* In this file the following routines are defined: */
30 extern int      main();
31 STATIC          readgrammar();
32 STATIC          doparse();
33 extern          error();
34 extern          fatal();
35 extern          comfatal();
36 extern          copyfile();
37 extern          install();
38 extern char     *mktemp();
39 extern char     *sbrk();
40
41 main(argc,argv) register string argv[]; {
42         register string arg;
43         string libpath();
44         char    *beg_sbrk = 0;
45
46         /* Initialize */
47
48         assval = 0400;
49         /* read options */
50
51         while (argc >= 2 && (arg = argv[1], *arg == '-')) {
52                 while (*++arg) {
53                         switch(*arg) {
54                           case 'j':
55                           case 'J':
56                                 jmptable_option = 1;
57                                 if (*++arg)
58                                         min_cases_for_jmptable = atoi(arg);
59                                 break;
60                           case 'w':
61                           case 'W':
62                                 wflag = 1;
63                                 continue;
64                           case 'v':
65                           case 'V':
66                                 verbose++;
67                                 continue;
68                           case 'l':
69                           case 'L':
70                                 low_percentage = atoi(++arg);
71                                 break;
72                           case 'h':
73                           case 'H':
74                                 high_percentage = atoi(++arg);
75                                 break;
76 # ifndef NDEBUG
77                           case 'd':
78                           case 'D':
79                                 debug++;
80                                 continue;
81                           case 'r':
82                           case 'R':
83                                 if (rec_file) {
84                                         fprintf(stderr,"duplicate -r flag\n");
85                                         exit(1);
86                                 }
87                                 rec_file = ++arg;
88                                 break;
89                           case 'i':
90                           case 'I':
91                                 if (incl_file) {
92                                         fprintf(stderr,"duplicate -i flag\n");
93                                         exit(1);
94                                 }
95                                 incl_file = ++arg;
96                                 break;
97 #endif /* not NDEBUG */
98                           case 'x':
99                           case 'X':
100                                 ntneeded = 1;
101                                 ntprint = 1;
102                                 continue;
103                           case 'a':
104                           case 'A':
105                                 ansi_c = 1;
106                                 continue;
107 #ifdef NON_CORRECTING
108                           case 'n':
109                           case 'N':
110                                 non_corr = 1;
111                                 continue;
112                           case 's':
113                           case 'S':
114                                 subpars_sim = 1;
115                                 continue;
116 #endif
117                           case 'g':
118                           case 'G':
119                                 strip_grammar = 1;
120                                 continue;
121                           default:
122                                 fprintf(stderr,"illegal option : %c\n",*arg);
123                                 exit(1);
124                         }
125                         break;
126                 }
127                 argv++;
128                 argc--;
129         }
130
131         if (verbose) beg_sbrk = sbrk(0);
132
133 #ifdef NON_CORRECTING
134         if ((subpars_sim) && (!non_corr)) {
135             fprintf(stderr,"option -s illegal without -n, turned off\n");
136             subpars_sim = 0;
137         }
138 #endif
139
140         /*
141          * Now check wether the sets should include nonterminals
142          */
143         if (verbose == 2) ntneeded = 1;
144         /*
145          * Initialise
146          */
147 # ifndef NDEBUG
148         if (!rec_file) {
149 # endif
150                 rec_file = libpath("rec");
151 # ifndef NDEBUG
152         }
153         if (!incl_file) {
154 # endif
155                 incl_file = libpath("incl");
156 # ifndef NDEBUG
157         }
158 # endif
159 #ifdef NON_CORRECTING
160         if (non_corr) {
161             nc_incl_file = libpath("nc_incl");
162             nc_rec_file = libpath ("nc_rec");
163         }
164 #endif
165         mktemp(f_temp);
166         mktemp(f_pars);
167         if ((fact = fopen(f_temp,"w")) == NULL) {
168                 fputs("Cannot create temporary\n",stderr);
169                 exit(1);
170         }
171         name_init();
172         readgrammar(argc,argv);
173         sprintf(f_out, OUTFILE, prefix ? prefix : "LL");
174
175         /* for the following two filenames only one L is used; historical
176            reasons ...
177         */
178         sprintf(f_include, HFILE, prefix ? prefix : "L");
179         sprintf(f_rec, RFILE, prefix ? prefix : "L");
180 #ifdef NON_CORRECTING
181         if (non_corr)
182             sprintf(f_nc, NCFILE, prefix ? prefix : "L");
183 #endif
184         setinit(ntneeded);
185         maxnt = &nonterms[nnonterms];
186         maxt = &tokens[ntokens];
187         /*
188          * Now, the grammar is read. Do some computations
189          */
190         co_reach();             /* Check for undefined and unreachable */
191         if (nerrors) comfatal();
192         do_compute();
193         conflchecks();
194         if (nerrors) comfatal();
195         fclose(fact);
196         if (argc-- == 1) {
197                 fputs("No code generation for input from standard input\n",
198                       stderr);
199         }
200         else    gencode(argc);
201         UNLINK(f_temp);
202         UNLINK(f_pars);
203         if (verbose) {
204                 fprintf(stderr, "number of nonterminals: %d\n", nnonterms);
205                 fprintf(stderr, "number of tokens: %d\n", ntokens);
206                 fprintf(stderr, "number of term structures: %d\n", nterms);
207                 fprintf(stderr, "number of alternation structures: %d\n", nalts);
208                 fprintf(stderr, "total memory used: %ld\n", (long)(sbrk(0) - beg_sbrk));
209         }
210         exit(0);
211 }
212
213 STATIC
214 readgrammar(argc,argv) char *argv[]; {
215         /*
216          * Do just what the name suggests : read the grammar
217          */
218         register p_file p;
219         p_mem           alloc();
220
221         linecount = 0;
222         f_input = "no filename";
223         /*
224          * Build the file structure
225          */
226         files = p = (p_file) alloc((unsigned) (argc+1) * sizeof(t_file));
227         if (argc-- == 1) {
228                 finput = stdin;
229                 f_input = "standard input";
230                 doparse(p++);
231         } else {
232                 while (argc--) {
233                         if ((finput = fopen(f_input=argv[1],"r")) == NULL) {
234                                 fatal(0,e_noopen,f_input);
235                         }
236                         doparse(p++);
237                         argv++;
238                         fclose(finput);
239                 }
240         }
241         maxfiles = p;
242         if (! lexical) lexical = "yylex";
243         /*
244          * There must be a start symbol!
245          */
246         if (! nerrors && start == 0) {
247                 fatal(linecount,"Missing %%start");
248         }
249         if (nerrors) comfatal();
250 }
251
252 STATIC
253 doparse(p) register p_file p; {
254
255         linecount = 0;
256         p->f_name = f_input;
257         p->f_firsts = 0;
258         pfile = p;
259         torder = -1;
260         norder = -1;
261         LLparse();
262         p->f_nonterminals = norder;
263         p->f_terminals = torder;
264 }
265
266 /* VARARGS1 */
267 error(lineno,s,t,u) string      s,t,u; {
268         /*
269          * Just an error message
270          */
271
272         ++nerrors;
273         if (!lineno) lineno = 1;
274         fprintf(stderr,"\"%s\", line %d: ",f_input, lineno);
275         fprintf(stderr,s,t,u);
276         fputs("\n",stderr);
277 }
278
279 /* VARARGS1 */
280 warning(lineno,s,t,u) string    s,t,u; {
281         /*
282          * Just a warning
283          */
284
285         if (wflag) return;
286         if (!lineno) lineno = 1;
287         fprintf(stderr,"\"%s\", line %d: (Warning) ",f_input, lineno);
288         fprintf(stderr,s,t,u);
289         fputs("\n",stderr);
290 }
291
292 /* VARARGS1 */
293 fatal(lineno,s,t,u) string      s,t,u; {
294         /*
295          * Fatal error
296          */
297         error(lineno,s,t,u);
298         comfatal();
299 }
300
301 comfatal() {
302         /*
303          * Some common code for exit on errors
304          */
305         if (fact != NULL) {
306                 fclose(fact);
307                 UNLINK(f_temp);
308         }
309         if (fpars != NULL) fclose(fpars);
310         UNLINK(f_pars);
311         exit(1);
312 }
313
314 copyfile(file) string file; {
315         /*
316          * Copies a file indicated by the parameter to filedescriptor fpars.
317          */
318         register int    c;
319         register FILE   *f;
320
321         if ((f = fopen(file,"r")) == NULL) {
322                 fatal(0,"Cannot open library file %s, call an expert",file);
323         }
324         while ((c = getc(f)) != EOF) putc(c,fpars);
325         fclose(f);
326 }
327
328 install(target, source) string target, source; {
329         /*
330          * Copy the temporary file generated from source to target
331          * if allowed (which means that the target must be generated
332          * by LLgen from the source, or that the target is not present
333          */
334         register int    c1, c2;
335         register FILE   *f1, *f2;
336         int             cnt;
337
338         /*
339          * First open temporary, generated for source
340          */
341         if ((f1 = fopen(f_pars,"r")) == NULL) {
342                 fatal(0,e_noopen,f_pars);
343         }
344         /*
345          * Now open target for reading
346          */
347         if ((f2 = fopen(target,"r")) == NULL) {
348                 fclose(f1);
349                 RENAME(f_pars, target);
350                 return;
351         }
352         /*
353          * Compute length of LLgen identification string. The target must
354          * start with that!
355          */
356         cnt = strlen(LLgenid) + strlen(source) - 2;
357         /*
358          * Now compare the target with the temporary
359          */
360         do {
361                 c1 = getc(f1);
362                 c2 = getc(f2);
363                 if (cnt >= 0) cnt--;
364         } while (c1 == c2 && c1 != EOF);
365         fclose(f1);
366         fclose(f2);
367         /*
368          * Here, if c1 != c2 the target must be recreated
369          */
370         if (c1 != c2) {
371                 if (cnt >= 0) {
372                         fatal(0,"%s : not a file generated by LLgen",target);
373                 }
374                 RENAME(f_pars,target);
375         }
376 }