ack/util/LLgen/src/main.c

433 lines
7.6 KiB
C

/* Copyright (c) 1991 by the Vrije Universiteit, Amsterdam, the Netherlands.
* For full copyright and restrictions on use see the file COPYING in the top
* level of the LLgen tree.
*/
/*
* 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 <stdlib.h>
#include <string.h>
# include "types.h"
# include "io.h"
# include "extern.h"
# include "sets.h"
# include "assert.h"
# ifndef NORCSID
static string rcsid6 = "$Id$";
# endif
/* In this file the following routines are defined: */
STATIC void readgrammar(int, char *[]);
STATIC void doparse(register p_file);
STATIC void comfatal(void);
extern void UNLINK(string);
extern void RENAME(string, string);
extern void TMPNAM(string);
extern string libpath(string);
extern void conflchecks(void);
extern void do_compute(void);
extern void gencode(int);
int main(int argc, register string argv[])
{
register string arg;
TMPNAM(f_temp);
TMPNAM(f_pars);
/* Initialize */
assval = 0400;
/* read options */
while (argc >= 2 && (arg = argv[1], *arg == '-'))
{
while (*++arg)
{
switch (*arg)
{
case 'j':
case 'J':
jmptable_option = 1;
if (*++arg)
min_cases_for_jmptable = atoi(arg);
break;
case 'w':
case 'W':
wflag = 1;
continue;
case 'v':
case 'V':
verbose++;
continue;
case 'l':
case 'L':
low_percentage = atoi(++arg);
break;
case 'h':
case 'H':
high_percentage = atoi(++arg);
break;
# ifndef NDEBUG
case 'd':
case 'D':
debug++;
continue;
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;
#endif /* not NDEBUG */
case 'x':
case 'X':
ntneeded = 1;
ntprint = 1;
continue;
#ifdef NON_CORRECTING
case 'n':
case 'N':
non_corr = 1;
continue;
case 's':
case 'S':
subpars_sim = 1;
continue;
#endif
case 'g':
case 'G':
strip_grammar = 1;
continue;
default:
fprintf(stderr, "illegal option : %c\n", *arg);
exit(1);
}
break;
}
argv++;
argc--;
}
#ifdef NON_CORRECTING
if ((subpars_sim) && (!non_corr))
{
fprintf(stderr,"option -s illegal without -n, turned off\n");
subpars_sim = 0;
}
#endif
/*
* Now check wether the sets should include nonterminals
*/
if (verbose == 2)
ntneeded = 1;
/*
* Initialise
*/
# ifndef NDEBUG
if (!rec_file)
{
# endif
rec_file = libpath("rec");
# ifndef NDEBUG
}
if (!incl_file)
{
# endif
incl_file = libpath("incl");
# ifndef NDEBUG
}
# endif
#ifdef NON_CORRECTING
if (non_corr)
{
nc_incl_file = libpath("nc_incl");
nc_rec_file = libpath ("nc_rec");
}
#endif
if ((fact = fopen(f_temp, "w")) == NULL)
{
fputs("Cannot create temporary\n", stderr);
exit(1);
}
name_init();
readgrammar(argc, argv);
sprintf(f_out, OUTFILE, prefix ? prefix : "LL");
/* for the following two filenames only one L is used; historical
reasons ...
*/
sprintf(f_include, HFILE, prefix ? prefix : "L");
sprintf(f_rec, RFILE, prefix ? prefix : "L");
#ifdef NON_CORRECTING
if (non_corr)
sprintf(f_nc, NCFILE, prefix ? prefix : "L");
#endif
setinit(ntneeded);
maxnt = &nonterms[nnonterms];
maxt = &tokens[ntokens];
/*
* Now, the grammar is read. Do some computations
*/
co_reach(); /* Check for undefined and unreachable */
if (nerrors)
comfatal();
do_compute();
conflchecks();
if (nerrors)
comfatal();
fclose(fact);
if (argc-- == 1)
{
fputs("No code generation for input from standard input\n",
stderr);
}
else
gencode(argc);
UNLINK(f_temp);
UNLINK(f_pars);
if (verbose)
{
fprintf(stderr, "number of nonterminals: %d\n", nnonterms);
fprintf(stderr, "number of tokens: %d\n", ntokens);
fprintf(stderr, "number of term structures: %d\n", nterms);
fprintf(stderr, "number of alternation structures: %d\n", nalts);
}
exit(EXIT_SUCCESS);
}
STATIC void readgrammar(int argc, 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;
f_input = "standard input";
doparse(p++);
}
else
{
while (argc--)
{
if ((finput = fopen(f_input = argv[1], "r")) == NULL)
{
fatal(0, e_noopen, f_input);
}
doparse(p++);
argv++;
fclose(finput);
}
}
maxfiles = p;
if (!lexical)
lexical = "yylex";
/*
* There must be a start symbol!
*/
if (!nerrors && start == 0)
{
fatal(linecount, "Missing %%start", NULL);
}
if (nerrors)
comfatal();
}
STATIC void doparse(register p_file p)
{
linecount = 0;
p->f_name = f_input;
p->f_firsts = 0;
pfile = p;
torder = -1;
norder = -1;
LLparse();
p->f_nonterminals = norder;
p->f_terminals = torder;
}
void error(int lineno, string s, string t)
{
/*
* Just an error message
*/
++nerrors;
if (!lineno)
lineno = 1;
fprintf(stderr, "\"%s\", line %d: ", f_input, lineno);
fprintf(stderr, s, t);
fputs("\n", stderr);
}
void warning(int lineno, string s, string t)
{
/*
* Just a warning
*/
if (wflag)
return;
if (!lineno)
lineno = 1;
fprintf(stderr, "\"%s\", line %d: (Warning) ", f_input, lineno);
fprintf(stderr, s, t);
fputs("\n", stderr);
}
void fatal(int lineno, string s, string t)
{
/*
* Fatal error
*/
error(lineno, s, t);
comfatal();
}
STATIC void comfatal(void)
{
/*
* Some common code for exit on errors
*/
if (fact != NULL)
{
fclose(fact);
UNLINK(f_temp);
}
if (fpars != NULL)
fclose(fpars);
UNLINK(f_pars);
exit(EXIT_FAILURE);
}
void copyfile(string file)
{
/*
* Copies a file indicated by the parameter to filedescriptor fpars.
*/
register int c;
register FILE *f;
if ((f = fopen(file, "r")) == NULL)
{
fatal(0, "Cannot open library file %s, call an expert", file);
}
while ((c = getc(f)) != EOF)
putc(c, fpars);
fclose(f);
}
void copyto(string target, string source)
{
FILE *fsource;
FILE *ftarget;
int c;
ftarget = fopen(target,"wb+");
if (ftarget == NULL)
{
fatal(0, "Cannot open file %s, call an expert", target);
}
fsource = fopen(source,"rb");
if (fsource == NULL)
{
fatal(0, "Cannot open file %s, call an expert", source);
}
while ((c = getc(fsource)) != EOF)
putc(c, ftarget);
fclose(fsource);
fclose(ftarget);
}
void install(string target, string 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 int c1, c2;
register FILE *f1, *f2;
int cnt;
/*
* First open temporary, generated for source
*/
if ((f1 = fopen(f_pars, "r")) == NULL)
{
fatal(0, e_noopen, f_pars);
}
/*
* Now open target for reading
*/
if ((f2 = fopen(target, "r")) == NULL)
{
fclose(f1);
copyto(target, f_pars);
return;
}
/*
* Compute length of LLgen identification string. The target must
* start with that!
*/
cnt = strlen(LLgenid) + strlen(source) - 2;
/*
* Now compare the target with the temporary
*/
do
{
c1 = getc(f1);
c2 = getc(f2);
if (cnt >= 0)
cnt--;
} while (c1 == c2 && c1 != EOF);
fclose(f1);
fclose(f2);
/*
* Here, if c1 != c2 the target must be recreated
*/
if (c1 != c2)
{
if (cnt >= 0)
{
fatal(0, "%s : not a file generated by LLgen", target);
}
copyto(target, f_pars);
}
}