/* * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands. * * This product is part of the Amsterdam Compiler Kit. * * Permission to use, sell, duplicate or disclose this software must be * obtained in writing. Requests for such permissions may be sent to * * Dr. Andrew S. Tanenbaum * Wiskundig Seminarium * Vrije Universiteit * Postbox 7161 * 1007 MC Amsterdam * The Netherlands * */ /* * L L G E N * * An Extended LL(1) Parser Generator * * Author : Ceriel J.H. Jacobs */ /* * main.c * Contains main program, and some error message routines */ # include "types.h" # include "io.h" # include "extern.h" # include "sets.h" # include "assert.h" # ifndef NORCSID static string rcsid6 = "$Header$"; # endif static string rec_file; static string incl_file; /* In this file the following routines are defined: */ extern int main(); STATIC readgrammar(); extern error(); extern fatal(); extern comfatal(); extern copyfile(); extern install(); # ifndef NDEBUG extern badassertion(); # endif not NDEBUG main(argc,argv) register string argv[]; { register string arg; string libpath(); int nflag = 0; /* Initialize */ maxorder = order; assval = 0400; /* read options */ while (argc >= 2 && (arg = argv[1], *arg == '-')) { while (*++arg) { switch(*arg) { case 'v': case 'V': verbose++; continue; case 'n': case 'N': nflag++; continue; case 'f': case 'F': fflag++; continue; # ifndef NDEBUG case 'a': case 'A': debug++; continue; # endif not NDEBUG case 'r': case 'R': if (rec_file) { fprintf(stderr,"duplicate -r flag\n"); exit(1); } rec_file = ++arg; break; case 'i': case 'I': if (incl_file) { fprintf(stderr,"duplicate -i flag\n"); exit(1); } incl_file = ++arg; break; case 'x': case 'X': ntneeded = 1; ntprint = 1; continue; default: fprintf(stderr,"illegal option : %c\n",*arg); return 1; } break; } argv++; argc--; } /* * Now check wether the sets should include nonterminals */ if (verbose == 2) ntneeded = 1; else if (! verbose) ntneeded = 0; /* * Initialise */ if (!rec_file) rec_file = libpath("rec"); if (!incl_file) incl_file = libpath("incl"); if ((fact = fopen(f_temp,"w")) == NULL) { fputs("Cannot create temporary\n",stderr); return 1; } name_init(); readgrammar(argc,argv); if (nflag) comfatal(); setinit(ntneeded); maxnt = &nonterms[nnonterms]; max_t_ent = &h_entry[nterminals]; fclose(fact); /* * Now, the grammar is read. Do some computations */ co_reach(); /* Check for undefined and unreachable */ if (nerrors) comfatal(); createsets(); co_empty(); /* Which nonterminals produce empty? */ co_first(); /* Computes first sets */ co_follow(); /* Computes follow sets */ co_symb(); /* Computes choice sets in alternations */ conflchecks(); /* Checks for conflicts etc, and also * takes care of LL.output etc */ if (nerrors) comfatal(); co_contains(); /* Computes the contains sets */ co_safes(); /* Computes safe terms and nonterminals. * Safe means : always called with a terminal * symbol that is guarantied to be eaten by * the term */ if (argc-- == 1) { fputs("No code generation for input from standard input\n",stderr); } else gencode(argc); UNLINK(f_temp); UNLINK(f_pars); return 0; } STATIC readgrammar(argc,argv) char *argv[]; { /* * Do just what the name suggests : read the grammar */ register p_file p; p_mem alloc(); linecount = 0; f_input = "no filename"; /* * Build the file structure */ files = p = (p_file) alloc((unsigned) (argc+1) * sizeof(t_file)); if (argc-- == 1) { finput = stdin; p->f_name = f_input = "standard input"; p->f_firsts = 0; p->f_start = maxorder; pfile = p; LLparse(); p->f_end = maxorder - 1; p++; } else { while (argc--) { if ((finput = fopen(f_input=argv[1],"r")) == NULL) { fatal(0,e_noopen,f_input); } linecount = 0; p->f_name = f_input; p->f_start = maxorder; p->f_firsts = 0; pfile = p; LLparse(); p->f_end = maxorder-1; p++; argv++; fclose(finput); } } p->f_start = maxorder+1; p->f_end = maxorder; if (! lexical) lexical = "yylex"; /* * There must be a start symbol! */ if (start == 0) { fatal(linecount,"Missing %%start"); } if (nerrors) comfatal(); } /* VARARGS1 */ error(lineno,s,t,u) string s,t,u; { /* * Just an error message */ register FILE *f; f = stderr; ++nerrors; if (lineno) fprintf(f,"\"%s\", line %d : ",f_input,lineno); else fprintf(f,"\"%s\" : ",f_input); fprintf(f,s,t,u); putc('\n',f); } /* VARARGS1 */ fatal(lineno,s,t,u) string s,t,u; { /* * Fatal error */ error(lineno,s,t,u); comfatal(); } comfatal() { /* * Some common code for exit on errors */ if (fact != NULL) { fclose(fact); UNLINK(f_temp); } if (fpars != NULL) fclose(fpars); UNLINK(f_pars); exit(1); } copyfile(n) { /* * Copies a file indicated by the parameter to filedescriptor fpars. * If n != 0, the error recovery routines are copied, * otherwise a standard header is. */ register c; register FILE *f; if ((f = fopen(n?rec_file:incl_file,"r")) == NULL) { fatal(0,"Cannot open libraryfile, call an expert"); } while ((c = getc(f)) != EOF) putc(c,fpars); } install(target, source) string target, source; { /* * Copy the temporary file generated from source to target * if allowed (which means that the target must be generated * by LLgen from the source, or that the target is not present */ register c; register FILE *f1; register FILE *f2; register string s1; register int i; char buf[100]; /* * First open temporary, generated for source */ if ((f1 = fopen(f_pars,"r")) == NULL) { fatal(0,e_noopen,f_pars); } i = 0; /* * Now open target for reading */ if ((f2 = fopen(target,"r")) == NULL) { i = 1; fclose(f1); } else { /* * Create string recognised by LLgen. The target must * start with that! */ (int) sprintf(buf,LLgenid,source ? source : "."); s1 = buf; while (*s1 != '\0' && *s1++ == getc(f2)) { /* nothing */ } /* * Ai,ai, it did not */ if (*s1 != '\0') { fatal(0,"%s : not a file generated by LLgen",target); } rewind(f2); /* * Now compare the target with the temporary */ while ((c = getc(f1)) != EOF && c == getc(f2)) { /* nothing */} if (c != EOF || getc(f2) != EOF) i = 1; fclose(f1); fclose(f2); } /* * Here, if i != 0 the target must be recreated */ if (i) RENAME(f_pars,target); } #ifndef NDEBUG badassertion(asstr,file,line) char *asstr, *file; { fprintf(stderr,"Assertion \"%s\" failed %s(%d)\n",asstr,file,line); if (fact != NULL) fclose(fact); if (fpars != NULL) fclose(fpars); abort(); } #endif