main.c 7.1 KB

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