1 /**************************************************************************/
2 /*                                                                        */
3 /*                                 OCaml                                  */
4 /*                                                                        */
5 /*             Xavier Leroy, projet Cristal, INRIA Rocquencourt           */
6 /*                                                                        */
7 /*   Copyright 1996 Institut National de Recherche en Informatique et     */
8 /*     en Automatique.                                                    */
9 /*                                                                        */
10 /*   All rights reserved.  This file is distributed under the terms of    */
11 /*   the GNU Lesser General Public License version 2.1, with the          */
12 /*   special exception on linking described in the file LICENSE.          */
13 /*                                                                        */
14 /**************************************************************************/
15 
16 /* Based on public-domain code from Berkeley Yacc */
17 
18 #include <signal.h>
19 #include <string.h>
20 #include "defs.h"
21 #ifdef HAS_UNISTD
22 #include <unistd.h>
23 #endif
24 
25 #include "version.h"
26 
27 char dflag;
28 char lflag;
29 char rflag;
30 char tflag;
31 char vflag;
32 char qflag;
33 char eflag;
34 char sflag;
35 char big_endian;
36 
37 char *file_prefix = 0;
38 char *myname = "yacc";
39 char temp_form[] = "yacc.XXXXXXX";
40 
41 #ifdef NO_UNIX
42 char dirsep = '\\';
43 #else
44 char dirsep = '/';
45 #endif
46 
47 int lineno;
48 char *virtual_input_file_name = NULL;
49 int outline;
50 
51 char *action_file_name;
52 char *entry_file_name;
53 char *code_file_name;
54 char *interface_file_name;
55 char *defines_file_name;
56 char *input_file_name = "";
57 char *output_file_name;
58 char *text_file_name;
59 char *union_file_name;
60 char *verbose_file_name;
61 
62 #ifdef HAS_MKSTEMP
63 int action_fd = -1, entry_fd = -1, text_fd = -1, union_fd = -1;
64 #endif
65 
66 FILE *action_file;      /*  a temp file, used to save actions associated    */
67                         /*  with rules until the parser is written          */
68 FILE *entry_file;
69 FILE *code_file;        /*  y.code.c (used when the -r option is specified) */
70 FILE *defines_file;     /*  y.tab.h                                         */
71 FILE *input_file;       /*  the input file                                  */
72 FILE *output_file;      /*  y.tab.c                                         */
73 FILE *text_file;        /*  a temp file, used to save text until all        */
74                         /*  symbols have been defined                       */
75 FILE *union_file;       /*  a temp file, used to save the union             */
76                         /*  definition until all symbol have been           */
77                         /*  defined                                         */
78 FILE *verbose_file;     /*  y.output                                        */
79 FILE *interface_file;
80 
81 int nitems;
82 int nrules;
83 int ntotalrules;
84 int nsyms;
85 int ntokens;
86 int nvars;
87 
88 int   start_symbol;
89 char  **symbol_name;
90 short *symbol_value;
91 short *symbol_prec;
92 char  *symbol_assoc;
93 char **symbol_tag;
94 char *symbol_true_token;
95 
96 short *ritem;
97 short *rlhs;
98 short *rrhs;
99 short *rprec;
100 char  *rassoc;
101 short **derives;
102 char *nullable;
103 
104 #if !defined(HAS_MKSTEMP)
105 extern char *mktemp(char *);
106 #endif
107 #ifndef NO_UNIX
108 extern char *getenv(const char *);
109 #endif
110 
111 
done(int k)112 void done(int k)
113 {
114 #ifdef HAS_MKSTEMP
115     if (action_fd != -1)
116        unlink(action_file_name);
117     if (entry_fd != -1)
118        unlink(entry_file_name);
119     if (text_fd != -1)
120        unlink(text_file_name);
121     if (union_fd != -1)
122        unlink(union_file_name);
123 #else
124     if (action_file) { fclose(action_file); unlink(action_file_name); }
125     if (entry_file) { fclose(entry_file); unlink(entry_file_name); }
126     if (text_file) { fclose(text_file); unlink(text_file_name); }
127     if (union_file) { fclose(union_file); unlink(union_file_name); }
128 #endif
129     if (output_file && k > 0) {
130       fclose(output_file); unlink(output_file_name);
131     }
132     if (interface_file && k > 0) {
133       fclose(interface_file); unlink(interface_file_name);
134     }
135     exit(k);
136 }
137 
138 
onintr(int dummy)139 void onintr(int dummy)
140 {
141     done(1);
142 }
143 
144 
set_signals(void)145 void set_signals(void)
146 {
147 #ifdef SIGINT
148     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
149         signal(SIGINT, onintr);
150 #endif
151 #ifdef SIGTERM
152     if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
153         signal(SIGTERM, onintr);
154 #endif
155 #ifdef SIGHUP
156     if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
157         signal(SIGHUP, onintr);
158 #endif
159 }
160 
161 
usage(void)162 void usage(void)
163 {
164     fprintf(stderr, "usage: %s [-v] [--strict] [-q] [-b file_prefix] filename\n",
165             myname);
166     exit(1);
167 }
168 
getargs(int argc,char ** argv)169 void getargs(int argc, char **argv)
170 {
171     register int i;
172     register char *s;
173 
174     if (argc > 0) myname = argv[0];
175     for (i = 1; i < argc; ++i)
176     {
177         s = argv[i];
178         if (*s != '-') break;
179         switch (*++s)
180         {
181         case '\0':
182             input_file = stdin;
183             file_prefix = "stdin";
184             if (i + 1 < argc) usage();
185             return;
186 
187         case '-':
188             if (!strcmp (argv[i], "--strict")){
189               eflag = 1;
190               goto end_of_option;
191             }
192             ++i;
193             goto no_more_options;
194 
195         case 'v':
196             if (!strcmp (argv[i], "-version")){
197               printf ("The OCaml parser generator, version "
198                       OCAML_VERSION "\n");
199               exit (0);
200             }else if (!strcmp (argv[i], "-vnum")){
201               printf (OCAML_VERSION "\n");
202               exit (0);
203             }else{
204               vflag = 1;
205             }
206             break;
207 
208         case 'q':
209             qflag = 1;
210             break;
211 
212         case 'b':
213             if (*++s)
214                  file_prefix = s;
215             else if (++i < argc)
216                 file_prefix = argv[i];
217             else
218                 usage();
219             continue;
220 
221         default:
222             usage();
223         }
224 
225         for (;;)
226         {
227             switch (*++s)
228             {
229             case '\0':
230                 goto end_of_option;
231 
232             case 'v':
233                 vflag = 1;
234                 break;
235 
236             case 'q':
237                 qflag = 1;
238                 break;
239 
240             default:
241                 usage();
242             }
243         }
244 end_of_option:;
245     }
246 
247 no_more_options:;
248     if (i + 1 != argc) usage();
249     input_file_name = argv[i];
250     if (file_prefix == 0) {
251       int len;
252       len = strlen(argv[i]);
253       file_prefix = malloc(len + 1);
254       if (file_prefix == 0) no_space();
255       strcpy(file_prefix, argv[i]);
256       while (len > 0) {
257         len--;
258         if (file_prefix[len] == '.') {
259           file_prefix[len] = 0;
260           break;
261         }
262       }
263     }
264 }
265 
266 
267 char *
allocate(unsigned int n)268 allocate(unsigned int n)
269 {
270     register char *p;
271 
272     p = NULL;
273     if (n)
274     {
275         p = CALLOC(1, n);
276         if (!p) no_space();
277     }
278     return (p);
279 }
280 
281 
create_file_names(void)282 void create_file_names(void)
283 {
284     int i, len;
285     char *tmpdir;
286 
287 #ifdef NO_UNIX
288     tmpdir = getenv("TEMP");
289     if (tmpdir == 0) tmpdir = ".";
290 #else
291     tmpdir = getenv("TMPDIR");
292     if (tmpdir == 0) tmpdir = "/tmp";
293 #endif
294     len = strlen(tmpdir);
295     i = len + sizeof(temp_form);
296     if (len && tmpdir[len-1] != dirsep)
297         ++i;
298 
299     action_file_name = MALLOC(i);
300     if (action_file_name == 0) no_space();
301     entry_file_name = MALLOC(i);
302     if (entry_file_name == 0) no_space();
303     text_file_name = MALLOC(i);
304     if (text_file_name == 0) no_space();
305     union_file_name = MALLOC(i);
306     if (union_file_name == 0) no_space();
307 
308     strcpy(action_file_name, tmpdir);
309     strcpy(entry_file_name, tmpdir);
310     strcpy(text_file_name, tmpdir);
311     strcpy(union_file_name, tmpdir);
312 
313     if (len && tmpdir[len - 1] != dirsep)
314     {
315         action_file_name[len] = dirsep;
316         entry_file_name[len] = dirsep;
317         text_file_name[len] = dirsep;
318         union_file_name[len] = dirsep;
319         ++len;
320     }
321 
322     strcpy(action_file_name + len, temp_form);
323     strcpy(entry_file_name + len, temp_form);
324     strcpy(text_file_name + len, temp_form);
325     strcpy(union_file_name + len, temp_form);
326 
327     action_file_name[len + 5] = 'a';
328     entry_file_name[len + 5] = 'e';
329     text_file_name[len + 5] = 't';
330     union_file_name[len + 5] = 'u';
331 
332 #ifdef HAS_MKSTEMP
333     action_fd = mkstemp(action_file_name);
334     if (action_fd == -1)
335         open_error(action_file_name);
336     entry_fd = mkstemp(entry_file_name);
337     if (entry_fd == -1)
338         open_error(entry_file_name);
339     text_fd = mkstemp(text_file_name);
340     if (text_fd == -1)
341         open_error(text_file_name);
342     union_fd = mkstemp(union_file_name);
343     if (union_fd == -1)
344         open_error(union_file_name);
345 #else
346     mktemp(action_file_name);
347     mktemp(entry_file_name);
348     mktemp(text_file_name);
349     mktemp(union_file_name);
350 #endif
351 
352     len = strlen(file_prefix);
353 
354     output_file_name = MALLOC(len + 7);
355     if (output_file_name == 0)
356         no_space();
357     strcpy(output_file_name, file_prefix);
358     strcpy(output_file_name + len, OUTPUT_SUFFIX);
359 
360     code_file_name = output_file_name;
361 
362     if (vflag)
363     {
364         verbose_file_name = MALLOC(len + 8);
365         if (verbose_file_name == 0)
366             no_space();
367         strcpy(verbose_file_name, file_prefix);
368         strcpy(verbose_file_name + len, VERBOSE_SUFFIX);
369     }
370 
371     interface_file_name = MALLOC(len + 8);
372     if (interface_file_name == 0)
373         no_space();
374     strcpy(interface_file_name, file_prefix);
375     strcpy(interface_file_name + len, INTERFACE_SUFFIX);
376 
377 }
378 
379 
open_files(void)380 void open_files(void)
381 {
382     create_file_names();
383 
384     if (input_file == 0)
385     {
386         input_file = fopen(input_file_name, "r");
387         if (input_file == 0)
388             open_error(input_file_name);
389     }
390 
391 #ifdef HAS_MKSTEMP
392     action_file = fdopen(action_fd, "w");
393 #else
394     action_file = fopen(action_file_name, "w");
395 #endif
396     if (action_file == 0)
397         open_error(action_file_name);
398 
399 #ifdef HAS_MKSTEMP
400     entry_file = fdopen(entry_fd, "w");
401 #else
402     entry_file = fopen(entry_file_name, "w");
403 #endif
404     if (entry_file == 0)
405         open_error(entry_file_name);
406 
407 #ifdef HAS_MKSTEMP
408     text_file = fdopen(text_fd, "w");
409 #else
410     text_file = fopen(text_file_name, "w");
411 #endif
412     if (text_file == 0)
413         open_error(text_file_name);
414 
415     if (vflag)
416     {
417         verbose_file = fopen(verbose_file_name, "w");
418         if (verbose_file == 0)
419             open_error(verbose_file_name);
420     }
421 
422     if (dflag)
423     {
424         defines_file = fopen(defines_file_name, "w");
425         if (defines_file == 0)
426             open_error(defines_file_name);
427 #ifdef HAS_MKSTEMP
428         union_file = fdopen(union_fd, "w");
429 #else
430         union_file = fopen(union_file_name, "w");
431 #endif
432         if (union_file ==  0)
433             open_error(union_file_name);
434     }
435 
436     output_file = fopen(output_file_name, "w");
437     if (output_file == 0)
438         open_error(output_file_name);
439 
440     if (rflag)
441     {
442         code_file = fopen(code_file_name, "w");
443         if (code_file == 0)
444             open_error(code_file_name);
445     }
446     else
447         code_file = output_file;
448 
449 
450     interface_file = fopen(interface_file_name, "w");
451     if (interface_file == 0)
452       open_error(interface_file_name);
453 }
454 
main(int argc,char ** argv)455 int main(int argc, char **argv)
456 {
457     set_signals();
458     getargs(argc, argv);
459     open_files();
460     reader();
461     lr0();
462     lalr();
463     make_parser();
464     verbose();
465     if (eflag && SRtotal + RRtotal > 0) forbidden_conflicts();
466     output();
467     done(0);
468     /*NOTREACHED*/
469     return 0;
470 }
471