.SH NAME
LLgen, an extended LL(1) parser generator
.SH SYNOPSIS
-LLgen [ \-vxw ] [ \-j[\fInum\fP] ] [ \-l\fInum\fP ] [ \-h\fInum\fP ] file ...
+LLgen [ \-vxwa ] [ \-j[\fInum\fP] ] [ \-l\fInum\fP ] [ \-h\fInum\fP ] file ...
.SH DESCRIPTION
\fILLgen\fP
converts a context-free grammar into a set of
file.
.IP \fB\-w\fP
no warnings are given.
+.IP \fB\-a\fP
+Produce ANSI C function headers and prototypes.
.IP \fB\-j\fP[\fInum\fP]
when this flag is given, \fILLgen\fP will generate dense switches,
so that the compiler can generate a jump table for it. This will only be
#define LLtdecr(d) {LL_assert(LLtcnt[d] > 0); LLtcnt[d]--;}
#define LLsincr(d) LLscnt[d]++
#define LLtincr(d) LLtcnt[d]++
+
+#if LL_ANSI_C
+extern int LL_LEXI(void);
+extern void LLread(void);
+extern int LLskip(void);
+extern int LLnext(int);
+extern void LLerror(int);
+extern void LLnewlevel(unsigned int *);
+extern void LLoldlevel(unsigned int *);
+#ifndef LL_FASTER
+extern void LLscan(int);
+#endif
+#ifndef LLNOFIRSTS
+extern int LLfirst(int, int);
+#endif
+#else /* not LL_ANSI_C */
+extern LLread();
+extern int LLskip();
+extern int LLnext();
+extern LLerror();
+extern LLnewlevel();
+extern LLoldlevel();
+#ifndef LL_FASTER
+extern LLscan();
+#endif
+#ifndef LLNOFIRSTS
+extern int LLfirst();
+#endif
+#endif /* not LL_ANSI_C */
* This file is copied into Lpars.c.
*/
-# ifndef lint
+#ifndef lint
static char *rcsid = "$Header$";
-# endif
+#endif
unsigned int LLtcnt[LL_NTERMINALS];
unsigned int LLscnt[LL_NSETS];
int LLcsymb, LLsymb;
static int LLlevel;
-/* In this file are defined: */
-extern LLread();
-extern int LLskip();
-extern int LLnext();
-#ifndef LL_FASTER
-extern LLscan();
+#if LL_ANSI_C
+void LLmessage(int);
#endif
-extern LLerror();
-# ifndef LLNOFIRSTS
-extern int LLfirst();
-# endif
-extern LLnewlevel();
-extern LLoldlevel();
-
#ifdef LL_USERHOOK
+#if LL_ANSI_C
+static void LLdoskip(int);
+static int LLuserhook(int, int*);
+#else
static LLdoskip();
static int LLuserhook();
#endif
+#endif
#ifndef LL_FASTER
+#if LL_ANSI_C
+void LLscan(int t)
+#else
LLscan(t)
int t;
+#endif
{
/*
* Check if the next symbol is equal to the parameter
}
#endif
+#if LL_ANSI_C
+void LLread(void) {
+#else
LLread() {
+#endif
for (;;) {
if ((LLcsymb = LLindex[(LLsymb = LL_LEXI())]) >= 0) return;
LLmessage(0);
/* NOTREACHED */
}
+#if LL_ANSI_C
+void LLerror(int t)
+#else
LLerror(t)
int t;
+#endif
{
register int i;
#ifdef LL_USERHOOK
static int lst[] = { EOFILE, 0 };
if (LLuserhook(EOFILE, lst)) /* nothing */;
-#endif LL_USERHOOK
+#endif /* LL_USERHOOK */
if (LLsymb != EOFILE && LLsymb > 0) {
LLmessage(-1);
while ((LLsymb = LL_LEXI()) > 0 && LLsymb != EOFILE)
if (LLsymb != t) LLmessage(t);
}
-# ifndef LLNOFIRSTS
-LLfirst(x, d) {
+#ifndef LLNOFIRSTS
+#if LL_ANSI_C
+int LLfirst(int x, int d) {
+#else
+int LLfirst(x, d) {
+#endif
register int i;
return (i = LLindex[x]) >= 0 &&
(LLsets[d + (i >> 3)] & (1 << (i & 07)));
}
-# endif
+#endif
-LLnext(n)
+#if LL_ANSI_C
+int LLnext(int n)
+#else
+int LLnext(n)
int n;
+#endif
{
/* returns: 0 if the current symbol is'nt skipped, and it
is'nt a member of "n",
return retval;
}
-LLskip() {
+#if LL_ANSI_C
+int LLskip(void) {
+#else
+int LLskip() {
+#endif
/* returns 0 if the current symbol is'nt skipped, and
1 if it is, t.i., we have a new symbol
*/
return LLdoskip(0);
}
-static int
-LLuserhook(exp, list)
- int exp;
+#if LL_ANSI_C
+extern void LL_USERHOOK(int, int *);
+static int LLuserhook(int e, int *list)
+#else
+static int LLuserhook(e, list)
+ int e;
int *list;
+#endif
{
int old = LLsymb;
- LL_USERHOOK(exp, list);
+ LL_USERHOOK(e, list);
LLread();
return LLsymb != old;
}
-static
-LLmklist(list)
+#if LL_ANSI_C
+static void LLmklist(register int *list)
+#else
+static LLmklist(list)
register int *list;
+#endif
{
char Xset[LL_SSIZE];
register char *p;
*list = 0;
}
-static
-LLdoskip(exp)
- int exp;
+#if LL_ANSI_C
+static int LLdoskip(int e)
+#else
+static int LLdoskip(e)
+ int e;
+#endif
{
int LLx;
int list[LL_NTERMINALS+1];
-#endif LL_USERHOOK
+#endif /* LL_USERHOOK */
register int i;
int retval;
int LLi, LLb;
retval = 0;
#ifdef LL_USERHOOK
LLmklist(list);
- LLx = LLuserhook(exp, list);
+ LLx = LLuserhook(e, list);
if (LLx) retval = 1;
-#endif LL_USERHOOK
+#endif /* LL_USERHOOK */
for (;;) {
if (LLtcnt[LLcsymb] != 0) {
#ifdef LL_USERHOOK
- if (!exp || !LLx || LLcsymb == LLindex[exp])
+ if (!e || !LLx || LLcsymb == LLindex[e])
#endif
return retval;
}
if (LLscnt[i] != 0) {
if (LLsets[LL_SSIZE*i+LLi] & LLb) {
#ifdef LL_USERHOOK
- if (!exp || !LLx || LLcsymb == LLindex[exp])
+ if (!e || !LLx || LLcsymb == LLindex[e])
#endif
return retval;
}
}
#ifdef LL_USERHOOK
if (LLx) {
- LLx = LLuserhook(exp, list);
+ LLx = LLuserhook(e, list);
continue;
}
-#endif LL_USERHOOK
+#endif /* LL_USERHOOK */
LLmessage(0);
retval = 1;
LLread();
/* NOTREACHED */
}
+#if LL_ANSI_C
+void LLnewlevel(unsigned int *LLsinfo) {
+#else
LLnewlevel(LLsinfo) unsigned int *LLsinfo; {
+#endif
register int i;
if (LLlevel++) {
LLtincr(0);
}
-LLoldlevel(LLsinfo)
- unsigned int *LLsinfo;
-{
+#if LL_ANSI_C
+void LLoldlevel(unsigned int *LLsinfo) {
+#else
+LLoldlevel(LLsinfo) unsigned int *LLsinfo; {
+#endif
register int i;
LLtdecr(0);
-# ifdef LL_DEBUG
+#ifdef LL_DEBUG
for (i = 0; i < LL_NTERMINALS; i++) LL_assert(LLtcnt[i] == 0);
for (i = 0; i < LL_NSETS; i++) LL_assert(LLscnt[i] == 0);
-# endif
+#endif
if (--LLlevel) {
for (i = LL_NSETS - 1; i >= 0; i--) {
LLscnt[i] = LLsinfo[LL_NTERMINALS+i];
p_mem alloc(), ralloc();
string store();
p_gram search();
+long ftell();
static int nparams; /* parameter count for nonterminals */
static int acount; /* count #of global actions */
p->n_count = acount;
acount = 0;
p->n_lineno = linecount;
+ p->n_off = ftell(fact);
}
[ params { p->n_flags |= PARAMS;
if (nparams > 15) {
STATIC
createsets() {
/*
- * Allocate space for the sets
+ * Allocate space for the sets. Also determine which files use
+ * which nonterminals, and determine which nonterminals can be
+ * made static.
*/
register p_nont p;
+ register p_file f;
+ register p_start st;
+ register int i;
+ int n = NINTS(NBYTES(nnonterms));
+ p_mem alloc();
- for (p = nonterms; p < maxnt; p++) {
- p->n_first = get_set();
- p->n_follow = get_set();
- walk(p->n_rule);
+ for (f = files; f < maxfiles; f++) {
+ register p_set s;
+ f->f_used = s = (p_set) alloc((unsigned)n*sizeof(*(f->f_used)));
+ for (i = n; i; i--) *s++ = 0;
+ for (i = f->f_nonterminals; i != -1; i = p->n_next) {
+ p = &nonterms[i];
+ p->n_flags |= GENSTATIC;
+ p->n_first = get_set();
+ p->n_follow = get_set();
+ walk(f->f_used, p->n_rule);
+ }
+ }
+ for (f = files; f < maxfiles; f++) {
+ for (i = f->f_nonterminals; i != -1; i = p->n_next) {
+ register p_file f2;
+
+ p = &nonterms[i];
+ for (f2 = files; f2 < maxfiles; f2++) {
+ if (f2 != f && IN(f2->f_used, i)) {
+ p->n_flags &= ~GENSTATIC;
+ }
+ }
+ }
+ }
+ for (st = start; st; st = st->ff_next) {
+ nonterms[st->ff_nont].n_flags &= ~GENSTATIC;
}
}
STATIC
-walk(p) register p_gram p; {
+walk(u, p) p_set u; register p_gram p; {
/*
* Walk through the grammar rule p, allocating sets
*/
q = g_getterm(p);
q->t_first = get_set();
q->t_follow = get_set();
- walk(q->t_rule);
+ walk(u, q->t_rule);
break; }
case ALTERNATION : {
register p_link l;
l = g_getlink(p);
l->l_symbs = get_set();
l->l_others = get_set();
- walk(l->l_rule);
+ walk(u, l->l_rule);
+ break; }
+ case NONTERM : {
+ register int i = g_getcont(p);
+
+ PUTIN(u, i);
break; }
case EORULE :
return;
extern int low_percentage, high_percentage;
extern int min_cases_for_jmptable;
extern int jmptable_option;
+extern int ansi_c;
STATIC macro();
STATIC controlline();
STATIC getparams();
+STATIC getansiparams();
+STATIC genprototypes();
STATIC gettok();
STATIC rulecode();
STATIC int * dopush();
opentemp(f_input);
correct_prefix();
/* generate code ... */
+ if (ansi_c) fputs("#define LL_ANSI_C 1\n", fpars);
+ fprintf(fpars, "#define LL_LEXI %s\n", lexical);
copyfile(incl_file);
generate(p);
getaction(2);
}
geninclude();
genrecovery();
+ fclose(fact);
}
STATIC
opentemp((string) 0);
f = fpars;
correct_prefix();
- copyfile(incl_file);
if (!firsts) fputs("#define LLNOFIRSTS\n", f);
+ if (ansi_c) fputs("#define LL_ANSI_C 1\n", f);
+ fprintf(f, "#define LL_LEXI %s\n", lexical);
+ copyfile(incl_file);
for (st = start; st; st = st->ff_next) {
/* Make sure that every set the parser needs is in the list
* before generating a define of the number of them!
}
i = maxptr - setptr;
fprintf(f,
-"#define LL_LEXI %s\n#define LL_SSIZE %d\n#define LL_NSETS %d\n#define LL_NTERMINALS %d\n",
- lexical,
+"#define LL_SSIZE %d\n#define LL_NSETS %d\n#define LL_NTERMINALS %d\n",
nbytes,
i > 0 ? i : 1,
ntokens);
if (onerror) fprintf(f,"#define LL_USERHOOK %s\n", onerror);
/* Now generate the routines that call the startsymbols */
+ if (ansi_c) for (st = start; st; st = st->ff_next) {
+ p = &nonterms[st->ff_nont];
+ fputs("void ", f);
+ genextname(st->ff_nont, p->n_name, f);
+ fputs("(void);\n", f);
+ }
for (st = start; st; st = st->ff_next) {
- fputs(st->ff_name, f);
+ if (ansi_c) fputs("void ", f);
+ fprintf(f, "%s(%s)", st->ff_name, ansi_c ? "void" : "");
p = &nonterms[st->ff_nont];
- fputs("() {\n\tunsigned int s[LL_NTERMINALS+LL_NSETS+2];\n\tLLnewlevel(s);\n\tLLread();\n", f);
+ fputs(" {\n\tunsigned int s[LL_NTERMINALS+LL_NSETS+2];\n\tLLnewlevel(s);\n\tLLread();\n", f);
if (g_gettype(p->n_rule) == ALTERNATION) {
genpush(findindex(p->n_contains));
}
int i;
register p_first ff;
int mustpop;
+ int is_first = 1;
fprintf(fpars, "#define LL_LEXI %s\n", lexical);
listcount = 0;
getntparams(p) == 0) {
continue;
}
+ if (is_first) genprototypes(f);
+ is_first = 0;
+ if (p->n_flags & GENSTATIC) fputs("static ", fpars);
+ if (ansi_c) fputs("void ", fpars);
genextname(s, p->n_name, fpars);
if (p->n_flags & PARAMS) {
fputs("(\n", fpars);
controlline();
- getparams();
+ if (ansi_c) getansiparams(1);
+ else getparams();
}
- else fputs("() {\n", fpars);
+ else fprintf(fpars, "(%s) {\n", ansi_c ? "void" : "");
if (p->n_flags & LOCALS) getaction(1);
i = getntsafe(p);
mustpop = NOPOP;
fprintf(fpars, "%c {\n",add_semi);
}
+STATIC
+genprototypes(f)
+ register p_file f;
+{
+ /*
+ * Generate prototypes for all nonterminals
+ */
+ register int i;
+ register p_nont p;
+ long off = ftell(fact);
+
+ for (i = 0; i < nnonterms; i++) {
+ if (! IN(f->f_used, i)) continue;
+ p = &nonterms[i];
+ if (g_gettype(p->n_rule) == EORULE &&
+ getntparams(p) == 0) {
+ continue;
+ }
+ if (ansi_c || (p->n_flags & GENSTATIC)) {
+ if (p->n_flags & GENSTATIC) fputs("static ", fpars);
+ if (ansi_c) fputs("void ", fpars);
+ genextname(i, p->n_name, fpars);
+ if (! ansi_c) fputs("();\n", fpars);
+ else if (p->n_flags & PARAMS) {
+ fputs("(\n", fpars);
+ fseek(fact, p->n_off, 0);
+ controlline();
+ getansiparams(0);
+ fseek(fact, off, 0);
+ }
+ else fputs("(void);\n", fpars);
+ }
+ }
+}
+
+STATIC
+getansiparams(mkdef) {
+ /* getansiparams is called if a nonterminal has parameters
+ * and an ANSI C function definition/declaration has to be produced.
+ * If a definition has to be produced, "mkdef" is set to 1.
+ */
+ register int l;
+ char add_semi = ' ';
+ int delayed = 0;
+
+ ltext[0] = '\0';
+ while ((l = gettok()) != ENDDECL) {
+ if (delayed) {
+ fputc(',', fpars);
+ delayed = 0;
+ }
+ if ((l == ';' || l == ',') && ltext[0] != '\0') {
+ /*
+ * The last identifier found before a ';' or a ','
+ * must be a parameter
+ */
+ delayed = 1;
+ ltext[0] = '\0';
+ }
+ else if (l == IDENT) fprintf(fpars, "%s", ltext);
+ else fputc(l, fpars);
+ }
+ fprintf(fpars, ") %c\n", mkdef ? '{' : ';');
+}
+
STATIC
gettok() {
/* Read from the action file. */
int low_percentage = 10, high_percentage = 30;
int min_cases_for_jmptable = 8;
int jmptable_option;
+int ansi_c = 0;
ntneeded = 1;
ntprint = 1;
continue;
+ case 'a':
+ case 'A':
+ ansi_c = 1;
+ continue;
default:
fprintf(stderr,"illegal option : %c\n",*arg);
exit(1);
*/
# define getntparams(p) ((p)->n_flags&017)
# define setntparams(p,i) {assert(((unsigned)(i))<=017);(p)->n_flags&=~017;(p)->n_flags|=(i);}
+# define GENSTATIC 01000 /* set if routine can be made static */
# define RECURSIVE 02000 /* Set if the default rule is recursive */
# define PARAMS 04000 /* tells if a nonterminal has parameters */
# define EMPTY 010000 /* tells if a nonterminal produces empty */
p_set n_contains; /* pointer to symbols that can be produced */
string n_name; /* name of nonterminal */
int n_next; /* index of next nonterminal */
+ long n_off; /* index of parameters in action file */
} t_nont, *p_nont;
/*
*/
int f_nonterminals; /* list of nonterminals in this file */
int f_terminals; /* list of terminals in this file */
+ p_set f_used; /* set of nonterminals used in this file */
} t_file, *p_file;
typedef struct info_alloc {