main.c 7.2 KB

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