Completely new version, generating a much faster parser.

This commit is contained in:
ceriel 1985-11-25 15:47:51 +00:00
parent 5ac646f89f
commit f055d610d3
16 changed files with 1579 additions and 1394 deletions

View file

@ -26,33 +26,64 @@
/*
* LLgen.g
* Defines the grammar of LLgen.
* Some routines that are included build the internal structure
* Some routines that build the internal structure are also included
*/
{
# include "types.h"
# include "io.h"
# include "tunable.h"
# include "extern.h"
# include "assert.h"
# include "cclass.h"
# ifndef NORCSID
static string rcsidb = "$Header$";
static string rcsid = "$Header$";
# endif
p_mem alloc();
p_mem alloc(), new_mem();
string store();
t_gram search();
p_gram search();
static int nparams; /* parameter count for nonterminals */
static t_gram elem; /* temporary space */
static int acount; /* count #of global actions */
static t_info term_info,
link_info;
static p_order order,
maxorder;
/* Here are defined : */
extern a_init();
STATIC p_order neworder();
STATIC copyact();
STATIC unsigned get();
STATIC t_gram mkalt();
STATIC t_gram mkterm();
STATIC mkalt();
STATIC mkterm();
STATIC p_gram copyrule();
/* and of course LLparse() */
a_init() {
term_info.i_esize = sizeof (t_term);
term_info.i_incr = 50;
link_info.i_esize = sizeof (t_link);
link_info.i_incr = 50;
name_init();
}
STATIC p_order
neworder(index) {
register p_order po;
if ((po = order) == maxorder) {
po = (p_order) alloc(20 * sizeof(*order));
maxorder = po + 20;
}
order = po + 1;
po->o_next = 0;
po->o_index = index;
if (porder) {
porder->o_next = po;
}
else sorder = po;
return po;
}
}
%start LLparse, spec;
@ -62,7 +93,7 @@ spec : { acount = 0; }
{ /*
* Put an endmarker in temporary file
*/
putc('\0',fact); putc('\0',fact);
fprintf(fact,"%c%c",'\0', '\0');
}
;
@ -85,12 +116,12 @@ def { register string p; }
* Put the declaration in the list
* of start symbols
*/
t_gram temp;
register p_gram temp;
register p_start ff;
temp = search(NONTERM,lextoken.t_string,BOTH);
ff = (p_start) alloc(sizeof(t_start));
ff->ff_nont = &nonterms[g_getnont(&temp)];
ff->ff_nont = g_getnont(temp);
ff->ff_name = p;
ff->ff_next = start;
start = ff;
@ -98,7 +129,8 @@ def { register string p; }
| C_LEXICAL C_IDENT
{ if (!lexical) {
lexical = store(lextoken.t_string);
} else error(linecount,"Duplicate %%lexical");
}
else error(linecount,"Duplicate %%lexical");
}
';'
/*
@ -118,17 +150,18 @@ def { register string p; }
listel : C_IDENT { search(TERMINAL,lextoken.t_string,ENTERING); }
;
rule { register p_nont p;}
rule { register p_nont p;
p_gram rr;
register p_gram temp;
}
: /*
* grammar for a production rule
*/
C_IDENT { t_gram temp;
temp = search(NONTERM,lextoken.t_string,BOTH);
p = &nonterms[g_getnont(&temp)];
C_IDENT { temp = search(NONTERM,lextoken.t_string,BOTH);
p = &nonterms[g_getnont(temp)];
if (p->n_rule) {
error(linecount,
"nonterminal already defined");
"nonterminal %s already defined", lextoken.t_string);
}
/*
* Remember the order in which the nonterminals
@ -136,20 +169,26 @@ rule { register p_nont p;}
* order to keep track with the actions on the
* temporary file
*/
*maxorder++ = p - nonterms;
porder = neworder(p - nonterms);
p->n_count = acount;
acount = 0;
p->n_lineno = linecount;
}
[ params(2) { p->n_flags |= PARAMS;
if (nparams > 7) {
if (nparams > 15) {
error(linecount,"Too many parameters");
} else setntparams(p,nparams);
}
else setntparams(p,nparams);
}
]?
[ action(0) { p->n_flags |= LOCALS; }
]?
':' productions(&(p->n_rule)) ';'
':' productions(&rr) ';'
/*
* Do not use p->n_rule now! The nonterms array
* might have been re-allocated.
*/
{ nonterms[g_getnont(temp)].n_rule = rr;}
;
action(int n;)
@ -173,73 +212,80 @@ productions(p_gram *p;)
register p_gram p_alts = alts;
int o_lc, n_lc;
} :
{ n_lc = o_lc = linecount; }
{ o_lc = linecount; }
simpleproduction(p,&conflres)
[ '|' { n_lc = linecount; }
[ C_DEFAULT { if (haddefault) {
error(linecount,
"multiple %%default");
}
haddefault = 1;
t |= DEF;
}
]?
simpleproduction(&prod,&t)
{ if (conflres & DEF) haddefault = 1; }
[
[ '|' { n_lc = linecount; }
simpleproduction(&prod,&t)
{ if (p_alts - alts >= 97) {
error(n_lc,"Too many alternatives");
p_alts = alts;
}
*p_alts++ = mkalt(*p,conflres,o_lc);
if (t & DEF) {
if (haddefault) {
error(n_lc,
"More than one %%default in alternation");
}
haddefault = 1;
}
mkalt(*p,conflres,o_lc,p_alts++);
o_lc = n_lc;
conflres = t;
t = 0;
*p = prod;
}
]* { if (conflres & ~DEF) {
]+ { if (conflres & ~DEF) {
error(n_lc,
"Resolver on last alternative");
}
if (p_alts > alts) {
*p_alts++ = mkalt(*p,conflres,n_lc);
g_settype(p_alts,EORULE);
*p = copyrule(alts,p_alts+1-alts);
if (!haddefault) {
((p_link) pentry[g_getcont(*p)])
->l_flag |= DEF;
}
"Resolver on last alternative not allowed");
}
mkalt(*p,conflres,n_lc,p_alts++);
g_settype(p_alts,EORULE);
*p = copyrule(alts,p_alts+1-alts);
}
|
{ if (conflres & ~DEF) {
error(o_lc,
"No alternation conflict resolver allowed here");
}
/*
if (conflres & DEF) {
error(o_lc,
"No %%default allowed here");
}
*/
}
]
;
{
STATIC t_gram
mkalt(prod,condition,lc) p_gram prod; {
STATIC
mkalt(prod,condition,lc,res) p_gram prod; register p_gram res; {
/*
* Create an alternation, initialise it and return
* a grammar element containing it
* Create an alternation and initialise it.
*/
register unsigned hulp;
register int hulp;
register p_link l;
t_gram r;
g_init(&r);
hulp = get(sizeof(*l));
l = (p_link) pentry[hulp];
l = (p_link) new_mem(&link_info);
links = (p_link) link_info.i_ptr;
hulp = l - links;
l->l_rule = prod;
l->l_flag = condition;
g_setcont(&r,hulp);
g_settype(&r,ALTERNATION);
r.g_lineno = lc;
return r;
g_setcont(res,hulp);
g_settype(res,ALTERNATION);
res->g_lineno = lc;
}
}
simpleproduction(p_gram *p; register int *conflres;)
{ t_gram rule[100];
t_gram elem;
register p_gram p_rule = rule;
t_reps reps;
int cnt, kind;
} :
{ r_init(&reps); }
[ C_DEFAULT { *conflres = DEF; }
]?
[
/*
* Optional conflict reslover
@ -248,92 +294,91 @@ simpleproduction(p_gram *p; register int *conflres;)
| C_PREFER { *conflres |= PREFERING; }
| C_AVOID { *conflres |= AVOIDING; }
]?
[ %persistent elem
[ %persistent elem(&elem)
{ if (p_rule - rule >= 98) {
error(linecount,"Production too long");
p_rule = rule;
}
r_setkind(&reps,FIXED);
r_setnum(&reps,0);
kind = FIXED;
cnt = 0;
}
[ repeats(&reps)
[ repeats(&kind, &cnt)
{ if (g_gettype(&elem) != TERM) {
*p_rule = elem;
g_settype(p_rule+1,EORULE);
elem = mkterm(copyrule(p_rule,2),
0,
&reps,
p_rule->g_lineno);
mkterm(copyrule(p_rule,2),
0,
p_rule->g_lineno,
&elem);
}
}
]? { if (g_gettype(&elem) == TERM) {
register p_term q;
q = (p_term) pentry[g_getcont(&elem)];
q->t_reps = reps;
if (q->t_flags & RESOLVER &&
(r_getkind(&reps) == PLUS ||
r_getkind(&reps) == FIXED)) {
q = &terms[g_getcont(&elem)];
r_setkind(q,kind);
r_setnum(q,cnt);
if ((q->t_flags & RESOLVER) &&
(kind == PLUS || kind == FIXED)) {
error(linecount,
"illegal %%while");
"%%while not allowed in this term");
}
if (q->t_flags & PERSISTENT &&
r_getkind(&reps) == FIXED) {
/*
* A persistent fixed term is the same
* as a non-persistent fixed term.
* Should we complain?
if ((q->t_flags & PERSISTENT) &&
kind == FIXED) {
error(linecount,
"illegal %%persistent");
}
*/
}
*p_rule++ = elem;
}
]* { register p_term q;
g_settype(p_rule,EORULE);
*p = 0;
if (g_gettype(&rule[0]) == TERM &&
p_rule-rule == 1) {
q=(p_term)pentry[g_getcont(&rule[0])];
if (r_getkind(&(q->t_reps))==FIXED &&
r_getnum(&(q->t_reps)) == 0) {
q = &terms[g_getcont(&rule[0])];
if (r_getkind(q) == FIXED &&
r_getnum(q) == 0) {
*p = q->t_rule;
}
else *p = copyrule(rule,2);
}
else *p = copyrule(rule,p_rule-rule+1);
if (!*p) *p = copyrule(rule,p_rule-rule+1);
}
;
{
STATIC t_gram
mkterm(prod,flags,reps,lc) p_gram prod; register p_reps reps; {
STATIC
mkterm(prod,flags,lc, result) p_gram prod; register p_gram result; {
/*
* Create a term, initialise it and return
* a grammar element contianing it
* a grammar element containing it
*/
register p_term q;
register unsigned hulp;
t_gram r;
unsigned hulp;
g_init(&r);
hulp = get(sizeof(*q));
q = (p_term) pentry[hulp];
q = (p_term) new_mem(&term_info);
terms = (p_term) term_info.i_ptr;
hulp = q - terms;
q->t_rule = prod;
q->t_contains = 0;
/* "*1" = "?" */
if (r_getnum(reps) == 1 && r_getkind(reps) == STAR) {
r_setkind(reps,OPT);
}
q->t_reps = *reps;
q->t_flags = flags;
g_settype(&r,TERM);
g_setcont(&r,hulp);
r.g_lineno = lc;
return r;
g_settype(result,TERM);
g_setcont(result,hulp);
result->g_lineno = lc;
}
}
elem { register short t = 0;
elem (register p_gram pres;)
{ register short t = 0;
p_gram p1;
t_reps reps;
int ln;
p_gram pe;
} :
'[' { ln = linecount; }
[ C_WHILE expr { t |= RESOLVER; }
@ -341,23 +386,27 @@ elem { register short t = 0;
[ C_PERSISTENT { t |= PERSISTENT; }
]?
productions(&p1)
']' { r_init(&reps);
elem = mkterm(p1,t,&reps,ln);
']' {
mkterm(p1,t,ln,pres);
}
| %default
C_IDENT { elem = search(UNKNOWN,lextoken.t_string,BOTH); }
[ params(0) { if (nparams > 6) {
|
C_IDENT { pe = search(UNKNOWN,lextoken.t_string,BOTH);
*pres = *pe;
}
[ params(0) { if (nparams > 14) {
error(linecount,"Too many parameters");
} else g_setnpar(&elem,nparams+1);
if (g_gettype(&elem) == TERMINAL) {
} else g_setnpar(pres,nparams+1);
if (g_gettype(pres) == TERMINAL) {
error(linecount,
"Terminal with parameters");
}
}
]?
| C_LITERAL { elem = search(LITERAL,lextoken.t_string,BOTH); }
| { g_settype(&elem,ACTION);
elem.g_lineno = linecount;
| C_LITERAL { pe = search(LITERAL,lextoken.t_string,BOTH);
*pres = *pe;
}
| { g_settype(pres,ACTION);
pres->g_lineno = linecount;
}
action(1)
;
@ -371,20 +420,21 @@ expr : '(' { copyact('(',')',1,0); }
')'
;
repeats(t_reps *t;) { int t1 = 0; } :
repeats(int *kind, *cnt;) { int t1 = 0; } :
[
'?' { r_setkind(t,OPT); }
| [ '*' { r_setkind(t,STAR); }
| '+' { r_setkind(t,PLUS); }
'?' { *kind = OPT; }
| [ '*' { *kind = STAR; }
| '+' { *kind = PLUS; }
]
number(&t1)?
{ if (t1 == 1 && r_getkind(t) == PLUS) {
error(linecount,
"Illegal repetition specifier");
{ if (t1 == 1) {
t1 = 0;
if (*kind == STAR) *kind = OPT;
if (*kind == PLUS) *kind = FIXED;
}
}
| number(&t1)
] { r_setnum(t,t1); }
] { *cnt = t1; }
;
number(int *t;)
@ -404,12 +454,12 @@ firsts { register string p; }
* Store this %first in the list belonging
* to this input file
*/
t_gram temp;
p_gram temp;
register p_first ff;
temp = search(NONTERM,lextoken.t_string,BOTH);
ff = (p_first) alloc(sizeof(t_first));
ff->ff_nont = &nonterms[g_getnont(&temp)];
ff->ff_nont = g_getnont(temp);
ff->ff_name = p;
ff->ff_next = pfile->f_firsts;
pfile->f_firsts = ff;
@ -436,11 +486,9 @@ copyact(ch1,ch2,flag,level) char ch1,ch2; {
if (!level) {
saved = linecount;
nparams = 0; /* count comma's */
putc('\0',f);
fprintf(f,"# line %d \"%s\"\n", linecount,f_input);
if (flag == 1) putc(ch1,f);
fprintf(f,"%c# line %d \"%s\"\n", '\0', linecount,f_input);
}
else putc(ch1,f);
if (level || flag == 1) putc(ch1,f);
for (;;) {
ch = input();
if (ch == ch2) {
@ -451,7 +499,7 @@ copyact(ch1,ch2,flag,level) char ch1,ch2; {
}
return;
}
if (! isspace(ch)) semicolon = 0;
if (c_class[ch] != ISSPA) semicolon = 0;
switch(ch) {
case ')':
case '}':
@ -474,6 +522,7 @@ copyact(ch1,ch2,flag,level) char ch1,ch2; {
skipcomment(1);
continue;
}
ch = '/';
break;
case ';':
semicolon = 1;
@ -516,21 +565,8 @@ copyact(ch1,ch2,flag,level) char ch1,ch2; {
}
}
static int ecount; /* Index in "pentry" array */
STATIC unsigned
get(size) unsigned size; {
/*
* Get some core, save a pointer to it in "pentry",
* return index in pentry
*/
if (ecount >= ENTSIZ) fatal(linecount,"Entry table overflow");
pentry[ecount] = alloc(size);
return ecount++;
}
STATIC p_gram
copyrule(p,length) register p_gram p; register length; {
copyrule(p,length) register p_gram p; {
/*
* Returns a pointer to a grammar rule that was created in
* p. The space pointed to by p can now be reused

View file

@ -1,11 +1,11 @@
# $Header$
PROF=
LLOPT= # -vvv -x
CFLAGS=$(PROF) -O -DNDEBUG # -R
CFLAGS=$(PROF) -O -DNDEBUG
LDFLAGS=-i
OBJECTS = main.o gencode.o compute.o LLgen.o tokens.o check.o reach.o global.o name.o sets.o Lpars.o alloc.o machdep.o
CFILES = main.c gencode.c compute.c LLgen.c tokens.c check.c reach.c global.c name.c sets.c Lpars.c alloc.c machdep.c
FILES =types.h tunable.h extern.h io.h sets.h assert.h tokens.g LLgen.g main.c name.c compute.c sets.c gencode.c global.c check.c reach.c alloc.c machdep.c Makefile
OBJECTS = main.o gencode.o compute.o LLgen.o tokens.o check.o reach.o global.o name.o sets.o Lpars.o alloc.o machdep.o cclass.o
CFILES = main.c gencode.c compute.c LLgen.c tokens.c check.c reach.c global.c name.c sets.c Lpars.c alloc.c machdep.c cclass.c
FILES =types.h tunable.h extern.h io.h sets.h assert.h tokens.g LLgen.g main.c name.c compute.c sets.c gencode.c global.c check.c reach.c alloc.c machdep.c Makefile cclass.c
GFILES = tokens.g LLgen.g
LINT = lint -b -DNDEBUG -DNORCSID
@ -19,7 +19,7 @@ parser: $(GFILES)
@touch parser
LLgen: $(OBJECTS)
$(CC) $(PROF) $(LDFLAGS) $(OBJECTS) -o LLgen
$(CC) $(PROF) $(LDFLAGS) $(OBJECTS) -o LLgen
@size LLgen
pr :
@ -39,9 +39,9 @@ distr:
# AUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTOAUTO
LLgen.o: Lpars.h
LLgen.o: assert.h
LLgen.o: cclass.h
LLgen.o: extern.h
LLgen.o: io.h
LLgen.o: tunable.h
LLgen.o: types.h
Lpars.o: Lpars.h
alloc.o: extern.h
@ -50,22 +50,20 @@ check.o: assert.h
check.o: extern.h
check.o: io.h
check.o: sets.h
check.o: tunable.h
check.o: types.h
compute.o: assert.h
compute.o: extern.h
compute.o: io.h
compute.o: sets.h
compute.o: tunable.h
compute.o: types.h
gencode.o: assert.h
gencode.o: cclass.h
gencode.o: extern.h
gencode.o: io.h
gencode.o: sets.h
gencode.o: tunable.h
gencode.o: types.h
global.o: extern.h
global.o: io.h
global.o: tunable.h
global.o: types.h
machdep.o: ../../../h/em_path.h
machdep.o: types.h
@ -77,12 +75,10 @@ main.o: types.h
name.o: assert.h
name.o: extern.h
name.o: io.h
name.o: tunable.h
name.o: types.h
reach.o: assert.h
reach.o: extern.h
reach.o: io.h
reach.o: tunable.h
reach.o: types.h
sets.o: assert.h
sets.o: extern.h
@ -90,7 +86,7 @@ sets.o: sets.h
sets.o: types.h
tokens.o: Lpars.h
tokens.o: assert.h
tokens.o: cclass.h
tokens.o: extern.h
tokens.o: io.h
tokens.o: tunable.h
tokens.o: types.h

View file

@ -32,15 +32,18 @@
# include "extern.h"
# ifndef NORCSID
static string rcsida = "$Header$";
static string rcsid = "$Header$";
# endif
static string e_nomem = "Out of memory";
p_mem
alloc(size) unsigned size; {
register p_mem p;
p_mem malloc();
/*
Allocate "size" bytes. Panic if it fails
*/
p_mem p;
p_mem malloc();
if ((p = malloc(size)) == 0) fatal(linecount,e_nomem);
return p;
@ -48,9 +51,41 @@ alloc(size) unsigned size; {
p_mem
ralloc(p,size) p_mem p; unsigned size; {
register p_mem q;
p_mem realloc();
/*
Re-allocate the chunk of memory indicated by "p", to
occupy "size" bytes
*/
p_mem realloc();
if ((q = realloc(p,size)) == 0) fatal(linecount,e_nomem);
return q;
if ((p = realloc(p,size)) == 0) fatal(linecount,e_nomem);
return p;
}
p_mem
new_mem(p) p_info p; {
/*
This routine implements arrays that can grow.
It must be called every time a new element is added to it.
Also, the array has associated with it a "info_alloc" structure,
which contains info on the element size, total allocated size,
a pointer to the array, a pointer to the first free element,
and a pointer to the top.
If the base of the array is remembered elsewhere, it should
be updated each time this routine is called
*/
p_mem rp;
unsigned sz;
if (p->i_max >= p->i_top) { /* No more free elements */
sz = p->i_size;
p->i_size += p->i_incr * p->i_esize;
p->i_ptr = !p->i_ptr ?
alloc(p->i_size) :
ralloc(p->i_ptr, p->i_size);
p->i_max = p->i_ptr + sz;
p->i_top = p->i_ptr + p->i_size;
}
rp = p->i_max;
p->i_max += p->i_esize;
return rp;
}

View file

@ -30,7 +30,6 @@
# include "types.h"
# include "extern.h"
# include "tunable.h"
# include "io.h"
# include "sets.h"
# include "assert.h"
@ -39,21 +38,18 @@
static string rcsid1 = "$Header$";
# endif
# define PTERM(p) fprintf(fout,(p)->h_num < 0400 ? "'%s' " : "%s ",(p)->h_name);
static string c_first = "> firstset ";
static string c_contains = "> containset ";
static string c_follow = "> followset ";
p_set setalloc();
static string ntname; /* nonterminal that is currently checked */
static p_nont nt; /* pointer to its struct */
static int level;
/* In this file are defined : */
extern conflchecks();
STATIC newline();
STATIC prline();
STATIC printset();
STATIC check();
STATIC int check();
STATIC moreverbose();
STATIC prrule();
STATIC cfcheck();
@ -70,8 +66,7 @@ conflchecks() {
* must be disjunct.
*/
register p_nont p;
register FILE *f;
register short *s;
register p_order s;
p_file x = files;
f_input = x->f_name;
@ -79,38 +74,43 @@ conflchecks() {
for (p = nonterms; p < maxnt; p++) p->n_flags |= VERBOSE;
}
if (verbose) {
if ((f = fopen(f_out,"w")) == NULL) fatal(1,e_noopen,f_out);
fout = f;
if ((fout = fopen(f_out,"w")) == NULL) fatal(1,e_noopen,f_out);
}
/*
* Check the rules in the order in which they are declared,
* and input file by input file, to give proper error messages
*/
for (; x->f_end < maxorder; x++) {
for (; x < maxfiles; x++) {
f_input = x->f_name;
for (s = x->f_start; s <= x->f_end; s++) {
nt = p = &nonterms[*s];
ntname = (min_nt_ent + *s)->h_name;
for (s = x->f_list; s; s = s->o_next) {
p = &nonterms[s->o_index];
if (check(p->n_rule)) p->n_flags |= VERBOSE;
}
}
for (x = files; x < maxfiles; x++) {
f_input = x->f_name;
for (s = x->f_list; s; s = s->o_next) {
p = &nonterms[s->o_index];
if (p->n_flags & RECURSIVE) {
error(p->n_lineno,
"Recursion in default for nonterminal %s",
ntname);
p->n_name);
}
check(p->n_rule);
/*
* If a printout is needed for this rule in
* LL.output, just do it
*/
if (verbose && (p->n_flags & VERBOSE)) {
fprintf(f,"\n%s :\n",ntname);
fprintf(fout,"\n%s :\n",p->n_name);
printset(p->n_first,c_first);
printset(p->n_contains,c_contains);
printset(p->n_follow,c_follow);
fputs("> rule\n\t",f);
fprintf(fout,"> rule%s\n\t",
p->n_flags&EMPTY ? "\t(EMPTY producing)" : "");
level = 8;
prrule(p->n_rule);
level = 0;
newline();
prline("\n");
}
/*
* Now, the conflicts may be resolved
@ -118,16 +118,13 @@ conflchecks() {
resolve(p->n_rule);
}
}
if (verbose) fclose(f);
if (verbose) fclose(fout);
}
STATIC
newline() {
/*
* Newline and "level" spaces indentation
*/
if (level > 0) fprintf(fout,"\n%*c",level,' ');
else putc('\n',fout);
prline(s) char *s; {
fputs(s, fout);
spaces();
}
STATIC
@ -135,69 +132,68 @@ printset(p,s) register p_set p; string s; {
/*
* Print the elements of a set
*/
register FILE *f;
register i;
register j;
register int i;
register int j;
register p_token pt;
string name;
int k;
int hulp;
k = strlen(s)+1;
k = strlen(s) + 2 + level;
/*
* k contains relative level of indentation
*/
f = fout;
fprintf(f,"%s{ ",s);
j = level+1+k;
fprintf(fout,"%s{ ",s);
j = k;
/*
* j will gather the total length of the line
*/
if (p == (p_set) 0) fputs(">non existent (yet?)< ",f);
else {
for (i = 0; i < nterminals; i++) {
if (IN(p,i)) {
hulp = strlen(h_entry[i].h_name)+1;
if (h_entry[i].h_num < 0400) hulp += 2;
if ((j += hulp) >= 78) {
/*
* Line becoming too long
*/
j = level+k+1+hulp;
newline();
fprintf(f,">%*c",k,' ');
}
PTERM(&h_entry[i]);
}
}
if (ntprint) for (i = 0; i < nnonterms; i++) {
/*
* Nonterminals in the set must also be printed
*/
if (NTIN(p,i)) {
hulp = strlen((min_nt_ent+i)->h_name)+3;
if ((j += hulp) >= 78) {
j = level + k + 1 + hulp;
newline();
fprintf(f,">%*c",k,' ');
}
fprintf(f,"<%s> ",(min_nt_ent+i)->h_name);
for (i = 0, pt = tokens; i < ntokens; i++,pt++) {
if (IN(p,i)) {
hulp = strlen(pt->t_string)+1;
if (pt->t_tokno < 0400) hulp += 2;
if ((j += hulp) >= 78) {
/*
* Line becoming too long
*/
j = k+hulp;
prline("\n");
fprintf(fout,">%*c",k - level - 1,' ');
}
fprintf(fout, pt->t_tokno<0400 ? "'%s' " : "%s ",pt->t_string);
}
}
putc('}',f);
newline();
if (ntprint) for (i = 0; i < nnonterms; i++) {
/*
* Nonterminals in the set must also be printed
*/
if (NTIN(p,i)) {
name = nonterms[i].n_name;
hulp = strlen(name) + 3;
if ((j += hulp) >= 78) {
j = k + hulp;
prline("\n");
fprintf(fout,">%*c",k - level - 1,' ');
}
fprintf(fout,"<%s> ",name);
}
}
prline("}\n");
}
STATIC
STATIC int
check(p) register p_gram p; {
/*
* Search for conflicts in a grammar rule.
*/
p_set temp;
register p_set temp;
register int retval;
retval = 0;
for (;;) {
switch (g_gettype(p)) {
case EORULE :
return;
return retval;
case NONTERM : {
register p_nont n;
@ -205,28 +201,28 @@ check(p) register p_gram p; {
if (g_getnpar(p) != getntparams(n)) {
error(p->g_lineno,
"Call of %s : parameter count mismatch",
(min_nt_ent+g_getnont(p))->h_name);
n->n_name);
}
break; }
case TERM : {
register p_term q;
q = (p_term) pentry[g_getcont(p)];
check(q->t_rule);
if (r_getkind(&(q->t_reps)) == FIXED) break;
q = &terms[g_getcont(p)];
retval |= check(q->t_rule);
if (r_getkind(q) == FIXED) break;
if (setempty(q->t_first)) {
q->t_flags |= EMPTYFIRST;
nt->n_flags |= VERBOSE;
retval = 1;
error(p->g_lineno, "No symbols in term");
}
if (empty(q->t_rule)) {
q->t_flags |= EMPTYTERM;
nt->n_flags |= VERBOSE;
retval = 1;
error(p->g_lineno, "Term produces empty");
}
temp = setalloc(setsize);
setunion(temp,q->t_first,setsize);
if (!setintersect(temp,q->t_follow,setsize)) {
temp = setalloc();
setunion(temp,q->t_first);
if (!setintersect(temp,q->t_follow)) {
/*
* q->t_first * q->t_follow != EMPTY
*/
@ -235,16 +231,17 @@ check(p) register p_gram p; {
* No conflict resolver
*/
error(p->g_lineno,
"Repitition conflict");
nt->n_flags |= VERBOSE;
if (verbose == 2) moreverbose(temp);
"Repetition conflict");
retval = 1;
moreverbose(temp);
}
} else {
}
else {
if (q->t_flags & RESOLVER) {
q->t_flags |= NOCONF;
error(p->g_lineno,
"%%while, no conflict");
nt->n_flags |= VERBOSE;
retval = 1;
}
}
free((p_mem) temp);
@ -252,29 +249,30 @@ check(p) register p_gram p; {
case ALTERNATION : {
register p_link l;
l = (p_link) pentry[g_getcont(p)];
temp = setalloc(setsize);
setunion(temp,l->l_symbs,setsize);
if(!setintersect(temp,l->l_others,setsize)) {
l = &links[g_getcont(p)];
temp = setalloc();
setunion(temp,l->l_symbs);
if(!setintersect(temp,l->l_others)) {
/*
* temp now contains the conflicting
* symbols
*/
if (!(l->l_flag & (COND|PREFERING|AVOIDING))) {
error(p->g_lineno,
"Alternation conflict");
nt->n_flags |= VERBOSE;
if (verbose == 2) moreverbose(temp);
"Alternation conflict");
retval = 1;
moreverbose(temp);
}
} else {
if (l->l_flag & (COND|PREFERING|AVOIDING)) {
l->l_flag |= NOCONF;
error(p->g_lineno,"No conflict");
nt->n_flags |= VERBOSE;
error(p->g_lineno,
"Conflict resolver without conflict");
retval = 1;
}
}
free( (p_mem) temp);
check(l->l_rule);
retval |= check(l->l_rule);
break; }
}
p++;
@ -288,10 +286,11 @@ moreverbose(t) register p_set t; {
* also containing nonterminals.
* Take care that a printout will be prepared for these nonterminals
*/
register i;
register int i;
register p_nont p;
if (verbose) for (i = 0; i < nnonterms; i++) {
if (NTIN(t,i)) nonterms[i].n_flags |= VERBOSE;
if (verbose == 2) for (i = 0, p = nonterms; i < nnonterms; i++, p++) {
if (NTIN(t,i)) p->n_flags |= VERBOSE;
}
}
@ -307,54 +306,45 @@ prrule(p) register p_gram p; {
for (;;) {
switch (g_gettype(p)) {
case EORULE :
putc('\n',f);
fputs("\n",f);
return;
case TERM : {
register p_term q;
register c;
register int c;
q = (p_term) pentry[g_getcont(p)];
if (present) newline();
if (r_getkind(&(q->t_reps)) != FIXED ||
r_getnum(&(q->t_reps)) != 0) {
fputs("[ ",f);
level += 4;
if (q->t_flags & RESOLVER) {
fputs("%%while (..)",f);
newline();
}
if (r_getkind(&(q->t_reps)) != FIXED) {
printset(q->t_first, c_first);
printset(q->t_contains, c_contains);
printset(q->t_follow,c_follow);
if (q->t_flags & EMPTYFIRST) {
fputs(">>> empty first",f);
newline();
}
if (q->t_flags & EMPTYTERM) {
fputs(">>> term produces empty",f);
newline();
}
cfcheck(q->t_first,q->t_follow,
q->t_flags & RESOLVER);
}
prrule(q->t_rule);
level -= 4;
spaces();
c = r_getkind(&(q->t_reps));
putc(']',f);
if (c != FIXED) {
c = (c==STAR)?'*':(c==PLUS)?'+':'?';
putc(c,f);
}
if (c = r_getnum(&(q->t_reps))) {
fprintf(f,"%d",c);
}
newline();
} else {
prrule(q->t_rule);
spaces();
q = &terms[g_getcont(p)];
if (present) prline("\n");
fputs("[ ",f);
level += 4;
if (q->t_flags & RESOLVER) {
prline("%while (..)\n");
}
if (q->t_flags & PERSISTENT) {
prline("%persistent\n");
}
if (r_getkind(q) != FIXED) {
printset(q->t_first, c_first);
printset(q->t_contains, c_contains);
printset(q->t_follow,c_follow);
if (q->t_flags & EMPTYFIRST) {
prline(">>> empty first\n");
}
if (q->t_flags & EMPTYTERM) {
prline(">>> term produces empty\n");
}
cfcheck(q->t_first,q->t_follow,
q->t_flags & RESOLVER);
}
prrule(q->t_rule);
level -= 4;
spaces();
c = r_getkind(q);
fputs(c == STAR ? "]*" : c == PLUS ? "]+" :
c == OPT ? "]?" : "]", f);
if (c = r_getnum(q)) {
fprintf(f,"%d",c);
}
prline("\n");
break; }
case ACTION :
fputs("{..} ",f);
@ -362,28 +352,44 @@ prrule(p) register p_gram p; {
case ALTERNATION : {
register p_link l;
l = (p_link) pentry[g_getcont(p)];
if (l->l_flag & (COND|PREFERING|AVOIDING)) {
printset(l->l_symbs,"> alt with resolver on ");
} else printset(l->l_symbs,"> alternative on ");
l = &links[g_getcont(p)];
if (g_gettype(p-1) == ALTERNATION) {
prline("|\n");
}
printset(l->l_symbs,"> alternative on ");
cfcheck(l->l_symbs,
l->l_others,
(int)(l->l_flag&(COND|PREFERING|AVOIDING)));
fputs(" ",f);
level += 4;
if (l->l_flag & DEF) {
prline("%default\n");
}
if (l->l_flag & AVOIDING) {
prline("%avoid\n");
}
if (l->l_flag & PREFERING) {
prline("%prefer\n");
}
if (l->l_flag & COND) {
prline("%if ( ... )\n");
}
prrule(l->l_rule);
level -= 4;
spaces();
if (g_gettype(p+1) == EORULE) {
fputs("> end alternatives\n",f);
return;
}
spaces();
p++; continue; }
case TERMINAL :
PTERM(&h_entry[g_getcont(p)]);
break;
case LITERAL :
case TERMINAL : {
register p_token pt = &tokens[g_getcont(p)];
fprintf(f,pt->t_tokno<0400 ?
"'%s' " : "%s ", pt->t_string);
break; }
case NONTERM :
fprintf(f,"%s ",(g_getnont(p)+min_nt_ent)->h_name);
fprintf(f,"%s ",nonterms[g_getnont(p)].n_name);
break;
}
p++;
@ -401,17 +407,16 @@ cfcheck(s1,s2,flag) p_set s1,s2; {
*/
register p_set temp;
temp = setalloc(setsize);
setunion(temp,s1,setsize);
if (!setintersect(temp,s2,setsize)) {
temp = setalloc();
setunion(temp,s1);
if (!setintersect(temp,s2)) {
if (! flag) {
printset(temp,">>> conflict on ");
newline();
prline("\n");
}
} else {
if (flag) {
fputs(">>> %if/%while, no conflict",fout);
newline();
prline(">>> %if/%while, no conflict\n");
}
}
free((p_mem) temp);
@ -427,18 +432,18 @@ resolve(p) register p_gram p; {
case EORULE :
return;
case TERM :
resolve(((p_term) pentry[g_getcont(p)])->t_rule);
resolve(terms[g_getcont(p)].t_rule);
break;
case ALTERNATION : {
register p_link l;
l = (p_link) pentry[g_getcont(p)];
l = &links[g_getcont(p)];
if (l->l_flag & AVOIDING) {
/*
* On conflicting symbols, this rule
* is never chosen
*/
setminus(l->l_symbs,l->l_others,setsize);
setminus(l->l_symbs,l->l_others);
}
if (setempty(l->l_symbs)) {
/*
@ -461,7 +466,7 @@ propagate(set,p) p_set set; register p_gram p; {
* p will not be chosen.
*/
while (g_gettype(p) != EORULE) {
setminus(((p_link) pentry[g_getcont(p)])->l_symbs,set,setsize);
setminus(links[g_getcont(p)].l_symbs,set);
p++;
}
}

File diff suppressed because it is too large Load diff

View file

@ -29,10 +29,12 @@
* some variables that are visible in more than one file
*/
# define LTEXTSZ 51 /* Size of longest token */
/*
* options for the identifier search routine
*/
# define JUSTLOOKING 0
# define ENTERING 1
# define BOTH 2
@ -42,27 +44,22 @@
extern char ltext[]; /* input buffer */
extern int nnonterms; /* number of nonterminals */
extern int nterminals; /* number of terminals */
extern int ntokens; /* number of terminals */
extern p_start start; /* will contain startsymbols */
extern int linecount; /* line number */
extern int assval; /* to create difference between literals
* and other terminals
*/
extern t_nont nonterms[]; /* the nonterminal array */
extern p_nont nonterms; /* the nonterminal array */
extern p_nont maxnt; /* is filled up until here */
extern int order[]; /* order of nonterminals in the grammar,
extern p_token tokens; /* the token array */
extern p_token maxt; /* is filled up until here */
extern struct order *sorder, *porder;
/* order of nonterminals in the grammar,
* important because actions are copied to
* a temporary file in the order in which they
* were read
*/
extern int *maxorder; /* will contain &order[nnonterms] */
extern t_entry h_entry[]; /* terminal and nonterminal entrys,
* first NTERMINAL entrys reserved
* for terminals
*/
extern p_entry max_t_ent; /* will contain &h_entry[nterminals] */
# define min_nt_ent &h_entry[NTERMINALS]
extern string pentry[]; /* pointers to various allocated things */
extern string e_noopen; /* Error message string used often */
extern int verbose; /* Level of verbosity */
extern string lexical; /* name of lexical analyser */
@ -78,9 +75,10 @@ extern int debug;
extern p_file files,pfile; /* pointers to file structure.
* "files" points to the start of the
* list */
extern p_file maxfiles;
extern string LLgenid; /* LLgen identification string */
extern t_token lextoken; /* the current token */
extern int nerrors;
extern int fflag; /* Enable compiler to generate jump tables
* for switches?
*/
extern string rec_file, incl_file;
extern p_term terms;
extern p_link links;

View file

@ -32,10 +32,10 @@
# include "types.h"
# include "io.h"
# include "tunable.h"
# include "extern.h"
# include "sets.h"
# include "assert.h"
# include "cclass.h"
# ifndef NORCSID
static string rcsid3 = "$Header$";
@ -47,7 +47,6 @@ static string rcsid3 = "$Header$";
static string c_arrend = "0 };\n";
static string c_close = "}\n";
static string c_LLptrmin = "LLptr++;\n";
static string c_break = "break;\n";
static string c_read = "LLread();\n";
@ -57,10 +56,7 @@ static string c_read = "LLread();\n";
static int nlabel; /* count for the generation of labels */
static int nvar; /* count for generation of variables */
static int pushlist[100];
static int *ppushlist;
static int *lists,*maxlists,*plists;
p_mem ralloc(),alloc();
static int firsts; /* are there any? */
/* In this file the following routines are defined: */
extern gencode();
@ -75,30 +71,27 @@ STATIC controlline();
STATIC getparams();
STATIC gettok();
STATIC rulecode();
STATIC int dopush();
STATIC pushcode();
STATIC int * dopush();
STATIC getaction();
STATIC alternation();
STATIC codeforterm();
STATIC genifhead();
STATIC genswhead();
STATIC gencases();
STATIC genpush();
STATIC genpop();
STATIC genincrdecr();
/* Macro to print a terminal */
# define PTERM(f,p) fprintf(f,(p)->h_num<0400?"'%s'":"%s",(p)->h_name)
# define NOPOP -20000
p_mem alloc();
gencode(argc) {
register p_file p = files;
/* Generate include file Lpars.h */
geninclude();
/* Set up for code generation */
if ((fact = fopen(f_temp,"r")) == NULL) {
fatal(0,e_noopen,f_temp);
}
lists = (int *) alloc(50 * sizeof(int));
plists = lists;
maxlists = lists+49;
/* For every source file .... */
while (argc--) {
@ -106,7 +99,7 @@ gencode(argc) {
f_input = p->f_name;
opentemp(f_input);
/* generate code ... */
copyfile(0);
copyfile(incl_file);
generate(p);
getaction(2);
if (ferror(fpars) != 0) {
@ -117,6 +110,7 @@ gencode(argc) {
install(genname(p->f_name),p->f_name);
p++;
}
geninclude();
genrecovery();
}
@ -126,86 +120,98 @@ opentemp(str) string str; {
if ((fpars = fopen(f_pars,"w")) == NULL) {
fatal(0,e_noopen,f_pars);
}
fprintf(fpars,LLgenid,str ? str : ".");
if (!str) str = ".";
fprintf(fpars,LLgenid,str);
}
STATIC
geninclude() {
register p_entry p;
register FILE *f;
register p_token p;
opentemp((string) 0);
f = fpars;
for (p = h_entry; p < max_t_ent; p++) {
if (p->h_num >= 0400) {
fprintf(f,"# define %s %d\n", p->h_name,p->h_num);
for (p = tokens; p < maxt; p++) {
if (p->t_tokno >= 0400) {
fprintf(fpars,"# define %s %d\n",
p->t_string,
p->t_tokno);
}
}
if (ferror(f) != 0) {
if (ferror(fpars) != 0) {
fatal(0,"write error on temporary");
}
fclose(f);
install(HFILE, (string) 0);
fclose(fpars);
install(HFILE, ".");
}
STATIC
genrecovery() {
register FILE *f;
register p_entry t;
register int i;
register p_token t;
register int *q;
int index[256+NTERMINALS];
register p_nont p;
register p_set *psetl;
int *index;
int i;
register p_start st;
opentemp((string) 0);
f = fpars;
copyfile(0);
copyfile(incl_file);
if (!firsts) fputs("#define LLNOFIRSTS\n", f);
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!
*/
p = &nonterms[st->ff_nont];
if (g_gettype(p->n_rule) == ALTERNATION) {
findindex(p->n_contains);
}
}
i = maxptr - setptr;
fprintf(fpars,
"#define LL_LEXI %s\n#define LL_SSIZE %d\n#define LL_NSETS %d\n#define LL_NTERMINALS %d\n",
lexical,
nbytes,
i > 0 ? i : 1,
ntokens);
/* Now generate the routines that call the startsymbols */
fputs("#define LLSTSIZ 1024\n",f);
for (i = 1, st = start; st; st = st->ff_next) {
i++;
for (st = start; st; st = st->ff_next) {
fputs(st->ff_name, f);
fputs("() {\n\tint LLstack[LLSTSIZ];\n\tLLnewlevel(LLstack);\n\tLLread();\n", f);
if (g_gettype(st->ff_nont->n_rule) == ALTERNATION) {
fprintf(f, "\tLLxx.LLx_p--; *LLxx.LLx_p = %d;\n",
findindex(&(st->ff_nont->n_contains)));
p = &nonterms[st->ff_nont];
fputs("() {\n\tunsigned int s[LL_NTERMINALS+LL_NSETS+1];\n\tLLnewlevel(s);\n\tLLread();\n", f);
if (g_gettype(p->n_rule) == ALTERNATION) {
genpush(findindex(p->n_contains));
}
fprintf(f, "\tL%d_%s();\n",
st->ff_nont-nonterms,
(min_nt_ent+(st->ff_nont-nonterms))->h_name);
if (getntout(st->ff_nont) == NOSCANDONE) {
st->ff_nont,
p->n_name);
if (getntout(p) == NOSCANDONE) {
fputs("\tLLscan(EOFILE);\n",f);
}
else fputs("\tif (LLsymb != EOFILE) LLerror(EOFILE);\n",f);
fputs("\tLLoldlevel();\n}\n",f);
fputs("\tLLoldlevel(s);\n}\n",f);
}
fprintf(f,"#define LL_MAX %d\n#define LL_LEXI %s\n", i, lexical);
fputs("static short LLlists[] = {\n", f);
/* Now generate lists */
q = lists;
while (q < plists) {
fprintf(f,"%d,\n",*q++);
}
fputs(c_arrend, f);
/* Now generate the sets */
fputs("char LLsets[] = {\n",f);
for (i = 0; i < maxptr-setptr; i++) prset(setptr[i]);
for (psetl = setptr; psetl < maxptr; psetl++) prset(*psetl);
fputs(c_arrend, f);
for (q = index; q <= &index[255 + NTERMINALS];) *q++ = -1;
for (t = h_entry; t < max_t_ent; t++) {
index[t->h_num] = t - h_entry;
index = (int *) alloc((unsigned) (assval * sizeof(int)));
for (q = index; q < &index[assval];) *q++ = -1;
for (t = tokens; t < maxt; t++) {
index[t->t_tokno] = t - tokens;
}
fputs("short LLindex[] = {\n",f);
for (q = index; q <= &index[assval-1]; q++) {
for (q = index; q < &index[assval]; q++) {
fprintf(f, "%d,\n", *q);
}
fputs(c_arrend, f);
copyfile(1);
free((p_mem) index);
copyfile(rec_file);
if (ferror(f) != 0) {
fatal(0,"write error on temporary");
}
fclose(f);
install(RFILE, (string) 0);
install(RFILE, ".");
}
STATIC
@ -213,48 +219,49 @@ generate(f) p_file f; {
/*
* Generates a parsing routine for every nonterminal
*/
register short *s;
register p_order s;
register p_nont p;
register FILE *fd;
int i;
p_first ff;
register p_first ff;
int mustpop;
/* Generate first sets */
for (ff = f->f_firsts; ff; ff = ff->ff_next) {
macro(ff->ff_name,ff->ff_nont);
macro(ff->ff_name,&nonterms[ff->ff_nont]);
}
/* For every nonterminal generate a function */
fd = fpars;
for (s = f->f_start; s <= f->f_end; s++) {
p = &nonterms[*s];
for (s = f->f_list; s; s = s->o_next) {
p = &nonterms[s->o_index];
/* Generate functions in the order in which the nonterminals
* were defined in the grammar. This is important, because
* of synchronisation with the action file
*/
while (p->n_count--) getaction(1);
if (p->n_flags & PARAMS) controlline();
fprintf(fd,"L%d_%s (",*s,(min_nt_ent + *s)->h_name);
if (p->n_flags & PARAMS) getparams();
else fputs(") {\n", fd);
fputs("register struct LLxx *LLx = &LLxx;\n#ifdef lint\nLLx=LLx;\n#endif\n", fd);
fprintf(fpars,"L%d_%s (\n",s->o_index,p->n_name);
if (p->n_flags & PARAMS) {
controlline();
getparams();
}
else fputs(") {\n", fpars);
if (p->n_flags & LOCALS) getaction(1);
i = getntsafe(p);
mustpop = 0;
if (g_gettype(p->n_rule) == ALTERNATION) {
mustpop = 1;
mustpop = NOPOP;
if (g_gettype(p->n_rule) == ALTERNATION &&
i > SAFESCANDONE) {
mustpop = findindex(p->n_contains);
if (i == NOSCANDONE) {
fputs(c_read, fd);
fputs(c_read, fpars);
i = SCANDONE;
}
}
nlabel = 1;
nvar = 1;
rulecode(p->n_rule,
i,
getntout(p) != NOSCANDONE,
mustpop);
fputs(c_close, fd);
fputs(c_close, fpars);
}
}
@ -264,7 +271,7 @@ prset(p) p_set p; {
register unsigned i;
int j;
j = NBYTES(nterminals);
j = nbytes;
for (;;) {
i = (unsigned) *p++;
for (k = 0; k < sizeof(int); k++) {
@ -281,17 +288,17 @@ prset(p) p_set p; {
STATIC
macro(s,n) string s; p_nont n; {
register FILE *f;
int i;
f = fpars;
i = findindex(&(n->n_first));
fprintf(f,"#define %s(x) ", s);
i = findindex(n->n_first);
if (i < 0) {
fprintf(f, "((x) == %d)\n", -i);
fprintf(fpars, "#define %s(x) ((x) == %d)\n",
s,
tokens[-(i+1)].t_tokno);
return;
}
fprintf(f,"LLfirst((x), %d)\n", i);
firsts = 1;
fprintf(fpars,"#define %s(x) LLfirst((x), %d)\n", s, i);
}
STATIC
@ -303,8 +310,6 @@ controlline() {
f1 = fact; f2 = fpars;
l = getc(f1);
assert(l == '\0');
l = getc(f1); putc(l,f2);
assert( l == '#' ) ;
do {
l = getc(f1);
putc(l,f2);
@ -318,12 +323,10 @@ getparams() {
*/
long off;
register int l;
register FILE *f;
long ftell();
char first;
first = ' ';
f = fpars;
/* save offset in file to be able to copy the declaration later */
off = ftell(fact);
/* First pass through declaration, find the parameter names */
@ -333,17 +336,17 @@ getparams() {
* The last identifier found before a ';' or a ','
* must be a parameter
*/
fprintf(f,"%c%s", first, ltext);
fprintf(fpars,"%c%s", first, ltext);
first = ',';
}
}
fputs(") ",f);
fputs(") ",fpars);
/*
* Now copy the declarations
*/
fseek(fact,off,0);
getaction(0);
fputs(" {\n",f);
fputs(" {\n",fpars);
}
STATIC
@ -369,13 +372,13 @@ gettok() {
case EOF :
return ENDDECL;
default :
if (isalpha(ch) || ch == '_') {
if (c_class[ch] == ISLET) {
c = ltext;
while (isalnum(ch) || ch == '_') {
do {
*c++ = ch;
if (c-ltext >= LTEXTSZ) --c;
ch = getc(f);
}
} while (c_class[ch] == ISLET || c_class[ch] == ISDIG);
if (ch != EOF) ungetc(ch,f);
*c = '\0';
return IDENT;
@ -392,13 +395,27 @@ rulecode(p,safety,mustscan,mustpop) register p_gram p; {
register int toplevel = 1;
register FILE *f;
register int *ppu;
int pushlist[100];
int *ppushlist;
/*
* First generate code to push the contains sets of this rule
* on a stack
*/
ppushlist = pushlist;
if (dopush(p,safety,1) > 0) pushcode();
ppu = pushlist;
ppushlist = dopush(p,safety,1,ppu);
if (mustpop != NOPOP) for (; ppu < ppushlist; ppu++) {
if (*ppu == mustpop) {
*ppu = mustpop = NOPOP;
break;
}
}
if (g_gettype(p) != ALTERNATION) {
genpop(mustpop);
mustpop = NOPOP;
}
for (ppu = pushlist; ppu < ppushlist; ppu++) genpush(*ppu);
f = fpars;
for (;;) {
switch (g_gettype(p)) {
@ -407,25 +424,31 @@ rulecode(p,safety,mustscan,mustpop) register p_gram p; {
fputs(c_read,f);
}
return;
case LITERAL :
case TERMINAL : {
register p_entry t;
register p_token t;
string s;
t = &h_entry[g_getcont(p)];
t = &tokens[g_getcont(p)];
if (toplevel == 0) {
fputs(c_LLptrmin,f);
fprintf(f,"LLtdecr(%d);\n", g_getcont(p));
}
if (safety == SAFE) {
fputs("LL_SAFE(",f);
}
else if (safety <= SCANDONE) {
else if (safety == SAFESCANDONE) {
fputs("LL_SSCANDONE(",f);
}
else if (safety == SCANDONE) {
fputs("LL_SCANDONE(",f);
}
else if (safety == NOSCANDONE) {
else /* if (safety == NOSCANDONE) */ {
fputs("LL_T_NOSCANDONE(", f);
}
PTERM(f,t);
fputs(");\n", f);
if (safety == SAFE && toplevel > 0) {
if (t->t_tokno < 0400) s = "'%s');\n";
else s = "%s);\n";
fprintf(f,s,t->t_string);
if (safety <= SAFESCANDONE && toplevel > 0) {
safety = NOSCANDONE;
toplevel = -1;
p++;
@ -434,36 +457,35 @@ rulecode(p,safety,mustscan,mustpop) register p_gram p; {
safety = NOSCANDONE;
break; }
case NONTERM : {
p_entry t;
register p_nont n;
int params;
n = &nonterms[g_getnont(p)];
t= min_nt_ent+(n-nonterms);
if (safety == NOSCANDONE &&
getntsafe(n) < NOSCANDONE) fputs(c_read, f);
if (toplevel == 0 &&
g_gettype(n->n_rule) != ALTERNATION) {
fputs(c_LLptrmin, f);
(g_gettype(n->n_rule) != ALTERNATION ||
getntsafe(n) <= SAFESCANDONE)) {
genpop(findindex(n->n_contains));
}
fprintf(f,"L%d_%s(\n",g_getnont(p), n->n_name);
if (g_getnpar(p)) {
controlline();
getaction(0);
}
params = g_getnpar(p);
if (params) controlline();
fprintf(f,"L%d_%s(",n-nonterms, t->h_name);
if (params) getaction(0);
fputs(");\n",f);
safety = getntout(n);
break; }
case TERM :
safety = codeforterm((p_term) pentry[g_getcont(p)],
safety,
toplevel);
safety = codeforterm(&terms[g_getcont(p)],
safety,
toplevel);
break;
case ACTION :
getaction(1);
p++;
continue;
case ALTERNATION :
alternation(p, safety, mustscan,mustpop, 0);
alternation(p, safety, mustscan, mustpop, 0, 0);
return;
}
p++;
@ -471,11 +493,11 @@ rulecode(p,safety,mustscan,mustpop) register p_gram p; {
}
}
alternation(p, safety, mustscan, mustpop, lb) register p_gram p; {
STATIC
alternation(p, safety, mustscan, mustpop, lb, var) register p_gram p; {
register FILE *f = fpars;
register p_link l;
int hulp, hulp1,hulp2;
int var;
int haddefault = 0;
int unsafe = 1;
int nsafe;
@ -483,24 +505,23 @@ alternation(p, safety, mustscan, mustpop, lb) register p_gram p; {
p_set setalloc();
assert(safety < NOSCANDONE);
l = (p_link) pentry[g_getcont(p)];
l = &links[g_getcont(p)];
hulp = nlabel++;
hulp1 = nlabel++;
hulp2 = nlabel++;
var = nvar++;
if (!lb) lb = hulp1;
if (safety <= SAFESCANDONE) unsafe = 0;
if (!unsafe && mustpop) {
mustpop = 0;
fputs(c_LLptrmin, f);
if (!unsafe) {
genpop(mustpop);
mustpop = NOPOP;
}
if (unsafe) {
fprintf(f,"{ int LL_%d = 0;\n", var);
if (hulp1 == lb) fprintf(f, "L_%d: \n", hulp1);
if (unsafe && hulp1 == lb) {
var = ++nvar;
fprintf(f,"{ int LL_%d = 0;\nL_%d: \n", var, hulp1);
}
fputs("switch(LLcsymb) {\n", f);
while (g_gettype(p) != EORULE) {
l = (p_link) pentry[g_getcont(p)];
l = &links[g_getcont(p)];
if (unsafe && (l->l_flag & DEF)) {
haddefault = 1;
fprintf(f,
@ -508,19 +529,18 @@ alternation(p, safety, mustscan, mustpop, lb) register p_gram p; {
var, var, lb, hulp2);
}
if (l->l_flag & COND) {
set = setalloc(tsetsize);
setunion(set, l->l_others, tsetsize);
setintersect(set, l->l_symbs, tsetsize);
setminus(l->l_symbs, set, tsetsize);
setminus(l->l_others, set, tsetsize);
set = setalloc();
setunion(set, l->l_others);
setintersect(set, l->l_symbs);
setminus(l->l_symbs, set);
setminus(l->l_others, set);
gencases(set);
free((p_mem) set);
controlline();
fputs("if (!",f);
getaction(0);
fprintf(f,") goto L_%d;\n", hulp);
}
if (!unsafe && (l->l_flag & DEF)) {
if (!haddefault && (l->l_flag & DEF)) {
fputs("default:\n", f);
haddefault = 1;
}
@ -532,111 +552,91 @@ alternation(p, safety, mustscan, mustpop, lb) register p_gram p; {
}
if (safety != SAFE) nsafe = SAFESCANDONE;
}
if (mustpop) fputs(c_LLptrmin, f);
rulecode(l->l_rule, nsafe, mustscan, 0);
rulecode(l->l_rule, nsafe, mustscan, mustpop);
fputs(c_break,f);
if (l->l_flag & COND) {
p++;
fprintf(f,"L_%d : ;\n",hulp);
if (g_gettype(p+1) == EORULE) {
setminus(links[g_getcont(p)].l_symbs, set);
free((p_mem) set);
continue;
}
free((p_mem) set);
if (!haddefault) {
fputs("default:\n", f);
}
else {
gencases(l->l_others);
safety = SAFE;
safety = SAFE;
}
fprintf(f,"L_%d : ;\n",hulp);
p++;
if (!unsafe && g_gettype(p+1) == EORULE) {
if (mustpop) fputs(c_LLptrmin, f);
rulecode(((p_link)pentry[g_getcont(p)])->l_rule,
safety,mustscan,0);
if (safety <= SAFESCANDONE) {
genpop(mustpop);
mustpop = NOPOP;
}
else alternation(p,safety,mustscan,mustpop,lb);
alternation(p,safety,mustscan,mustpop,lb,var);
break;
}
p++;
}
fputs(c_close, f);
if (unsafe) fputs(c_close, f);
return;
if (unsafe && hulp1 == lb) fputs(c_close, f);
}
STATIC int
dopush(p,safety,toplevel) register p_gram p; {
STATIC int *
dopush(p,safety,toplevel,pp) register p_gram p; register int *pp; {
/*
* The safety only matters if toplevel != 0
*/
register int count = 0;
for (;;) {
switch(g_gettype(p)) {
case EORULE :
case ALTERNATION :
return count;
return pp;
case TERM : {
register p_term q;
int rep, cnt;
q = (p_term) pentry[g_getcont(p)];
rep = r_getkind(&(q->t_reps));
cnt = r_getnum(&(q->t_reps));
count += dopush(p+1,SCANDONE,0);
if (toplevel > 0 &&
(rep == OPT || (rep == FIXED && cnt == 0))) {
if (safety <= SAFESCANDONE) return count;
q = &terms[g_getcont(p)];
rep = r_getkind(q);
cnt = r_getnum(q);
if (!(toplevel > 0 && safety <= SAFESCANDONE &&
(rep == OPT || (rep == FIXED && cnt == 0)))) {
*pp++ = findindex(q->t_contains);
}
*ppushlist++ = findindex(&(q->t_contains));
return count+1; }
break; }
case LITERAL :
case TERMINAL :
if (toplevel > 0 && safety == SAFE) {
count += dopush(p+1,NOSCANDONE,-1);
if (toplevel > 0 && safety <= SAFESCANDONE) {
toplevel = -1;
p++;
safety = NOSCANDONE;
continue;
}
else count += dopush(p+1, NOSCANDONE, 0);
if (toplevel != 0) {
return count;
}
*ppushlist++ = -h_entry[g_getcont(p)].h_num;
return count + 1;
if (toplevel == 0) *pp++ = -(g_getcont(p)+1);
break;
case NONTERM : {
register p_nont n;
n = &nonterms[g_getnont(p)];
count += dopush(p+1, SCANDONE, 0);
if (toplevel == 0 ||
g_gettype(n->n_rule) == ALTERNATION) {
*ppushlist++ = findindex(&n->n_contains);
count++;
(g_gettype(n->n_rule) == ALTERNATION &&
getntsafe(n) > SAFESCANDONE)) {
*pp++ = findindex(n->n_contains);
}
return count; }
break; }
case ACTION :
p++;
continue;
}
toplevel = 0;
safety = NOSCANDONE;
p++;
}
}
# define max(a,b) ((a) < (b) ? (b) : (a))
STATIC
pushcode() {
register int i,j,k;
register int *p = pushlist;
if ((i = ppushlist - p) == 0) return;
if (i <= 2) {
genpush(p[0]);
if (i == 2) genpush(p[1]);
return;
}
fprintf(fpars,"\LLlpush(%d, %d);\n",plists-lists, i);
if (maxlists - plists < i) {
j = plists - lists;
k = maxlists-lists+max(i+1,50);
lists = (int *) ralloc( (p_mem)lists,
(unsigned)(k+1)*sizeof(int));
plists = lists+j;
maxlists = lists+k;
}
while (i--) {
*plists++ = *p++;
}
}
STATIC
getaction(flag) {
@ -674,14 +674,14 @@ getaction(flag) {
newline = 0;
}
match = ch;
putc(ch,f);
while (ch = getc(fact)) {
if (ch == match) break;
for (;;) {
putc(ch,f);
ch = getc(fact);
if (ch == match || !ch) break;
if (ch == '\\') {
putc(ch,f);
ch = getc(fact);
}
putc(ch,f);
}
break;
case IDENT :
@ -711,35 +711,44 @@ codeforterm(q,safety,toplevel) register p_term q; {
register int rep;
int persistent;
int ispushed;
int sw = SAFE;
f = fpars;
i = r_getnum(&(q->t_reps));
rep = r_getkind(&(q->t_reps));
ispushed = !(toplevel > 0 && safety <= SAFESCANDONE &&
(rep == OPT || (rep == FIXED && i == 0)));
i = r_getnum(q);
rep = r_getkind(q);
persistent = (q->t_flags & PERSISTENT);
if (safety == NOSCANDONE && (rep != FIXED || i == 0)) {
ispushed = NOPOP;
if (!(toplevel > 0 && safety <= SAFESCANDONE &&
(rep == OPT || (rep == FIXED && i == 0)))) {
ispushed = findindex(q->t_contains);
}
if (safety == NOSCANDONE && (rep != FIXED || i == 0 ||
gettout(q) != NOSCANDONE)) {
fputs(c_read, f);
safety = SCANDONE;
}
if (ispushed) {
if ((safety <= SAFESCANDONE &&
(rep == OPT || (rep == FIXED && i == 0))) ||
(rep == FIXED && i == 0 &&
g_gettype(q->t_rule) != ALTERNATION)) {
fputs(c_LLptrmin, f);
ispushed = 0;
if (rep == PLUS && !persistent) {
int temp;
temp = findindex(q->t_first);
if (temp != ispushed) {
genpop(ispushed);
ispushed = temp;
genpush(temp);
}
}
if (i) {
/* N > 0, so generate fixed forloop */
fprintf(f,"{\nregister LL_i = %d;\n",i);
fputs("for (;;) {\nif (!LL_i--) {\nLLptr++;\n", f);
fputs("break;\n}\n", f);
fputs("{\nregister LL_i;\n", f);
assert(ispushed != NOPOP);
fprintf(f, "for (LL_i = %d; LL_i >= 0; LL_i--) {\n", i - 1);
if (rep == FIXED) {
if (gettout(q) == NOSCANDONE && safety == NOSCANDONE) {
fputs(c_read,f);
safety = SCANDONE;
fputs("if (!LL_i) ", f);
genpop(ispushed);
genpush(ispushed);
if (safety == NOSCANDONE) {
assert(gettout(q) == NOSCANDONE);
fputs(c_read, f);
}
}
}
@ -747,26 +756,36 @@ codeforterm(q,safety,toplevel) register p_term q; {
/* '+' or '*', so generate infinite loop */
fputs("for (;;) {\n",f);
}
if (rep == STAR || rep == OPT) {
genifhead(q, rep, safety, ispushed);
else if (safety <= SAFESCANDONE && rep == OPT) {
genpop(ispushed);
ispushed = NOPOP;
}
if (rep == STAR || rep == OPT) {
sw = genswhead(q, rep, i, safety, ispushed);
}
rulecode(q->t_rule,
t_safety(rep,i,persistent,safety),
gettout(q) != NOSCANDONE,
rep == FIXED ? ispushed : NOPOP);
if (gettout(q) == NOSCANDONE && rep != FIXED) {
fputs(c_read, f);
}
rulecode(q->t_rule,t_safety(rep,i,persistent,safety),
rep != FIXED || gettout(q) != NOSCANDONE,
rep == FIXED && i == 0 && ispushed);
/* in the case of '+', the if is after the code for the rule */
if (rep == PLUS) {
if (!persistent) {
fprintf(f, "*LLptr = %d;\n", findindex(&(q->t_first)));
/* ??? */
if (i) {
fputs("if (!LL_i) break;\n", f);
}
genifhead(q,rep,safety, ispushed);
sw = genswhead(q, rep, i, safety, ispushed);
}
if (rep != OPT && rep != FIXED) fputs("continue;\n", f);
if (rep != FIXED) {
fputs(c_close, f); /* Close switch */
if (sw > SAFESCANDONE && (q->t_flags & RESOLVER)) {
fputs(c_close, f);
}
if (rep != OPT) {
if (ispushed) fputs(c_LLptrmin, f);
fputs("break;\n", f);
genpop(ispushed);
fputs(c_break, f);
}
}
if (rep != OPT && (rep != FIXED || i > 0)) {
@ -779,34 +798,38 @@ codeforterm(q,safety,toplevel) register p_term q; {
}
STATIC
genifhead(q, rep, safety, ispushed) register p_term q; {
genswhead(q, rep, cnt, safety, ispushed) register p_term q; {
/*
* Generate if statement for term q
* Generate switch statement for term q
*/
register FILE *f;
p_set p1;
p_set setalloc();
int hulp1;
int hulp1, hulp2, var;
int safeterm;
f = fpars;
hulp1 = nlabel++;
if (rep == PLUS) safeterm = gettout(q) <= SAFESCANDONE;
else if (rep == OPT) safeterm = safety <= SAFESCANDONE;
else /* if (rep == STAR) */ {
safeterm = safety <= SAFESCANDONE && gettout(q) <= SAFESCANDONE;
if (rep == PLUS) safeterm = gettout(q);
else if (rep == OPT) safeterm = safety;
else /* if (rep == STAR) */ safeterm = max(safety, gettout(q));
if ((q->t_flags & RESOLVER) && safeterm > SAFESCANDONE) {
hulp2 = nlabel++;
var = nvar++;
fprintf(f, "{ int LL_%d = 0;\nL_%d : ", var, hulp2);
}
fputs("switch(LLcsymb) {\n", f);
if (q->t_flags & RESOLVER) {
p1 = setalloc(tsetsize);
setunion(p1,q->t_first,tsetsize);
setintersect(p1,q->t_follow,tsetsize);
hulp1 = nlabel++;
p1 = setalloc();
setunion(p1,q->t_first);
setintersect(p1,q->t_follow);
/*
* p1 now points to a set containing the conflicting
* symbols
*/
setminus(q->t_first, p1, tsetsize);
setminus(q->t_follow, p1, tsetsize);
setminus(q->t_first, p1);
setminus(q->t_follow, p1);
setminus(q->t_contains, p1);
gencases(p1);
free((p_mem) p1);
controlline();
@ -814,18 +837,42 @@ genifhead(q, rep, safety, ispushed) register p_term q; {
getaction(0);
fprintf(f, ") goto L_%d;\n", hulp1);
}
gencases(q->t_follow);
if (ispushed && rep == OPT) fputs(c_LLptrmin, f);
fputs("break;\n", f);
if (!safeterm) {
fputs("default: if (!LLnext()) break;\n", f);
gencases(q->t_first);
if (safeterm <= SAFESCANDONE) fputs("default:\n", f);
else gencases(q->t_follow);
if (rep == OPT) genpop(ispushed);
fputs(c_break, f);
if (safeterm > SAFESCANDONE) {
int i;
assert(ispushed != NOPOP);
if (ispushed >= 0) i = -ispushed;
else i = tokens[-(ispushed+1)].t_tokno;
fputs("default: if (", f);
if (q->t_flags & RESOLVER) {
fprintf(f, "LL_%d ||", var);
}
fprintf(f, "!LLnext(%d)) {\n", i);
if (rep == OPT) genpop(ispushed);
fputs(c_break, f);
fputs(c_close, f);
if (q->t_flags & RESOLVER) {
fprintf(f,"LL_%d = 1;\ngoto L_%d;\n", var, hulp2);
}
}
else fputs("default: ;\n", f);
if ((q->t_flags & PERSISTENT) && safeterm != SAFE) {
gencases(q->t_contains);
}
else gencases(q->t_first);
if (q->t_flags & RESOLVER) {
fprintf(f, "L_%d : ;\n", hulp1);
}
if (ispushed && rep == OPT) fputs(c_LLptrmin, f);
if (rep == OPT) genpop(ispushed);
if (cnt > 0) {
assert(ispushed != NOPOP);
fputs(rep == STAR ? "if (!LL_i) " : "if (LL_i == 1) ", f);
genpop(ispushed);
}
return safeterm;
}
STATIC
@ -845,27 +892,19 @@ gencases(setp) register p_set setp; {
* labeledstatement : labels statement ;
* labels : labels label | ;
*/
register p_entry p;
register i;
register p_token p;
register int i;
p = h_entry;
for (i=0; i < nterminals; i++) {
for (i = 0, p = tokens; i < ntokens; i++, p++) {
if (IN(setp,i)) {
fprintf(fpars,
p->h_num<0400 ? "case /* '%s' */ %d : ;\n"
p->t_tokno<0400 ? "case /* '%s' */ %d : ;\n"
: "case /* %s */ %d : ;\n",
p->h_name, i);
p->t_string, i);
}
p++;
}
}
STATIC
genpush(d) {
fprintf(fpars, "LLptr--;\n*LLptr = %d;\n",d);
}
static char namebuf[20];
STATIC string
@ -895,3 +934,23 @@ genname(s) string s; {
*d = '\0';
return namebuf;
}
STATIC
genpush(d) {
genincrdecr("incr", d);
}
STATIC
genincrdecr(s, d) string s; {
if (d == NOPOP) return;
if (d >= 0) {
fprintf(fpars, "LLs%s(%d);\n", s, d / nbytes);
return;
}
fprintf(fpars, "LLt%s(%d);\n", s, -(d + 1));
}
STATIC
genpop(d) {
genincrdecr("decr", d);
}

View file

@ -29,30 +29,28 @@
*/
# include "types.h"
# include "extern.h"
# include "io.h"
# include "tunable.h"
# ifndef NORCSID
static string rcsid4 = "$Header$";
# endif
char ltext[LTEXTSZ];
t_entry h_entry[NTERMINALS+NNONTERMS+1];
p_entry max_t_ent;
t_nont nonterms[NNONTERMS+1];
p_nont nonterms;
p_nont maxnt;
int nnonterms;
int nterminals;
int order[NNONTERMS+1];
int *maxorder;
p_token tokens;
p_token maxt;
int ntokens;
p_order porder, sorder;
p_start start;
int linecount;
int assval;
string pentry[ENTSIZ];
FILE *fout;
FILE *fpars;
FILE *finput;
FILE *fact;
p_nont maxnt;
string f_pars = PARSERFILE;
string f_out = OUTFILE;
string f_temp = ACTFILE;
@ -66,8 +64,11 @@ int ntprint;
int debug;
# endif not NDEBUG
p_file files;
p_file maxfiles;
p_file pfile;
string LLgenid = "/* LLgen generated code from source %s */\n";
t_token lextoken;
int nerrors;
int fflag;
string rec_file, incl_file;
p_link links;
p_term terms;

View file

@ -29,7 +29,6 @@
*/
# include <stdio.h>
# include <ctype.h>
/* FILES */

View file

@ -38,12 +38,10 @@
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();
STATIC doparse();
extern error();
extern fatal();
extern comfatal();
@ -56,11 +54,9 @@ extern badassertion();
main(argc,argv) register string argv[]; {
register string arg;
string libpath();
int nflag = 0;
/* Initialize */
maxorder = order;
assval = 0400;
/* read options */
@ -71,20 +67,11 @@ main(argc,argv) register string argv[]; {
case 'V':
verbose++;
continue;
case 'n':
case 'N':
nflag++;
continue;
case 'f':
case 'F':
fflag++;
continue;
# ifndef NDEBUG
case 'a':
case 'A':
case 'd':
case 'D':
debug++;
continue;
# endif not NDEBUG
case 'r':
case 'R':
if (rec_file) {
@ -101,6 +88,7 @@ main(argc,argv) register string argv[]; {
}
incl_file = ++arg;
break;
# endif not NDEBUG
case 'x':
case 'X':
ntneeded = 1;
@ -110,7 +98,9 @@ main(argc,argv) register string argv[]; {
fprintf(stderr,"illegal option : %c\n",*arg);
return 1;
}
# ifndef NDEBUG
break;
# endif
}
argv++;
argc--;
@ -119,46 +109,44 @@ main(argc,argv) register string argv[]; {
* 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");
# ifndef NDEBUG
if (!rec_file) {
# endif
rec_file = libpath("rec");
# ifndef NDEBUG
}
if (!incl_file) {
# endif
incl_file = libpath("incl");
# ifndef NDEBUG
}
# endif
if ((fact = fopen(f_temp,"w")) == NULL) {
fputs("Cannot create temporary\n",stderr);
return 1;
}
name_init();
a_init();
readgrammar(argc,argv);
if (nflag) comfatal();
setinit(ntneeded);
maxnt = &nonterms[nnonterms];
max_t_ent = &h_entry[nterminals];
maxt = &tokens[ntokens];
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
*/
do_compute();
conflchecks();
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);
fputs("No code generation for input from standard input\n",
stderr);
}
else gencode(argc);
UNLINK(f_temp);
UNLINK(f_pars);
return 0;
@ -180,32 +168,19 @@ readgrammar(argc,argv) char *argv[]; {
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++;
f_input = "standard input";
doparse(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++;
doparse(p++);
argv++;
fclose(finput);
}
}
p->f_start = maxorder+1;
p->f_end = maxorder;
maxfiles = p;
if (! lexical) lexical = "yylex";
/*
* There must be a start symbol!
@ -216,19 +191,30 @@ readgrammar(argc,argv) char *argv[]; {
if (nerrors) comfatal();
}
STATIC
doparse(p) register p_file p; {
linecount = 0;
p->f_name = f_input;
p->f_firsts = 0;
pfile = p;
sorder = 0;
porder = 0;
LLparse();
p->f_list = sorder;
}
/* 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);
if (!lineno) lineno = 1;
fprintf(stderr,"\"%s\", line %d : ",f_input, lineno);
fprintf(stderr,s,t,u);
fputs("\n",stderr);
}
/* VARARGS1 */
@ -253,16 +239,14 @@ comfatal() {
exit(1);
}
copyfile(n) {
copyfile(file) string file; {
/*
* 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 int c;
register FILE *f;
if ((f = fopen(n?rec_file:incl_file,"r")) == NULL) {
if ((f = fopen(file,"r")) == NULL) {
fatal(0,"Cannot open libraryfile, call an expert");
}
while ((c = getc(f)) != EOF) putc(c,fpars);
@ -275,12 +259,9 @@ install(target, source) string target, source; {
* 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];
register int c1, c2;
register FILE *f1, *f2;
int cnt;
/*
* First open temporary, generated for source
@ -288,41 +269,38 @@ install(target, source) string target, 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);
RENAME(f_pars, target);
return;
}
/*
* Here, if i != 0 the target must be recreated
* Compute length of LLgen identification string. The target must
* start with that!
*/
if (i) RENAME(f_pars,target);
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);
}
RENAME(f_pars,target);
}
}
#ifndef NDEBUG

View file

@ -25,11 +25,11 @@
/*
* name.c
* Defines the symboltable search routine and an initialising routine
* Defines the symboltable search routine, a name store routine and an
* initialising routine.
*/
# include "types.h"
# include "tunable.h"
# include "extern.h"
# include "assert.h"
# include "io.h"
@ -39,42 +39,68 @@ static string rcsid7 = "$Header$";
# endif
# define HASHSIZE 128
# define NMSIZ 2048 /* Room for names allocated NMSIZ bytes at a time */
static char name[NAMESZ]; /* space for names */
static int iname; /* index in nametable */
static char *name, *maxname;
static p_entry h_root[HASHSIZE]; /* hash table */
static string e_literal = "Illegal literal";
static p_entry entries, maxentries;
static t_info token_info, nont_info;
/* Defined in this file are: */
extern string store();
extern name_init();
STATIC int hash();
extern t_gram search();
STATIC p_entry newentry();
extern p_gram search();
p_mem alloc();
p_mem new_mem();
name_init() {
token_info.i_esize = sizeof (t_token);
token_info.i_incr = 25;
nont_info.i_esize = sizeof (t_nont);
nont_info.i_incr = 25;
search(TERMINAL,"EOFILE",ENTERING);
}
STATIC p_entry
newentry(str, next) string str; p_entry next; {
register p_entry p;
if ((p = entries) == maxentries) {
p = (p_entry) alloc(50 * sizeof(t_entry));
maxentries = p + 50;
}
entries = p + 1;
p->h_name = str;
p->h_next = next;
p->h_type.g_lineno = linecount;
return p;
}
string
store(s) register string s; {
store(s) string s; {
/*
* Store a string s in the name table
*/
register string t,u;
register string s1, t ,u;
u = t = &name[iname];
do { if (u > &name[NAMESZ-1]) fatal(linecount,"name table overflow");
else *u++ = *s;
} while (*s++);
iname = u - name;
return t;
}
name_init() {
/*
* Initialise hash-table and enter special terminal EOFILE
*/
register p_entry *p;
t_gram search();
for(p = h_root; p<= &h_root[HASHSIZE-1]; p++) *p = 0;
search(TERMINAL,"EOFILE",ENTERING);
u = name;
t = s;
s1 = u;
do {
if (u >= maxname) {
u = alloc(NMSIZ);
maxname = u + NMSIZ;
t = s;
s1 = u;
}
*u++ = *t;
} while (*t++);
name = u;
return s1;
}
STATIC int
@ -82,7 +108,7 @@ hash(str) string str; {
/*
* Compute the hash for string str
*/
register i;
register int i;
register string l;
l = str;
@ -92,151 +118,133 @@ hash(str) string str; {
return i % HASHSIZE;
}
t_gram
p_gram
search(type,str,option) register string str; {
/*
* Search for object str.
* It has type UNKNOWN, LITERAL, TERMINAL or NONTERM.
* option can be ENTERING, JUSTLOOKING or BOTH.
* option can be ENTERING or BOTH (also looking).
*/
register int val;
register p_entry p;
t_gram r;
register int i;
int type1;
g_init(&r);
g_setcont(&r,UNDEFINED);
r.g_lineno = linecount;
i = hash(str);
/*
* Walk hash chain
*/
for (p = h_root[i]; p != (p_entry) 0; p = p->h_next) {
if(!strcmp(p->h_name,str)) {
val = p - h_entry;
if (type == LITERAL &&
(val >= NTERMINALS || p->h_num >= 0400)) continue;
if (val>=NTERMINALS) {
/* Should be a nonterminal */
if (type == TERMINAL) {
error(linecount,
"%s : terminal expected",
str);
}
g_settype(&r,NONTERM);
g_setnont(&r,val - NTERMINALS);
} else {
if (type != LITERAL && p->h_num < 0400) {
type1 = g_gettype(&(p->h_type));
if (type1 != type) {
if (type1 == LITERAL || type == LITERAL) {
continue;
}
if (type == NONTERM) {
if (type != UNKNOWN) {
error(linecount,
"%s : nonterminal expected",
"%s : illegal type",
str);
continue;
}
g_setnont(&r, val);
g_settype(&r, TERMINAL);
}
if (option==ENTERING) {
error(linecount,
"%s : already defined",str);
}
return r;
p->h_type.g_lineno = linecount;
return &(p->h_type);
}
}
if (option == JUSTLOOKING) return r;
if (type == TERMINAL || type == LITERAL) {
if (nterminals == NTERMINALS) {
fatal(linecount,"too many terminals");
}
p = &h_entry[nterminals];
} else {
/*
* type == NONTERM || type == UNKNOWN
* UNKNOWN and not yet declared means : NONTERM
*/
if (nnonterms == NNONTERMS) {
fatal(linecount,"too many nonterminals");
}
p = &h_entry[NTERMINALS+nnonterms];
}
p->h_name = store(str);
p->h_next = h_root[i];
p = newentry(store(str), h_root[i]);
h_root[i] = p;
if (type == NONTERM || type == UNKNOWN) {
if (type == TERMINAL || type == LITERAL) {
register p_token pt;
pt = (p_token) new_mem(&token_info);
tokens = (p_token) token_info.i_ptr;
pt->t_string = p->h_name;
if (type == LITERAL) {
if (str[0] == '\\') {
/*
* Handle escapes in literals
*/
if (str[2] == '\0') {
switch(str[1]) {
case 'n' :
val = '\n';
break;
case 'r' :
val = '\r';
break;
case 'b' :
val = '\b';
break;
case 'f' :
val = '\f';
break;
case 't' :
val = '\t';
break;
case '\'':
val = '\'';
break;
case '\\':
val = '\\';
break;
default :
error(linecount,e_literal);
}
} else {
/*
* Here, str[2] != '\0'
*/
if (str[1] > '3' || str[1] < '0' ||
str[2] > '7' || str[2] < '0' ||
str[3] > '7' || str[3] < '0' ||
str[4] != '\0') error(linecount,e_literal);
val = 64*str[1] - 73*'0' +
8*str[2] + str[3];
}
} else {
/*
* No escape in literal
*/
if (str[1] == '\0') val = str[0];
else error(linecount,e_literal);
}
pt->t_tokno = val;
g_settype(&(p->h_type), LITERAL);
} else {
/*
* Here, type = TERMINAL
*/
pt->t_tokno = assval++;
g_settype(&(p->h_type), TERMINAL);
}
g_setcont(&(p->h_type), ntokens);
ntokens++;
return &(p->h_type);
}
/*
* type == NONTERM || type == UNKNOWN
* UNKNOWN and not yet declared means : NONTERM
*/
{
register p_nont q;
q = &nonterms[nnonterms];
q = (p_nont) new_mem(&nont_info);
nonterms = (p_nont) nont_info.i_ptr;
q->n_name = p->h_name;
q->n_rule = 0;
q->n_lineno = linecount;
q->n_string = f_input;
q->n_follow = 0;
q->n_flags = 0;
q->n_contains = 0;
p->h_num = 0;
g_settype(&r, NONTERM);
g_setnont(&r, nnonterms);
g_settype(&(p->h_type), NONTERM);
g_setcont(&(p->h_type), nnonterms);
nnonterms++;
return r;
return &(p->h_type);
}
if (type == LITERAL) {
if (str[0] == '\\') {
/*
* Handle escapes in literals
*/
if (str[2] == '\0') {
switch(str[1]) {
case 'n' :
val = '\n';
break;
case 'r' :
val = '\r';
break;
case 'b' :
val = '\b';
break;
case 'f' :
val = '\f';
break;
case 't' :
val = '\t';
break;
case '\'':
val = '\'';
break;
case '\\':
val = '\\';
break;
default :
error(linecount,e_literal);
}
} else {
/*
* Here, str[2] != '\0'
*/
if (str[1] > '3' || str[1] < '0' ||
str[2] > '7' || str[2] < '0' ||
str[3] > '7' || str[3] < '0' ||
str[4] != '\0') error(linecount,e_literal);
val = 64*str[1] - 73*'0' + 8*str[2] + str[3];
}
} else {
/*
* No escape in literal
*/
if (str[1] == '\0') val = str[0];
else error(linecount,e_literal);
}
p->h_num = val;
} else {
/*
* Here, type = TERMINAL
*/
p->h_num = assval++;
}
g_settype(&r, TERMINAL);
g_setnont(&r, nterminals);
nterminals++;
return r;
}

View file

@ -29,7 +29,6 @@
* are all defined.
*/
# include "tunable.h"
# include "types.h"
# include "extern.h"
# include "io.h"
@ -51,15 +50,15 @@ co_reach() {
*/
register p_nont p;
register p_start st;
register p_file x = files;
register int *s;
register p_file x;
register p_order s;
/* Check for undefined nonterminals */
for (p = nonterms; p < maxnt; p++) {
if (! p->n_rule) {
if (! p->n_rule) { /* undefined */
f_input = p->n_string;
error(p->n_lineno,"nonterminal %s not defined",
(min_nt_ent + (p - nonterms))->h_name);
p->n_name);
}
}
/*
@ -67,17 +66,19 @@ co_reach() {
* Mark the nonterminals that are encountered with the flag
* REACHABLE, and walk their rules, if not done before
*/
for (st = start; st; st = st->ff_next) reachable(st->ff_nont);
for (st = start; st; st = st->ff_next) {
reachable(&nonterms[st->ff_nont]);
}
/*
* Now check for unreachable nonterminals
*/
for (; x->f_end < maxorder; x++) {
for (x = files; x < maxfiles; x++) {
f_input = x->f_name;
for (s = x->f_start; s <= x->f_end; s++) {
p = &nonterms[*s];
for (s = x->f_list; s; s = s->o_next) {
p = &nonterms[s->o_index];
if (! (p->n_flags & REACHABLE)) {
error(p->n_lineno,"nonterminal %s unreachable",
(min_nt_ent + (p - nonterms))->h_name);
p->n_name);
}
}
}
@ -107,10 +108,10 @@ reachwalk(p) register p_gram p; {
for (;;) {
switch(g_gettype(p)) {
case ALTERNATION :
reachwalk(((p_link) pentry[g_getcont(p)])->l_rule);
reachwalk(links[g_getcont(p)].l_rule);
break;
case TERM :
reachwalk(((p_term) pentry[g_getcont(p)])->t_rule);
reachwalk(terms[g_getcont(p)].t_rule);
break;
case NONTERM :
reachable(&nonterms[g_getnont(p)]);

View file

@ -25,8 +25,7 @@
/*
* sets.c
* Some general setmanipulation routines are defined,
* and also two set allocating routines are defined
* Set manipulation and allocation routines.
*/
# include "types.h"
@ -41,6 +40,7 @@ static string rcsid9 = "$Header$";
/* In this file the following routines are defined: */
extern setinit();
extern p_set setalloc();
extern p_set get_set();
extern int setunion();
extern int setintersect();
extern setminus();
@ -48,11 +48,12 @@ extern int setempty();
extern int findindex();
extern int setcount();
int tbitset;
int setsize,tsetsize;
p_set *setptr, *maxptr, *topptr;
static unsigned size,nbytes;
int nbytes;
static int setsize;
int tsetsize;
p_set *setptr, *maxptr;
static t_info set_info;
p_mem alloc();
setinit(ntneeded) {
/*
@ -60,84 +61,99 @@ setinit(ntneeded) {
*/
register int bitset;
nbytes = NBYTES(nterminals);
tbitset = ALIGN(nbytes);
tsetsize = NINTS(tbitset);
bitset = tbitset;
nbytes = NBYTES(ntokens);
bitset = ALIGN(nbytes);
tsetsize = NINTS(bitset);
if (ntneeded) {
/* nonterminals must be included in the sets */
bitset += NBYTES(nnonterms);
}
setsize = NINTS(bitset);
tbitset *= 8;
set_info.i_esize = sizeof(p_set);
set_info.i_incr = 20;
}
p_set
setalloc(size) int size; {
get_set() {
/*
* Allocate a set of size "size" ints
* Allocate a set that cannot be freed
*/
register p_set t;
register int i;
p_mem alloc();
register p_set p, q;
static p_set sets, maxsets;
assert(size == tsetsize || size == setsize);
t = (p_set) alloc((unsigned) (size * sizeof(int)));
i = size;
t += i;
for (; i; i--) {
*--t = 0;
if ((p = sets) >= maxsets) {
q = p = (p_set) alloc((unsigned) (50*setsize*sizeof(*sets)));
maxsets = p + 50 * setsize;
do {
*q++ = 0;
} while (q < maxsets);
}
return t;
sets = p + setsize;;
return p;
}
p_set
setalloc() {
/*
* Allocate a set which can later be freed.
*/
register p_set p;
register int size = setsize;
p = (p_set) alloc((unsigned) (size * sizeof(*p))) + size;
do {
*--p = 0;
} while (--size);
return p;
}
int
setunion(a,b,size) register p_set a,b; int size; {
setunion(a,b) register p_set a,b; {
/*
* a = a union b.
* Return 1 if the set a changed
*/
register i;
register j;
int nsub = 0;
register int i;
register int j;
register int nsub = 0;
assert(size == tsetsize || size == setsize);
for (i = size; i; i--) {
i = setsize;
do {
*a = (j = *a) | *b++;
if (*a++ != j) {
nsub = 1;
}
}
} while (--i);
return nsub;
}
int
setintersect(a,b,size) register p_set a,b; int size; {
setintersect(a,b) register p_set a,b; {
/*
* a = a intersect b.
* return 1 if the resut is empty
* return 1 if the result is empty
*/
register i;
register nempty;
register int i;
register int nempty;
assert(size == tsetsize || size == setsize);
nempty = 1;
for (i = size; i; i--) {
i = setsize;
do {
if (*a++ &= *b++) nempty = 0;
}
} while (--i);
return nempty;
}
setminus(a,b,size) register p_set a,b; int size; {
setminus(a,b) register p_set a,b; {
/*
* a = a setminus b
*/
register i;
register int i;
assert(size == tsetsize || size == setsize);
for (i = size; i; i--) {
i = setsize;
do {
*a++ &= ~(*b++);
}
} while (--i);
}
int
@ -145,26 +161,28 @@ setempty(p) register p_set p; {
/*
* Return 1 if the set p is empty
*/
register i;
register int i;
for (i = tsetsize; i; i--) {
i = tsetsize;
do {
if (*p++) return 0;
}
} while (--i);
return 1;
}
int
findindex(set) p_set *set; {
findindex(set) p_set set; {
/*
* The set "set" will serve as a recovery set.
* Search for it in the table. If not present, enter it
* Search for it in the table. If not present, enter it.
* Here is room for improvement. At the moment, the list of
* sets is examined with linear search.
*/
register p_set *t;
p_mem alloc(),ralloc();
p_mem new_mem();
register p_set a;
register p_set b;
register i;
register j;
register int i;
int saved;
/*
@ -172,10 +190,11 @@ findindex(set) p_set *set; {
*/
for (t = setptr; t < maxptr; t++) {
a = *t;
b = *set;
for (i = tsetsize; i; i--) {
b = set;
i = tsetsize;
do {
if (*a++ != *b++) break;
}
} while (--i);
if (i) continue;
/*
* Here, the sets are equal.
@ -186,28 +205,14 @@ findindex(set) p_set *set; {
* Now check if the set consists of only one element.
* It would be a waste to use a set for that
*/
if (setcount(*set, &saved) == 1) return -h_entry[saved].h_num;
if (setcount(set, &saved) == 1) return -(saved + 1);
/*
* If it does, return its number as a negative number.
*/
if (maxptr >= topptr) {
/*
* Need new space for the list, in chunks of 50 pointers
*/
if (setptr == 0) {
setptr = (p_set *) alloc(50 * sizeof(p_set));
size = 50;
maxptr = setptr;
} else {
setptr = (p_set *) ralloc((p_mem) setptr,
(50+size)*sizeof(p_set));
maxptr = &setptr[size-1];
size += 50;
}
topptr = &setptr[size-1];
}
*maxptr = setalloc(tsetsize);
setunion(*maxptr, *set, tsetsize);
maxptr = (p_set *) new_mem(&set_info);
setptr = (p_set *) set_info.i_ptr;
*maxptr = setalloc();
setunion(*maxptr, set);
return nbytes * (maxptr++ - setptr);
}
@ -215,7 +220,7 @@ int
setcount(set, saved) register p_set set; int *saved; {
register int i, j;
for (j = 0, i = 0; i < nterminals; i++) {
for (j = 0, i = 0; i < ntokens; i++) {
if (IN(set,i)) {
j++;
*saved = i;

View file

@ -30,9 +30,9 @@
# define BITS (8 * sizeof (int))
# define IN(a,i) ((a)[(i)/BITS] & (1<<((i) % BITS)))
# define NTIN(a,i) ((a)[((i)+tbitset)/BITS]&(1<<((i)%BITS)))
# define NTIN(a,i) ((a)[(i)/BITS+tsetsize]&(1<<((i)%BITS)))
# define PUTIN(a,i) ((a)[(i)/BITS] |=(1<<((i) % BITS)))
# define NTPUTIN(a,i) ((a)[((i)+tbitset)/BITS]|=(1<<((i)%BITS)))
# define NTPUTIN(a,i) ((a)[(i)/BITS+tsetsize]|=(1<<((i)%BITS)))
# define NBYTES(n) (((n) + 7) / 8)
/*
* The next two macros operate on byte counts!
@ -40,6 +40,6 @@
# define NINTS(n) (((n) + (int) (sizeof(int) - 1)) / (int) sizeof(int))
# define ALIGN(n) (NINTS(n) * (int) sizeof (int))
extern int tbitset;
extern p_set *setptr,*maxptr,*topptr;
extern int tsetsize,setsize;
extern int tsetsize;
extern p_set *setptr, *maxptr;
extern int nbytes;

View file

@ -26,15 +26,15 @@
/*
* tokens.g
* Defines the tokens for the grammar of LLgen.
* The lexical analyser and LLmes are also included here.
* The lexical analyser and LLmessage are also included here.
*/
{
# include "types.h"
# include "io.h"
# include "tunable.h"
# include "extern.h"
# include "assert.h"
# include "cclass.h"
# ifndef NORCSID
static string rcsidc = "$Header$";
@ -46,11 +46,12 @@ extern LLmessage();
extern int input();
extern unput();
extern skipcomment();
# ifdef LINE_DIRECTIVE
STATIC linedirective();
# endif
STATIC string cpy();
STATIC string vallookup();
}
/* Classes */
%token C_IDENT ; /* lextoken.t_string contains the identifier read */
@ -78,17 +79,17 @@ STATIC string vallookup();
* Structure for a keyword
*/
struct keyword {
typedef struct keyword {
string w_word;
int w_value;
};
} t_keyw, *p_keyw;
/*
* The list of keywords, the most often used keywords come first.
* Linear search is used, as there are not many keywords
*/
static struct keyword resword[] = {
static t_keyw resword[] = {
{ "token", C_TOKEN },
{ "avoid", C_AVOID },
{ "prefer", C_PREFER },
@ -103,108 +104,105 @@ static struct keyword resword[] = {
};
static t_token savedtok; /* to save lextoken in case of an insertion */
# ifdef LINE_DIRECTIVE
static int nostartline; /* = 0 if at the start of a line */
# endif
scanner() {
/*
* Lexical analyser, what else
*/
register ch; /* Current char */
register i;
register reserved = 0; /* reserved word? */
register int ch; /* Current char */
register char *p = ltext;
int reserved = 0; /* reserved word? */
int last; /* Char before current char */
char *max = &ltext[LTEXTSZ - 1];
if (savedtok.t_tokno) { /*
* A token has been inserted.
if (ch = savedtok.t_tokno) {
/* A token has been inserted.
* Now deliver the last lextoken again
*/
lextoken = savedtok;
savedtok.t_tokno = 0;
return lextoken.t_tokno;
return ch;
}
for (;;) { /*
* First, skip space, comments, line directives, etc
*/
do ch = input();
while(isspace(ch));
if (ch == '/') skipcomment(0);
else if (ch == '#' && !nostartline) linedirective();
else break;
}
/*
* Now we have a first character of a token
*/
switch(ch) {
case EOF :
return EOF;
case '\'': /*
* Literal, put it in ltext
*/
i = 0;
for (;;) {
last = ch;
ch = input();
if (ch == '\n' || ch == EOF) {
error(linecount,"missing '");
break;
}
if (ch == '\'' && last != '\\') break;
ltext[i] = ch;
if (i < LTEXTSZ - 1) ++i;
}
ltext[i] = '\0';
lextoken.t_string = ltext;
return C_LITERAL;
case '%' : /*
* Start of a reserved word
*/
reserved = 1;
for (;;) {
ch = input();
/* Fall through */
default :
i = 0;
if (isdigit(ch)) {
if (reserved) {
error(linecount," A reserved number ?");
if (ch == EOF) return ch;
# ifdef LINE_DIRECTIVE
if (ch == '#' && !nostartline) {
linedirective();
continue;
}
# endif
switch(c_class[ch]) {
case ISLIT :
for (;;) {
last = ch;
ch = input();
if (ch == '\n' || ch == EOF) {
error(linecount,"missing '");
break;
}
if (ch == '\'' && last != '\\') break;
*p++ = ch;
if (p > max) p--;
}
while (isdigit(ch)) {
*p = '\0';
lextoken.t_string = ltext;
return C_LITERAL;
case ISCOM :
skipcomment(0);
/* Fall through */
case ISSPA :
continue;
case ISDIG : {
register i = 0;
do {
i = 10 * i + (ch - '0');
ch= input();
}
} while (c_class[ch] == ISDIG);
lextoken.t_num = i;
unput(ch);
return C_NUMBER;
}
if (isalpha(ch) || ch == '_') {
return C_NUMBER; }
default:
return ch;
case ISKEY :
reserved = 1;
ch = input();
/* Fall through */
case ISLET :
do {
if (reserved && isupper(ch)) ch += 'a' - 'A';
ltext[i] = ch;
if (i < LTEXTSZ - 1) ++i;
if (reserved && ch >= 'A' && ch <= 'Z') {
ch += 'a' - 'A';
}
*p++ = ch;
if (p > max) p--;
ch = input();
} while (isalnum(ch) || ch == '_');
} else return ch;
unput(ch);
}
ltext[i] = '\0';
if (reserved) { /*
* Now search for the keyword
*/
register struct keyword *w;
} while (c_class[ch] == ISDIG || c_class[ch] == ISLET);
unput(ch);
*p = '\0';
if (reserved) { /*
* Now search for the keyword
*/
register p_keyw w;
w = resword;
while (w->w_word) {
if (! strcmp(ltext,w->w_word)) {
/*
* Found it. Return token number.
*/
return w->w_value;
w = resword;
while (w->w_word) {
if (! strcmp(ltext,w->w_word)) {
/*
* Return token number.
*/
return w->w_value;
}
w++;
}
error(linecount,"illegal reserved word");
}
w++;
lextoken.t_string = ltext;
return C_IDENT;
}
error(linecount,"illegal reserved word");
}
lextoken.t_string = ltext;
return C_IDENT;
}
static int backupc; /* for unput() */
@ -215,21 +213,22 @@ input() {
* Low level input routine, used by all other input routines
*/
register c;
register FILE *f;
if(backupc) { /*
* Last char was "unput()". Deliver it again
if (c = backupc) {
/* Last char was "unput()". Deliver it again
*/
c = backupc;
backupc = 0;
return c;
}
f = finput;
if ((c = getc(f)) == EOF) return c;
if ((c = getc(finput)) == EOF) return c;
# ifdef LINE_DIRECTIVE
nostartline = 1;
# endif
if (!nonline) {
linecount++;
# ifdef LINE_DIRECTIVE
nostartline = 0;
# endif
nonline = 1;
}
if (c == '\n') nonline = 0;
@ -249,30 +248,29 @@ skipcomment(flag) {
* of C-code, so the newlines in it must be copied to enable the
* C-compiler to keep a correct line count
*/
register ch;
register int ch;
int saved; /* line count on which comment starts */
saved = linecount;
if (input() != '*') error(linecount,"illegal comment");
ch = input();
while (ch != EOF) {
if (flag && ch == '\n') putc(ch,fact);
do {
ch = input();
while (ch == '*') {
if ((ch = input()) == '/') return;
if (flag && ch == '\n') putc(ch,fact);
}
ch = input();
}
if (flag && ch == '\n') putc(ch,fact);
} while (ch != EOF);
error(saved,"Comment does not terminate");
}
# ifdef LINE_DIRECTIVE
STATIC
linedirective() {
/*
* Read a line directive
*/
register ch;
register i;
register int ch;
register int i;
string s_error = "Illegal line directive";
string store();
register string c;
@ -282,17 +280,16 @@ linedirective() {
* Do not skip newlines
*/
ch = input();
} while (ch != '\n' && ! isdigit(ch));
} while (ch != '\n' && c_class[ch] != ISDIG);
if (ch == '\n') {
error(linecount,s_error);
return;
}
i = ch - '0';
ch = input();
while (isdigit(ch)) {
i = 0;
do {
i = i*10 + (ch - '0');
ch = input();
}
} while (c_class[ch] == ISDIG);
while (ch != '\n' && ch != '"') ch = input();
if (ch == '"') {
c = ltext;
@ -314,13 +311,14 @@ linedirective() {
}
linecount = i;
}
# endif
STATIC string
vallookup(s) {
/*
* Look up the keyword that has token number s
*/
register struct keyword *p = resword;
register p_keyw p = resword;
while (p->w_value) {
if (p->w_value == s) return p->w_word;
@ -330,25 +328,24 @@ vallookup(s) {
}
STATIC string
cpy(s,p,flag) register s; register string p; {
cpy(s,p,inserted) register string p; {
/*
* Create a piece of error message for token s and put it at p.
* flag = 0 if the token s was deleted (in which case we have
* inserted = 0 if the token s was deleted (in which case we have
* attributes), else it was inserted
*/
register string t = 0;
switch(s) {
case C_IDENT :
if (!flag) t = lextoken.t_string;
if (!inserted) t = lextoken.t_string;
else t = "identifier";
break;
case C_NUMBER :
t = "number";
break;
case C_LITERAL :
if (!flag) {
*p++ = '"';
if (!inserted) {
*p++ = '\'';
t = lextoken.t_string;
break;
@ -359,19 +356,15 @@ cpy(s,p,flag) register s; register string p; {
t = "endoffile";
break;
}
if (!t) {
t = vallookup(s);
if (t) {
*p++ = '%';
}
if (!t && (t = vallookup(s))) {
*p++ = '%';
}
if (t) { /*
* We have a string for the token. Copy it
*/
while (*t) *p++ = *t++;
if (s == C_LITERAL && !flag) {
if (s == C_LITERAL && !inserted) {
*p++ = '\'';
*p++ = '"';
}
return p;
}
@ -380,14 +373,17 @@ cpy(s,p,flag) register s; register string p; {
*/
*p++ = '\'';
if (s >= 040 && s <= 0176) *p++ = s;
else switch(s) {
case '\b' : *p++ = '\\'; *p++ = 'b'; break;
case '\f' : *p++ = '\\'; *p++ = 'f'; break;
case '\n' : *p++ = '\\'; *p++ = 'n'; break;
case '\r' : *p++ = '\\'; *p++ = 'r'; break;
case '\t' : *p++ = '\\'; *p++ = 't'; break;
default : *p++='0'+((s&0377)>>6); *p++='0'+((s>>3)&07);
*p++='0'+(s&07);
else {
*p++ = '\\';
switch(s) {
case '\b' : *p++ = 'b'; break;
case '\f' : *p++ = 'f'; break;
case '\n' : *p++ = 'n'; break;
case '\r' : *p++ = 'r'; break;
case '\t' : *p++ = 't'; break;
default : *p++='0'+((s&0377)>>6); *p++='0'+((s>>3)&07);
*p++='0'+(s&07);
}
}
*p++ = '\'';
return p;

View file

@ -43,7 +43,7 @@ typedef struct token {
} t_x;
# define t_string t_x.t_s
# define t_num t_x.t_v
} t_token;
} t_token, *p_token;
/*
* structure for the grammar elements
@ -74,49 +74,49 @@ typedef struct gram {
# define TERMINAL 03 /* A terminal */
# define TERM 04 /* Something between square brackets */
# define ALTERNATION 05 /* Alternation (|) */
# define LITERAL 06 /* Also a terminal */
/*
* Access macros for the x-field of a grammar element
*/
# define g_init(p) {(p)->x = 0;}
# define g_gettype(p) (((p)->x>>13)&07)
# define g_getcont(p) ((p)->x&017777)
# define g_getnont(p) ((p)->x&0777)
# define g_getnpar(p) (((p)->x>>9)&07)
# define g_getnpar(p) (((p)->x>>9)&017)
# define g_settype(p,s) { assert(((unsigned)(s))<=07);(p)->x=((p)->x&017777)|((s)<<13);}
# define g_setcont(p,s) { assert(((unsigned)(s))<=017777);(p)->x=((p)->x&0160000)|(s);}
# define g_setnont(p,s) { assert(((unsigned)(s))<=0777);(p)->x=((p)->x&0177000)|(s);}
# define g_setnpar(p,s) { assert(((unsigned)(s))<=07);(p)->x=((p)->x&0170777)|((s)<<9);}
# define g_setnpar(p,s) { assert(((unsigned)(s))<=017);(p)->x=((p)->x&0160777)|((s)<<9);}
/*
* Some constants to communicate with the symbol table search routine
*/
# define LITERAL 01 /* Not equal to NONTERM or TERMINAL */
# define UNKNOWN 00 /* Not equal to NONTERM, TERMINAL or LITERAL */
/*
* Some constants for safety
*/
# define SAFE 0
# define SAFESCANDONE 1
# define SCANDONE 2
# define NOSCANDONE 3
# define NOSAFETY 4
# define SAFE 0 /* Indicates that a scan is done, and that the
* token is correct
*/
# define SAFESCANDONE 1 /* Indicates that a scan is done, and that the
* token will not be skipped
*/
# define SCANDONE 2 /* Indicates that a scan is done */
# define NOSCANDONE 3 /* Indicates that no scan is done */
# define NOSAFETY 4 /* Safety not yet computed */
/*
* nonterminal structure
*/
typedef struct {
short n_flags; /* low order three bits are reserved
short n_flags; /* low order four bits are reserved
* the parameter count
*/
# define getntparams(p) ((p)->n_flags&07)
# define setntparams(p,i) {assert(((unsigned)(i))<=7);(p)->n_flags&=~07;(p)->n_flags|=(i);}
# define RECURSIVE 00100 /* Set if the default rule is recursive */
# define CONTIN 00400 /* continuation already computed? */
# define BUSY 01000 /* or are we busy computing it? */
# define PARAMS 02000 /* tells if a nonterminal has parameters */
# define PRODUCE 04000 /* tells if a nonterminal produces anything */
# define getntparams(p) ((p)->n_flags&017)
# define setntparams(p,i) {assert(((unsigned)(i))<=017);(p)->n_flags&=~017;(p)->n_flags|=(i);}
# 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 */
# define LOCALS 020000 /* local declarations ? */
# define REACHABLE 040000 /* can this nonterminal be reached ? */
@ -141,6 +141,7 @@ typedef struct {
# define n_string n_x.n_s
p_set n_follow; /* pointer to the "follow" set */
p_set n_contains; /* pointer to symbols that can be produced */
string n_name; /* name of nonterminal */
} t_nont, *p_nont;
/*
@ -148,7 +149,7 @@ typedef struct {
*/
typedef struct h_entry {
string h_name; /* pointer to name */
int h_num; /* numbering of terminals */
t_gram h_type; /* Type and index */
struct h_entry *h_next; /* next in hash chain */
} t_entry, *p_entry;
@ -180,20 +181,19 @@ typedef short t_reps,*p_reps;
# define OPT 03 /* 0 or 1 times */
/*
* Access macros for repitition
* Access macros for repitition in term
*/
# define r_init(p) {*(p)=0;}
# define r_getkind(p) (*(p)&03)
# define r_getnum(p) ((*(p)>>2)&037777)
# define r_setkind(p,s) { assert(((unsigned)(s))<=03);*(p)=(*(p)&0177774)|(s);}
# define r_setnum(p,s) { assert(((unsigned)(s))<=037777);*(p)=(*(p)&03)|((s)<<2);}
# define r_getkind(q) ((q)->t_reps&03)
# define r_getnum(q) (((q)->t_reps>>2)&037777)
# define r_setkind(q,s) { assert(((unsigned)(s))<=03);(q)->t_reps=((q)->t_reps&0177774)|(s);}
# define r_setnum(q,s) { assert(((unsigned)(s))<=037777);(q)->t_reps=((q)->t_reps&03)|((s)<<2);}
/*
* header structure for a term
*/
typedef struct term {
t_reps t_reps; /* repeats ? */
short t_flags;
short t_flags; /* Low order three bits for safety */
# define gettout(q) ((q)->t_flags&07)
# define settout(q,i) {assert(((unsigned)(i))<=NOSAFETY);(q)->t_flags&=~07;(q)->t_flags|=i;}
# define PERSISTENT 010 /* Set if this term has %persistent */
@ -205,7 +205,7 @@ typedef struct term {
p_gram t_rule; /* pointer to this term */
p_set t_follow; /* set of followers */
p_set t_first; /* set of firsts */
p_set t_contains;
p_set t_contains; /* contains set */
} t_term, *p_term;
/*
@ -213,7 +213,7 @@ typedef struct term {
*/
typedef struct ff_firsts {
string ff_name; /* Name of the macro */
p_nont ff_nont; /* for this nonterminal */
int ff_nont; /* for this nonterminal */
struct ff_firsts *ff_next;
} t_first, *p_first;
@ -223,6 +223,11 @@ typedef struct ff_firsts {
typedef t_first t_start;
typedef p_first p_start;
typedef struct order {
int o_index; /* index in nonterminal array */
struct order *o_next;
} t_order, *p_order;
/*
* structure for file names and info
*/
@ -232,11 +237,21 @@ typedef struct f_file {
* generated in the target file for this
* grammar file
*/
short *f_start,*f_end;/* pointers in the "order" array,
* Indicating which nonterminals were defined
* in this file
*/
struct order *f_list; /* list of nonterminals in this file */
} t_file, *p_file;
typedef struct info_alloc {
/*
* Structure used for dynamically growing arrays
*/
unsigned i_size; /* Size of the array */
unsigned i_esize; /* Size of an element */
unsigned i_incr; /* When filled, add room for i_incr elements */
p_mem i_ptr; /* ptr to base of array */
p_mem i_max; /* ptr to first free */
p_mem i_top; /* ptr to top of array */
} t_info, *p_info;
# ifdef NDEBUG
# define STATIC static
# else not NDEBUG