Added non-correcting error recovery stuff
This commit is contained in:
parent
a44875cf00
commit
c2607fdf0f
|
@ -21,6 +21,10 @@ extern unsigned int LLscnt[];
|
|||
extern unsigned int LLtcnt[];
|
||||
extern int LLcsymb;
|
||||
|
||||
#if LL_NON_CORR
|
||||
extern int LLstartsymb;
|
||||
#endif
|
||||
|
||||
#define LLsdecr(d) {LL_assert(LLscnt[d] > 0); LLscnt[d]--;}
|
||||
#define LLtdecr(d) {LL_assert(LLtcnt[d] > 0); LLtcnt[d]--;}
|
||||
#define LLsincr(d) LLscnt[d]++
|
||||
|
|
70
util/LLgen/lib/nc_incl
Normal file
70
util/LLgen/lib/nc_incl
Normal file
|
@ -0,0 +1,70 @@
|
|||
#define LLALT 9999 /* Alternative is following */
|
||||
|
||||
#define LLTERMINAL 1 /* Symbol is a terminal */
|
||||
#define LLNONTERMINAL 2 /* Symbol is a nonterminal */
|
||||
#define LLEORULE 0 /* No more alternatives */
|
||||
|
||||
|
||||
struct lhs { /* LHS of a rule */
|
||||
int nr; /* Nr of the nonterminal */
|
||||
struct symbol *rhs; /* Pointer to RHS */
|
||||
char first[LLSETSIZE]; /* First set */
|
||||
char follow[LLSETSIZE]; /* Follow set */
|
||||
char empty; /* Set if nonterminal produces empty */
|
||||
};
|
||||
|
||||
struct symbol { /* Symbol in the RHS of a rule */
|
||||
int x; /* LLTERMINAL or LLNONTERMINAL */
|
||||
int nr; /* Nr of the symbol */
|
||||
struct symbol *link; /* Ptr to next rule with this symbol */
|
||||
struct symbol *next; /* Ptr to next symbol in this rule */
|
||||
struct lhs *lhs; /* Ptr to LHS */
|
||||
};
|
||||
|
||||
struct terminal { /* Array with links to terminals in a */
|
||||
struct symbol *link; /* rule */
|
||||
};
|
||||
|
||||
struct nonterminal { /* Array with links to nt's in a rule */
|
||||
struct symbol *link; /* and pointer to LHS's */
|
||||
struct lhs *rule;
|
||||
};
|
||||
|
||||
struct stack_elt { /* Stack element */
|
||||
int flags; /* Some flags */
|
||||
int nr; /* Nr of symbol */
|
||||
int ref_count; /* Nr of predecessors */
|
||||
int hyp_ref_count; /* Temporary nr of predecessors */
|
||||
int matched; /* Nr of LHS trying to match */
|
||||
int nr_nexts; /* Nr of successors */
|
||||
struct edge *edges; /* Array of edges to other stack elt's*/
|
||||
};
|
||||
|
||||
/* Possible flags in a stack element */
|
||||
#define LLHEAD 1 /* Stack element is a head */
|
||||
#define LLDUMMY 2 /* Stack element is substituted */
|
||||
#define LLGEN_SEARCH 8 /* Set by 'generate_heads()' */
|
||||
|
||||
|
||||
struct edge { /* Edges of a stack element */
|
||||
char flags; /* Some flags */
|
||||
struct stack_elt *ptr; /* Array with pointers to stack elt's */
|
||||
};
|
||||
|
||||
/* Possible flags in an edge */
|
||||
#define LLLOOP 1 /* Belongs to a loop */
|
||||
#define LLLOOP_SEARCH 2 /* Used by 'loop()' */
|
||||
#define LLHYP_SEARCH 4 /* Used by 'hyp_run()' */
|
||||
#define PRINT_SEARCH 8 /* DEBUG */
|
||||
#define LLMARK_SEARCH 16 /* Used by 'mark_loop()' */
|
||||
#define LLYES 32
|
||||
#define LLNO 64
|
||||
|
||||
#define LLEOSTACK -1 /* Indicates last element of a stack */
|
||||
#define LLHEADS_BUF_INCR 10 /* Nr of elements the buffer will be */
|
||||
#define LLCLEANUP_BUF_INCR 25 /* increased by */
|
||||
#define LL_VIS_INCR 200
|
||||
|
||||
/* Macro's to manipulate bit sets */
|
||||
#define LLIN(a, i) ((a)[(i)/8] & (1 << ((i) % 8)))
|
||||
#define LLPUTIN(a, i) ((a)[(i)/8] |= (1 << ((i) % 8)))
|
1791
util/LLgen/lib/nc_rec
Normal file
1791
util/LLgen/lib/nc_rec
Normal file
File diff suppressed because it is too large
Load diff
|
@ -12,6 +12,11 @@ unsigned int LLscnt[LL_NSETS];
|
|||
int LLcsymb, LLsymb;
|
||||
static int LLlevel;
|
||||
|
||||
#if LL_NON_CORR
|
||||
int LLstartsymb;
|
||||
static int fake_eof = 0;
|
||||
#endif
|
||||
|
||||
#if LL_ANSI_C
|
||||
#define LL_VOIDCST (void)
|
||||
void LLmessage(int);
|
||||
|
@ -39,7 +44,38 @@ LLscan(t)
|
|||
/*
|
||||
* Check if the next symbol is equal to the parameter
|
||||
*/
|
||||
|
||||
#if LL_NON_CORR
|
||||
/* See if the error recovery has eaten an eof */
|
||||
if (fake_eof) {
|
||||
LLsymb = EOFILE;
|
||||
fake_eof = 0;
|
||||
}
|
||||
else {
|
||||
LLsymb = LL_LEXI();
|
||||
}
|
||||
|
||||
if (LLsymb == t) {
|
||||
#else
|
||||
if ((LLsymb = LL_LEXI()) == t) {
|
||||
#endif
|
||||
|
||||
#if LL_NON_CORR
|
||||
/* Check if a previous parser has 'crashed', in that
|
||||
* case continue with non-correcting parser
|
||||
*/
|
||||
if (err_seen && !nc_done) {
|
||||
LLnc_recover();
|
||||
nc_done = 1;
|
||||
/* Remember that the error recovery has eaten an eof */
|
||||
fake_eof = 1;
|
||||
if (t != LLsymb) {
|
||||
LLerror(t);
|
||||
}
|
||||
else
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
/*
|
||||
|
@ -54,6 +90,31 @@ void LLread(void) {
|
|||
#else
|
||||
LLread() {
|
||||
#endif
|
||||
|
||||
#if LL_NON_CORR
|
||||
/* Again, check if another parser has crashed,
|
||||
* in that case intercept and go to the
|
||||
* non-correcting parser
|
||||
*/
|
||||
|
||||
if (err_seen && !nc_done) {
|
||||
LLnc_recover();
|
||||
nc_done = 1;
|
||||
/* Pretend we read end of file */
|
||||
LLsymb = EOFILE;
|
||||
LLcsymb = LLindex[EOFILE];
|
||||
fake_eof = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (fake_eof) {
|
||||
LLsymb = EOFILE;
|
||||
LLcsymb = LLindex[EOFILE];
|
||||
fake_eof = 0;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (;;) {
|
||||
if ((LLcsymb = LLindex[(LLsymb = LL_LEXI())]) >= 0) return;
|
||||
LLmessage(0);
|
||||
|
@ -85,6 +146,16 @@ LLerror(t)
|
|||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LL_NON_CORR
|
||||
if ((!nc_done) && (LLsymb > 0) && (LLsymb != EOFILE)) {
|
||||
LLmessage(0);
|
||||
LLnc_recover();
|
||||
nc_done = 1;
|
||||
LLsymb = EOFILE;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((LLcsymb = LLindex[LLsymb]) < 0) {
|
||||
LLmessage(0);
|
||||
LLread();
|
||||
|
@ -97,7 +168,25 @@ LLerror(t)
|
|||
LL_VOIDCST LLskip();
|
||||
#endif
|
||||
LLtcnt[i]--;
|
||||
if (LLsymb != t) LLmessage(t);
|
||||
if (LLsymb != t) {
|
||||
#if LL_NON_CORR
|
||||
/* A little kludge here; when using non-correcting recovery
|
||||
* it can happen that a program is correct but incomplete.
|
||||
* Here, we test this, and make sure the appropriate
|
||||
* message is generated
|
||||
*/
|
||||
if (! nc_done) {
|
||||
int oldLLsymb;
|
||||
oldLLsymb = LLsymb;
|
||||
LLsymb = EOFILE;
|
||||
LLmessage(0);
|
||||
nc_done = 1;
|
||||
/* Not really, but to prevent more than 1 error message */
|
||||
LLsymb = oldLLsymb;
|
||||
}
|
||||
#endif
|
||||
LLmessage(t);
|
||||
}
|
||||
}
|
||||
|
||||
#if LL_ANSI_C
|
||||
|
@ -121,6 +210,14 @@ LLsafeerror(t)
|
|||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#if LL_NON_CORR
|
||||
if ((!nc_done) && (LLsymb > 0) && (LLsymb != EOFILE)) {
|
||||
LLmessage(0);
|
||||
LLnc_recover();
|
||||
nc_done = 1;
|
||||
LLsymb = EOFILE;
|
||||
}
|
||||
#endif
|
||||
LLmessage(t);
|
||||
}
|
||||
|
@ -265,7 +362,19 @@ static int LLdoskip(e)
|
|||
continue;
|
||||
}
|
||||
#endif /* LL_USERHOOK */
|
||||
#if LL_NON_CORR
|
||||
if ((!nc_done) && (LLsymb > 0)) {
|
||||
LLmessage(0);
|
||||
LLnc_recover();
|
||||
nc_done = 1;
|
||||
fake_eof = 1;
|
||||
}
|
||||
else {
|
||||
LLmessage(0);
|
||||
}
|
||||
#else
|
||||
LLmessage(0);
|
||||
#endif
|
||||
retval = 1;
|
||||
LLread();
|
||||
}
|
||||
|
|
|
@ -32,9 +32,7 @@ string store();
|
|||
p_gram search();
|
||||
long ftell();
|
||||
|
||||
static int nparams; /* parameter count for nonterminals */
|
||||
static int acount; /* count #of global actions */
|
||||
static int order;
|
||||
static p_term t_list;
|
||||
static int t_cnt;
|
||||
static p_gram alt_table;
|
||||
|
@ -48,9 +46,8 @@ static int max_rules;
|
|||
#define RULEINCR 32
|
||||
|
||||
/* Here are defined : */
|
||||
STATIC newnorder();
|
||||
STATIC newtorder();
|
||||
STATIC copyact();
|
||||
STATIC newnorder();
|
||||
STATIC newtorder();
|
||||
STATIC mkalt();
|
||||
STATIC mkterm();
|
||||
STATIC p_gram copyrule();
|
||||
|
@ -169,13 +166,20 @@ def { register string p; }
|
|||
}
|
||||
';'
|
||||
| C_ONERROR C_IDENT
|
||||
{ if (! onerror) {
|
||||
{
|
||||
#ifdef NON_CORRECTING
|
||||
if (non_corr) {
|
||||
warning(linecount, "%%onerror conflicts with -n option");
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (! onerror) {
|
||||
onerror = store(lextoken.t_string);
|
||||
}
|
||||
else error(linecount,"Duplicate %%onerror");
|
||||
}
|
||||
';'
|
||||
| action(0) { acount++; }
|
||||
| C_ACTION { acount++; }
|
||||
/*
|
||||
* A global C-declaration
|
||||
*/
|
||||
|
@ -216,18 +220,20 @@ rule { register p_nont p;
|
|||
p->n_lineno = linecount;
|
||||
p->n_off = ftell(fact);
|
||||
}
|
||||
[ params(1) { if (nparams > 0) {
|
||||
[ C_PARAMS { if (lextoken.t_num > 0) {
|
||||
p->n_flags |= PARAMS;
|
||||
if (nparams > 15) {
|
||||
if (lextoken.t_num > 15) {
|
||||
error(linecount,"Too many parameters");
|
||||
}
|
||||
else setntparams(p,nparams);
|
||||
else setntparams(p,lextoken.t_num);
|
||||
}
|
||||
}
|
||||
]?
|
||||
[ action(0) { p->n_flags |= LOCALS; }
|
||||
[ C_ACTION { p->n_flags |= LOCALS; }
|
||||
]?
|
||||
':' productions(&rr) ';'
|
||||
':' { in_production = 1; }
|
||||
productions(&rr) ';'
|
||||
{ in_production = 0; }
|
||||
/*
|
||||
* Do not use p->n_rule now! The nonterms array
|
||||
* might have been re-allocated.
|
||||
|
@ -235,15 +241,6 @@ rule { register p_nont p;
|
|||
{ nonterms[g_getcont(temp)].n_rule = rr;}
|
||||
;
|
||||
|
||||
action(int n;)
|
||||
/*
|
||||
* The parameter n is non-zero when the opening and closing
|
||||
* bracket must be copied along with the action
|
||||
*/
|
||||
: '{' { copyact('{','}',n,0); }
|
||||
'}'
|
||||
;
|
||||
|
||||
productions(p_gram *p;)
|
||||
/*
|
||||
* One or more alternatives
|
||||
|
@ -280,7 +277,7 @@ productions(p_gram *p;)
|
|||
t = 0;
|
||||
*p = prod;
|
||||
}
|
||||
]+ { if (conflres & ~DEF) {
|
||||
]+ { if (conflres & (COND|PREFERING|AVOIDING)) {
|
||||
error(n_lc,
|
||||
"Resolver on last alternative not allowed");
|
||||
}
|
||||
|
@ -290,7 +287,7 @@ productions(p_gram *p;)
|
|||
*p = copyrule(&alt_table[n_alts-altcnt],altcnt+1);
|
||||
}
|
||||
|
|
||||
{ if (conflres & ~DEF) {
|
||||
{ if (conflres & (COND|PREFERING|AVOIDING)) {
|
||||
error(o_lc,
|
||||
"No alternation conflict resolver allowed here");
|
||||
}
|
||||
|
@ -336,16 +333,32 @@ simpleproduction(p_gram *p; register int *conflres;)
|
|||
int cnt, kind;
|
||||
int termdeleted = 0;
|
||||
} :
|
||||
[ C_DEFAULT { *conflres = DEF; }
|
||||
[ C_DEFAULT { *conflres |= DEF; }
|
||||
]?
|
||||
[
|
||||
/*
|
||||
* Optional conflict reslover
|
||||
*/
|
||||
C_IF expr { *conflres |= COND; }
|
||||
C_IF C_EXPR { *conflres |= COND; }
|
||||
| C_PREFER { *conflres |= PREFERING; }
|
||||
| C_AVOID { *conflres |= AVOIDING; }
|
||||
]?
|
||||
[ C_ILLEGAL {
|
||||
#ifdef NON_CORRECTING
|
||||
if (n_rules >= max_rules-2) {
|
||||
rule_table = (p_gram) ralloc(
|
||||
(p_mem) rule_table,
|
||||
(unsigned)(max_rules+=RULEINCR)*sizeof(t_gram));
|
||||
}
|
||||
elmcnt++;
|
||||
rule_table[n_rules++] =
|
||||
*search(TERMINAL, "LLILLEGAL", BOTH);
|
||||
if (*conflres & DEF) {
|
||||
error(linecount, "%%illegal not allowed in %%default rule");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
]?
|
||||
[ %persistent elem(&elem)
|
||||
{ if (n_rules >= max_rules-2) {
|
||||
rule_table = (p_gram) ralloc(
|
||||
|
@ -467,9 +480,12 @@ elem (register p_gram pres;)
|
|||
p_gram p1;
|
||||
int ln;
|
||||
p_gram pe;
|
||||
#ifdef NON_CORRECTING
|
||||
int erroneous = 0;
|
||||
#endif
|
||||
} :
|
||||
'[' { ln = linecount; }
|
||||
[ C_WHILE expr { t |= RESOLVER; }
|
||||
[ C_WHILE C_EXPR { t |= RESOLVER; }
|
||||
]?
|
||||
[ C_PERSISTENT { t |= PERSISTENT; }
|
||||
]?
|
||||
|
@ -478,12 +494,32 @@ elem (register p_gram pres;)
|
|||
mkterm(p1,t,ln,pres);
|
||||
}
|
||||
|
|
||||
[ C_ERRONEOUS {
|
||||
#ifdef NON_CORRECTING
|
||||
erroneous = 1;
|
||||
#endif
|
||||
}
|
||||
]?
|
||||
|
||||
[
|
||||
C_IDENT { pe = search(UNKNOWN,lextoken.t_string,BOTH);
|
||||
*pres = *pe;
|
||||
#ifdef NON_CORRECTING
|
||||
if (erroneous) {
|
||||
if (g_gettype(pres) != TERMINAL){
|
||||
warning(linecount,
|
||||
"Erroneous only allowed on terminal");
|
||||
erroneous = 0;
|
||||
}
|
||||
else
|
||||
pres->g_erroneous = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
[ params(0) { if (nparams > 15) {
|
||||
[ C_PARAMS { if (lextoken.t_num > 15) {
|
||||
error(linecount,"Too many parameters");
|
||||
} else g_setnpar(pres,nparams);
|
||||
} else g_setnpar(pres,lextoken.t_num);
|
||||
if (g_gettype(pres) == TERMINAL) {
|
||||
error(linecount,
|
||||
"Terminal with parameters");
|
||||
|
@ -492,27 +528,73 @@ elem (register p_gram pres;)
|
|||
]?
|
||||
| C_LITERAL { pe = search(LITERAL,lextoken.t_string,BOTH);
|
||||
*pres = *pe;
|
||||
#ifdef NON_CORRECTING
|
||||
if (erroneous)
|
||||
pres->g_erroneous = 1;
|
||||
#endif
|
||||
}
|
||||
]
|
||||
| { g_settype(pres,ACTION);
|
||||
pres->g_lineno = linecount;
|
||||
#ifdef NON_CORRECTING
|
||||
g_setsubparse(pres, (p_start) 0);
|
||||
#endif
|
||||
}
|
||||
action(1)
|
||||
;
|
||||
|
||||
params(int formal)
|
||||
{
|
||||
long off = ftell(fact);
|
||||
}
|
||||
: '(' { copyact('(', ')', formal ? 2 : 0, 0); }
|
||||
')'
|
||||
{ if (nparams == 0) {
|
||||
fseek(fact, off, 0);
|
||||
[ C_SUBSTART
|
||||
|
||||
{
|
||||
#ifdef NON_CORRECTING
|
||||
nsubstarts++;
|
||||
#endif
|
||||
}
|
||||
|
||||
C_IDENT
|
||||
{
|
||||
#ifdef NON_CORRECTING
|
||||
register p_gram temp;
|
||||
register p_start subp;
|
||||
|
||||
temp = search(NONTERM,lextoken.t_string,BOTH);
|
||||
subp = (p_start) alloc (sizeof(t_start));
|
||||
|
||||
subp->ff_nont = g_getcont(temp);
|
||||
subp->ff_name = (string) 0;
|
||||
subp->ff_next = (p_start) 0;
|
||||
g_setsubparse(pres, subp);
|
||||
#endif
|
||||
}
|
||||
|
||||
[ ',' C_IDENT
|
||||
{
|
||||
#ifdef NON_CORRECTING
|
||||
register p_gram temp;
|
||||
register p_start ff;
|
||||
|
||||
temp = search(NONTERM,lextoken.t_string,BOTH);
|
||||
|
||||
ff = g_getsubparse(pres);
|
||||
while (ff) {
|
||||
if (ff->ff_nont == g_getcont(temp)) {
|
||||
warning(linecount, "\"%s\" used twice in %%substart", lextoken.t_string);
|
||||
break;
|
||||
}
|
||||
ff = ff->ff_next;
|
||||
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
expr : '(' { copyact('(',')',1,0); }
|
||||
')'
|
||||
ff = (p_start) alloc(sizeof(t_start));
|
||||
ff->ff_nont = g_getcont(temp);
|
||||
ff->ff_name = (string) 0;
|
||||
ff->ff_next = g_getsubparse(pres);
|
||||
g_setsubparse(pres, ff);
|
||||
#endif
|
||||
}
|
||||
|
||||
]* ';'
|
||||
]?
|
||||
|
||||
C_ACTION
|
||||
;
|
||||
|
||||
repeats(int *kind; int *cnt;) { int t1 = 0; } :
|
||||
|
@ -562,119 +644,6 @@ firsts { register string p; }
|
|||
;
|
||||
{
|
||||
|
||||
STATIC
|
||||
copyact(ch1,ch2,flag,level) char ch1,ch2; {
|
||||
/*
|
||||
* Copy an action to file f. Opening bracket is ch1, closing bracket
|
||||
* is ch2.
|
||||
* If flag & 1, copy opening and closing parameters too.
|
||||
* If flag & 2, don't allow ','.
|
||||
*/
|
||||
static int text_seen = 0;
|
||||
register FILE *f;
|
||||
register ch; /* Current char */
|
||||
register match; /* used to read strings */
|
||||
int saved; /* save linecount */
|
||||
int sav_strip = strip_grammar;
|
||||
|
||||
f = fact;
|
||||
if (ch1 == '{' || flag != 1) strip_grammar = 0;
|
||||
if (!level) {
|
||||
saved = linecount;
|
||||
text_seen = 0;
|
||||
nparams = 0; /* count comma's */
|
||||
putc('\0',f);
|
||||
fprintf(f,"# line %d \"%s\"\n", linecount,f_input);
|
||||
}
|
||||
if (level || (flag & 1)) putc(ch1,f);
|
||||
for (;;) {
|
||||
ch = input();
|
||||
if (ch == ch2) {
|
||||
if (!level) {
|
||||
unput(ch);
|
||||
if (text_seen) nparams++;
|
||||
}
|
||||
if (level || (flag & 1)) putc(ch,f);
|
||||
if (strip_grammar != sav_strip) {
|
||||
if (ch1 == '{' || flag != 1) putchar(ch);
|
||||
}
|
||||
strip_grammar = sav_strip;
|
||||
return;
|
||||
}
|
||||
switch(ch) {
|
||||
case ')':
|
||||
case '}':
|
||||
case ']':
|
||||
error(linecount,"Parentheses mismatch");
|
||||
break;
|
||||
case '(':
|
||||
text_seen = 1;
|
||||
copyact('(',')',flag,level+1);
|
||||
continue;
|
||||
case '{':
|
||||
text_seen = 1;
|
||||
copyact('{','}',flag,level+1);
|
||||
continue;
|
||||
case '[':
|
||||
text_seen = 1;
|
||||
copyact('[',']',flag,level+1);
|
||||
continue;
|
||||
case '/':
|
||||
ch = input();
|
||||
unput(ch);
|
||||
if (ch == '*') {
|
||||
putc('/', f);
|
||||
skipcomment(1);
|
||||
continue;
|
||||
}
|
||||
ch = '/';
|
||||
text_seen = 1;
|
||||
break;
|
||||
case ';':
|
||||
case ',':
|
||||
if (! level && text_seen) {
|
||||
text_seen = 0;
|
||||
nparams++;
|
||||
if (ch == ',' && (flag & 2)) {
|
||||
warning(linecount, "Parameters may not be separated with a ','");
|
||||
ch = ';';
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '\'':
|
||||
case '"' :
|
||||
/*
|
||||
* watch out for brackets in strings, they do not
|
||||
* count !
|
||||
*/
|
||||
text_seen = 1;
|
||||
match = ch;
|
||||
putc(ch,f);
|
||||
while((ch = input())) {
|
||||
if (ch == match) break;
|
||||
if (ch == '\\') {
|
||||
putc(ch,f);
|
||||
ch = input();
|
||||
}
|
||||
if (ch == '\n') {
|
||||
error(linecount,"Newline in string");
|
||||
unput(match);
|
||||
}
|
||||
putc(ch,f);
|
||||
}
|
||||
if (ch == match) break;
|
||||
/* Fall through */
|
||||
case EOF :
|
||||
if (!level) error(saved,"Action does not terminate");
|
||||
strip_grammar = sav_strip;
|
||||
return;
|
||||
default:
|
||||
if (c_class[ch] != ISSPA) text_seen = 1;
|
||||
}
|
||||
putc(ch,f);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC p_gram
|
||||
copyrule(p,length) register p_gram p; {
|
||||
/*
|
||||
|
|
|
@ -80,7 +80,7 @@ new_mem(p) register p_info p; {
|
|||
*/
|
||||
p->i_size += p->i_incr * p->i_esize;
|
||||
}
|
||||
p->i_ptr = !p->i_ptr ?
|
||||
p->i_ptr = !p->i_ptr ?
|
||||
alloc(p->i_size) :
|
||||
ralloc(p->i_ptr, p->i_size);
|
||||
p->i_max = p->i_ptr + sz;
|
||||
|
|
|
@ -47,8 +47,8 @@ char c_class[] = {
|
|||
ISKEY, /* '%' */
|
||||
0, /* '&' */
|
||||
ISLIT, /* ''' */
|
||||
ISTOK, /* '(' */
|
||||
ISTOK, /* ')' */
|
||||
ISACT, /* '(' */
|
||||
0, /* ')' */
|
||||
ISTOK, /* '*' */
|
||||
ISTOK, /* '+' */
|
||||
ISTOK, /* ',' */
|
||||
|
@ -130,9 +130,9 @@ char c_class[] = {
|
|||
ISLET, /* 'x' */
|
||||
ISLET, /* 'y' */
|
||||
ISLET, /* 'z' */
|
||||
ISTOK, /* '{' */
|
||||
ISACT, /* '{' */
|
||||
ISTOK, /* '|' */
|
||||
ISTOK, /* '}' */
|
||||
0, /* '}' */
|
||||
0, /* '~' */
|
||||
0 /* 0177 */
|
||||
};
|
||||
|
|
|
@ -14,3 +14,4 @@ extern char c_class[];
|
|||
#define ISTOK 5
|
||||
#define ISCOM 6
|
||||
#define ISLIT 7
|
||||
#define ISACT 8
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
static string rcsid1 = "$Id$";
|
||||
# endif
|
||||
|
||||
|
||||
static string c_first = "> firstset ";
|
||||
static string c_contains = "> containset ";
|
||||
static string c_follow = "> followset ";
|
||||
|
@ -72,7 +71,7 @@ conflchecks() {
|
|||
f_input = x->f_name;
|
||||
for (s = x->f_nonterminals; s != -1; s = p->n_next) {
|
||||
p = &nonterms[s];
|
||||
if (check(p->n_rule)) p->n_flags |= VERBOSE;
|
||||
if (check(p->n_rule)) p->n_flags |= VERBOSE;
|
||||
}
|
||||
}
|
||||
for (x = files; x < maxfiles; x++) {
|
||||
|
@ -188,7 +187,7 @@ check(p) register p_gram p; {
|
|||
n = &nonterms[g_getcont(p)];
|
||||
if (g_getnpar(p) != getntparams(n)) {
|
||||
error(p->g_lineno,
|
||||
"Call of %s: parameter count mismatch",
|
||||
"Call of %s: parameter count mismatch",
|
||||
n->n_name);
|
||||
}
|
||||
break; }
|
||||
|
@ -211,13 +210,13 @@ check(p) register p_gram p; {
|
|||
temp = setalloc();
|
||||
setunion(temp,q->t_first);
|
||||
if (!setintersect(temp,q->t_follow)) {
|
||||
/*
|
||||
* q->t_first * q->t_follow != EMPTY
|
||||
*/
|
||||
/*
|
||||
* q->t_first * q->t_follow != EMPTY
|
||||
*/
|
||||
if (!(q->t_flags & RESOLVER)) {
|
||||
/*
|
||||
* No conflict resolver
|
||||
*/
|
||||
/*
|
||||
* No conflict resolver
|
||||
*/
|
||||
error(p->g_lineno,
|
||||
"Repetition conflict");
|
||||
retval = 1;
|
||||
|
@ -249,7 +248,7 @@ check(p) register p_gram p; {
|
|||
"Alternation conflict");
|
||||
retval = 1;
|
||||
moreverbose(temp);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (l->l_flag & (COND|PREFERING|AVOIDING)) {
|
||||
l->l_flag |= NOCONF;
|
||||
|
@ -257,8 +256,8 @@ check(p) register p_gram p; {
|
|||
"Conflict resolver without conflict");
|
||||
}
|
||||
}
|
||||
if (l->l_flag & PREFERING) propagate(l->l_symbs,p+1);
|
||||
free( (p_mem) temp);
|
||||
if (l->l_flag & PREFERING) propagate(l->l_symbs,p+1);
|
||||
retval |= check(l->l_rule);
|
||||
break; }
|
||||
}
|
||||
|
@ -378,7 +377,7 @@ prrule(p) register p_gram p; {
|
|||
spaces();
|
||||
p++; continue; }
|
||||
case LITERAL :
|
||||
case TERMINAL : {
|
||||
case TERMINAL : {
|
||||
register p_token pt = &tokens[g_getcont(p)];
|
||||
|
||||
fprintf(f,pt->t_tokno<0400 ?
|
||||
|
@ -463,7 +462,7 @@ propagate(set,p) p_set set; register p_gram p; {
|
|||
while (g_gettype(p) != EORULE) {
|
||||
setminus(g_getlink(p)->l_symbs,set);
|
||||
p++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
STATIC
|
||||
|
|
|
@ -59,6 +59,12 @@ STATIC do_contains();
|
|||
STATIC contains();
|
||||
STATIC int nsafes();
|
||||
STATIC int do_safes();
|
||||
#ifdef NON_CORRECTING
|
||||
STATIC int nc_nfirst();
|
||||
STATIC nc_first();
|
||||
STATIC int nc_nfollow();
|
||||
STATIC nc_follow();
|
||||
#endif
|
||||
|
||||
do_compute() {
|
||||
/*
|
||||
|
@ -116,6 +122,31 @@ do_compute() {
|
|||
setntsafe(p,SCANDONE);
|
||||
}
|
||||
co_trans(nsafes);
|
||||
|
||||
#ifdef NON_CORRECTING
|
||||
if (subpars_sim) {
|
||||
int s;
|
||||
|
||||
/* compute the union of the first sets of all start symbols
|
||||
Used to compute the nc-first-sets when -s option is given */
|
||||
start_firsts = get_set();
|
||||
for (st = start; st; st = st->ff_next) {
|
||||
s = setunion(start_firsts, (&nonterms[st->ff_nont])->n_first);
|
||||
}
|
||||
}
|
||||
|
||||
if (non_corr) {
|
||||
/* compute the non_corr first sets for all nonterminals and terms */
|
||||
|
||||
co_trans(nc_nfirst);
|
||||
for (st = start; st; st = st->ff_next) {
|
||||
p = &nonterms[st->ff_nont];
|
||||
PUTIN(p->n_nc_follow,0);
|
||||
}
|
||||
co_trans(nc_nfollow);
|
||||
}
|
||||
#endif
|
||||
|
||||
# ifndef NDEBUG
|
||||
if (debug) {
|
||||
fputs("Safeties:\n", stderr);
|
||||
|
@ -151,6 +182,10 @@ createsets() {
|
|||
p = &nonterms[i];
|
||||
p->n_flags |= GENSTATIC;
|
||||
p->n_first = get_set();
|
||||
#ifdef NON_CORRECTING
|
||||
p->n_nc_first = get_set();
|
||||
p->n_nc_follow = get_set();
|
||||
#endif
|
||||
p->n_follow = get_set();
|
||||
walk(f->f_used, p->n_rule);
|
||||
}
|
||||
|
@ -185,6 +220,10 @@ walk(u, p) p_set u; register p_gram p; {
|
|||
|
||||
q = g_getterm(p);
|
||||
q->t_first = get_set();
|
||||
#ifdef NON_CORRECTING
|
||||
q->t_nc_first = get_set();
|
||||
q->t_nc_follow = get_set();
|
||||
#endif
|
||||
q->t_follow = get_set();
|
||||
walk(u, q->t_rule);
|
||||
break; }
|
||||
|
@ -193,6 +232,9 @@ walk(u, p) p_set u; register p_gram p; {
|
|||
|
||||
l = g_getlink(p);
|
||||
l->l_symbs = get_set();
|
||||
#ifdef NON_CORRECTING
|
||||
l->l_nc_symbs = get_set();
|
||||
#endif
|
||||
l->l_others = get_set();
|
||||
walk(u, l->l_rule);
|
||||
break; }
|
||||
|
@ -237,7 +279,7 @@ empty(p) register p_gram p; {
|
|||
|
||||
for (;;) {
|
||||
switch (g_gettype(p)) {
|
||||
case EORULE :
|
||||
case EORULE :
|
||||
return 1;
|
||||
case TERM : {
|
||||
register p_term q;
|
||||
|
@ -271,6 +313,12 @@ nfirst(p) register p_nont p; {
|
|||
return first(p->n_first, p->n_rule, 0);
|
||||
}
|
||||
|
||||
#ifdef NON_CORRECTING
|
||||
STATIC int nc_nfirst(p) register p_nont p; {
|
||||
return nc_first(p->n_nc_first, p->n_rule, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
STATIC
|
||||
first(setp,p,flag) p_set setp; register p_gram p; {
|
||||
/*
|
||||
|
@ -282,8 +330,8 @@ first(setp,p,flag) p_set setp; register p_gram p; {
|
|||
*/
|
||||
register s; /* Will gather return value */
|
||||
int noenter;/* when set, unables entering of elements into
|
||||
* setp. This is necessary to walk through the
|
||||
* rest of rule p.
|
||||
* setp. This is necessary to walk through the
|
||||
* rest of rule p.
|
||||
*/
|
||||
|
||||
s = 0;
|
||||
|
@ -349,6 +397,108 @@ first(setp,p,flag) p_set setp; register p_gram p; {
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef NON_CORRECTING
|
||||
STATIC
|
||||
nc_first(setp,p,flag) p_set setp; register p_gram p; {
|
||||
/*
|
||||
* Compute the non_corr FIRST set of rule p.
|
||||
* If flag = 0, also the non_corr first sets for terms and
|
||||
* alternations in the rule p are computed.
|
||||
* The non_corr FIRST set is put in setp.
|
||||
* return 1 if the set refered to by "setp" changed
|
||||
* If the -s flag was given, the union of the first-sets of all
|
||||
* start symbols is used whenever an action occurs. Else, only the
|
||||
* first-sets of startsynbols in the %substart are used
|
||||
*/
|
||||
|
||||
register s; /* Will gather return value */
|
||||
int noenter;/* when set, unables entering of elements into
|
||||
* setp. This is necessary to walk through the
|
||||
* rest of rule p.
|
||||
*/
|
||||
|
||||
s = 0;
|
||||
noenter = 0;
|
||||
for (;;) {
|
||||
switch (g_gettype(p)) {
|
||||
case EORULE :
|
||||
return s;
|
||||
case TERM : {
|
||||
register p_term q;
|
||||
|
||||
q = g_getterm(p);
|
||||
if (flag == 0) {
|
||||
if (nc_first(q->t_nc_first,q->t_rule,0))/*nothing*/;
|
||||
}
|
||||
if (!noenter) s |= setunion(setp,q->t_nc_first);
|
||||
p++;
|
||||
if (r_getkind(q) == STAR ||
|
||||
r_getkind(q) == OPT ||
|
||||
empty(q->t_rule)) continue;
|
||||
break; }
|
||||
case ALTERNATION : {
|
||||
register p_link l;
|
||||
|
||||
l = g_getlink(p);
|
||||
if (flag == 0) {
|
||||
if (nc_first(l->l_nc_symbs,l->l_rule,0))/*nothing*/;
|
||||
}
|
||||
if (noenter == 0) {
|
||||
s |= setunion(setp,l->l_nc_symbs);
|
||||
}
|
||||
if (g_gettype(p+1) == EORULE) return s;
|
||||
}
|
||||
p++;
|
||||
continue;
|
||||
case ACTION : {
|
||||
register p_start subp;
|
||||
|
||||
if (!noenter)
|
||||
if (subpars_sim)
|
||||
s |= setunion(setp, start_firsts);
|
||||
else {
|
||||
for (subp = g_getsubparse(p); subp;
|
||||
subp = subp->ff_next)
|
||||
s |= setunion(setp, (&nonterms[subp->ff_nont])->n_nc_first);
|
||||
|
||||
}
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
case LITERAL :
|
||||
case TERMINAL :
|
||||
if (g_getcont(p) == g_getcont(illegal_gram)) {
|
||||
/* Ignore for this set. */
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
if ((noenter == 0) && !IN(setp,g_getcont(p))) {
|
||||
s = 1;
|
||||
PUTIN(setp,g_getcont(p));
|
||||
}
|
||||
p++;
|
||||
break;
|
||||
case NONTERM : {
|
||||
register p_nont n;
|
||||
|
||||
n = &nonterms[g_getcont(p)];
|
||||
if (noenter == 0) {
|
||||
s |= setunion(setp,n->n_nc_first);
|
||||
if (ntneeded) NTPUTIN(setp,g_getcont(p));
|
||||
}
|
||||
p++;
|
||||
if (n->n_flags & EMPTY) continue;
|
||||
break; }
|
||||
}
|
||||
if (flag == 0) {
|
||||
noenter = 1;
|
||||
continue;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
STATIC int
|
||||
nfollow(p) register p_nont p; {
|
||||
return follow(p->n_follow, p->n_rule);
|
||||
|
@ -426,6 +576,87 @@ follow(setp,p) p_set setp; register p_gram p; {
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef NON_CORRECTING
|
||||
|
||||
STATIC int
|
||||
nc_nfollow(p) register p_nont p; {
|
||||
return follow(p->n_nc_follow, p->n_rule);
|
||||
}
|
||||
|
||||
STATIC
|
||||
nc_follow(setp,p) p_set setp; register p_gram p; {
|
||||
/*
|
||||
* setp is the follow set for the rule p.
|
||||
* Compute the follow sets in the rule p from this set.
|
||||
* Return 1 if a follow set of a nonterminal changed.
|
||||
*/
|
||||
register s; /* Will gather return value */
|
||||
|
||||
s = 0;
|
||||
for (;;) {
|
||||
switch (g_gettype(p)) {
|
||||
case EORULE :
|
||||
return s;
|
||||
case TERM : {
|
||||
register p_term q;
|
||||
|
||||
q = g_getterm(p);
|
||||
if (empty(p+1)) {
|
||||
/*
|
||||
* If what follows the term can be empty,
|
||||
* everything that can follow the whole
|
||||
* rule can also follow the term
|
||||
*/
|
||||
s |= setunion(q->t_nc_follow,setp);
|
||||
}
|
||||
/*
|
||||
* Everything that can start the rest of the rule
|
||||
* can follow the term
|
||||
*/
|
||||
s |= nc_first(q->t_nc_follow,p+1,1);
|
||||
if (r_getkind(q) == STAR ||
|
||||
r_getkind(q) == PLUS ||
|
||||
r_getnum(q) ) {
|
||||
/*
|
||||
* If the term involves a repetition
|
||||
* of possibly more than one,
|
||||
* everything that can start the term
|
||||
* can also follow it.
|
||||
*/
|
||||
s |= nc_follow(q->t_nc_first,q->t_rule);
|
||||
}
|
||||
/*
|
||||
* Now propagate the set computed sofar
|
||||
*/
|
||||
s |= nc_follow(q->t_nc_follow, q->t_rule);
|
||||
break; }
|
||||
case ALTERNATION :
|
||||
/*
|
||||
* Just propagate setp
|
||||
*/
|
||||
s |= nc_follow(setp,g_getlink(p)->l_rule);
|
||||
break;
|
||||
case NONTERM : {
|
||||
register p_nont n;
|
||||
|
||||
n = &nonterms[g_getcont(p)];
|
||||
s |= nc_first(n->n_nc_follow,p+1,1);
|
||||
if (empty(p+1)) {
|
||||
/*
|
||||
* If the rest of p can produce empty,
|
||||
* everything that follows p can follow
|
||||
* the nonterminal
|
||||
*/
|
||||
s |= setunion(n->n_nc_follow,setp);
|
||||
}
|
||||
break; }
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
STATIC
|
||||
co_dirsymb(setp,p) p_set setp; register p_gram p; {
|
||||
/*
|
||||
|
@ -519,7 +750,7 @@ do_lengthcomp() {
|
|||
* Compute the minimum length of a terminal production for each
|
||||
* nonterminal.
|
||||
* This length consists of two fields: the number of terminals,
|
||||
* and a number that is composed of
|
||||
* and a number that is composed of
|
||||
* - the number of this alternative
|
||||
* - a crude measure of the number of terms and nonterminals in the
|
||||
* production of this shortest string.
|
||||
|
@ -562,6 +793,12 @@ complength(p,le) register p_gram p; p_length le; {
|
|||
switch (g_gettype(p)) {
|
||||
case LITERAL :
|
||||
case TERMINAL :
|
||||
#ifdef NON_CORRECTING
|
||||
if (g_getcont(p) == g_getcont(illegal_gram)) {
|
||||
add(&X, INFINITY, 0);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
add(&X, 1, 0);
|
||||
break;
|
||||
case ALTERNATION :
|
||||
|
@ -571,6 +808,7 @@ complength(p,le) register p_gram p; p_length le; {
|
|||
while (g_gettype(p) != EORULE) {
|
||||
cnt++;
|
||||
l = g_getlink(p);
|
||||
p++;
|
||||
complength(l->l_rule,&i);
|
||||
i.val += cnt;
|
||||
if (l->l_flag & DEF) {
|
||||
|
@ -580,7 +818,6 @@ complength(p,le) register p_gram p; p_length le; {
|
|||
if (compare(&i, &X) < 0) {
|
||||
X = i;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
/* Fall through */
|
||||
case EORULE :
|
||||
|
@ -593,7 +830,7 @@ complength(p,le) register p_gram p; p_length le; {
|
|||
q = g_getterm(p);
|
||||
rep = r_getkind(q);
|
||||
X.val += 1;
|
||||
if ((q->t_flags&PERSISTENT) ||
|
||||
if ((q->t_flags&PERSISTENT) ||
|
||||
rep==FIXED || rep==PLUS) {
|
||||
complength(q->t_rule,&i);
|
||||
add(&X, i.cnt, i.val);
|
||||
|
@ -661,6 +898,7 @@ setdefaults(p) register p_gram p; {
|
|||
do {
|
||||
cnt++;
|
||||
l = g_getlink(p);
|
||||
p++;
|
||||
complength(l->l_rule,&i);
|
||||
i.val += cnt;
|
||||
if (l->l_flag & DEF) temp = 1;
|
||||
|
@ -671,7 +909,6 @@ setdefaults(p) register p_gram p; {
|
|||
count = i;
|
||||
}
|
||||
setdefaults(l->l_rule);
|
||||
p++;
|
||||
} while (g_gettype(p) != EORULE);
|
||||
if (!temp) {
|
||||
/* No user specified default */
|
||||
|
@ -687,7 +924,7 @@ STATIC
|
|||
do_contains(n) register p_nont n; {
|
||||
/*
|
||||
* Compute the total set of symbols that nonterminal n can
|
||||
* produce
|
||||
* produce
|
||||
*/
|
||||
|
||||
if (n->n_contains == 0) {
|
||||
|
@ -811,7 +1048,7 @@ do_safes(p,safe,ch) register p_gram p; register int *ch; {
|
|||
for (;;) {
|
||||
switch (g_gettype(p)) {
|
||||
case ACTION:
|
||||
p++;
|
||||
p++;
|
||||
continue;
|
||||
case LITERAL:
|
||||
case TERMINAL:
|
||||
|
@ -830,12 +1067,13 @@ do_safes(p,safe,ch) register p_gram p; register int *ch; {
|
|||
safe = t_after(rep, i, retval);
|
||||
break; }
|
||||
case ALTERNATION : {
|
||||
register p_link l;
|
||||
register p_link l;
|
||||
register int i;
|
||||
|
||||
retval = -1;
|
||||
while (g_gettype(p) == ALTERNATION) {
|
||||
l = g_getlink(p);
|
||||
p++;
|
||||
if (safe > SAFE && (l->l_flag & DEF)) {
|
||||
i = do_safes(l->l_rule,SAFESCANDONE,ch);
|
||||
}
|
||||
|
@ -848,7 +1086,6 @@ do_safes(p,safe,ch) register p_gram p; register int *ch; {
|
|||
}
|
||||
else if (i > retval) retval = i;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
return retval; }
|
||||
case NONTERM : {
|
||||
|
|
|
@ -36,6 +36,11 @@ extern int ntokens; /* number of terminals */
|
|||
extern int nterms; /* number of terms */
|
||||
extern int nalts; /* number of alternatives */
|
||||
extern p_start start; /* will contain startsymbols */
|
||||
#ifdef NON_CORRECTING
|
||||
extern int nsubstarts; /* number of subparserstarts */
|
||||
extern p_set start_firsts; /* Will contain the union of first sets of
|
||||
startsymbols when -n -s option is on */
|
||||
#endif
|
||||
extern int linecount; /* line number */
|
||||
extern int assval; /* to create difference between literals
|
||||
* and other terminals
|
||||
|
@ -73,8 +78,17 @@ extern string LLgenid; /* LLgen identification string */
|
|||
extern t_token lextoken; /* the current token */
|
||||
extern int nerrors;
|
||||
extern string rec_file, incl_file;
|
||||
#ifdef NON_CORRECTING
|
||||
extern string nc_rec_file, nc_incl_file;
|
||||
#endif
|
||||
extern int low_percentage, high_percentage;
|
||||
extern int min_cases_for_jmptable;
|
||||
extern int jmptable_option;
|
||||
extern int ansi_c;
|
||||
#ifdef NON_CORRECTING
|
||||
extern int non_corr;
|
||||
extern int subpars_sim;
|
||||
extern p_gram illegal_gram;
|
||||
#endif
|
||||
extern int strip_grammar;
|
||||
extern int in_production;
|
||||
|
|
|
@ -51,6 +51,9 @@ extern gencode();
|
|||
STATIC opentemp();
|
||||
STATIC geninclude();
|
||||
STATIC genrecovery();
|
||||
#ifdef NON_CORRECTING
|
||||
STATIC genncrecovery();
|
||||
#endif
|
||||
STATIC string genname();
|
||||
STATIC generate();
|
||||
STATIC prset();
|
||||
|
@ -109,18 +112,31 @@ genhdr()
|
|||
else {
|
||||
fputs("#if __STDC__ || __cplusplus\n#define LL_ANSI_C 1\n#endif\n", fpars);
|
||||
}
|
||||
#ifdef NON_CORRECTING
|
||||
if (non_corr) fputs("#define LL_NON_CORR 1\n", fpars);
|
||||
#endif
|
||||
fprintf(fpars, "#define LL_LEXI %s\n", lexical);
|
||||
copyfile(incl_file);
|
||||
}
|
||||
|
||||
gencode(argc) {
|
||||
register p_file p = files;
|
||||
|
||||
|
||||
/* Set up for code generation */
|
||||
if ((fact = fopen(f_temp,"r")) == NULL) {
|
||||
fatal(0,e_noopen,f_temp);
|
||||
}
|
||||
|
||||
#ifdef NON_CORRECTING
|
||||
/* The non-correcting error recovery must be generated BEFORE
|
||||
parser code is generated!!!! In case of conflict resolvers,
|
||||
the code-generation process will delete conflicting symbols
|
||||
from first and followsets, making them UNUSABLE for the
|
||||
non-correcting error recovery code.
|
||||
*/
|
||||
if (non_corr)
|
||||
genncrecovery();
|
||||
#endif
|
||||
/* For every source file .... */
|
||||
while (argc--) {
|
||||
/* Open temporary */
|
||||
|
@ -138,6 +154,7 @@ gencode(argc) {
|
|||
}
|
||||
geninclude();
|
||||
genrecovery();
|
||||
|
||||
fclose(fact);
|
||||
}
|
||||
|
||||
|
@ -167,13 +184,18 @@ geninclude() {
|
|||
}
|
||||
fprintf(fpars, "#define %s_MAXTOKNO %d\n", prefix ? prefix : "LL",
|
||||
maxno);
|
||||
#ifdef NON_CORRECTING
|
||||
if (non_corr) {
|
||||
fprintf(fpars, "#define %sNONCORR\n", prefix ? prefix : "LL");
|
||||
}
|
||||
#endif
|
||||
doclose(fpars);
|
||||
install(f_include, ".");
|
||||
}
|
||||
|
||||
STATIC
|
||||
genrecovery() {
|
||||
register FILE *f;
|
||||
register FILE *f;
|
||||
register p_token t;
|
||||
register int *q;
|
||||
register p_nont p;
|
||||
|
@ -202,6 +224,12 @@ genrecovery() {
|
|||
i > 0 ? i : 1,
|
||||
ntokens);
|
||||
if (onerror) fprintf(f,"#define LL_USERHOOK %s\n", onerror);
|
||||
#ifdef NON_CORRECTING
|
||||
if (non_corr) {
|
||||
fputs("static int nc_done = 0;\n", f);
|
||||
fputs("static int err_seen = 0;\n", f);
|
||||
}
|
||||
#endif
|
||||
/* Now generate the routines that call the startsymbols */
|
||||
fputs("#if LL_ANSI_C\n", f);
|
||||
for (st = start; st; st = st->ff_next) {
|
||||
|
@ -214,7 +242,18 @@ genrecovery() {
|
|||
for (st = start; st; st = st->ff_next) {
|
||||
fprintf(f, "#if LL_ANSI_C\nvoid %s(void)\n#else\n%s()\n#endif\n", st->ff_name, st->ff_name);
|
||||
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];", f);
|
||||
#ifdef NON_CORRECTING
|
||||
if (non_corr) {
|
||||
fputs(" \n\tint oldstartsymb;", f);
|
||||
fputs(" \n\tint oldncflag;", f);
|
||||
fputs(" \n\toldstartsymb = LLstartsymb;", f);
|
||||
fputs(" \n\toldncflag = nc_done;", f);
|
||||
fputs(" \n\tnc_done = 0;", f);
|
||||
fprintf(f, "\n\tLLstartsymb = %d;", st->ff_nont + assval);
|
||||
}
|
||||
#endif
|
||||
fputs("\n\tLLnewlevel(s);\n\tLLread();\n", f);
|
||||
if (g_gettype(p->n_rule) == ALTERNATION) {
|
||||
genpush(findindex(p->n_contains));
|
||||
}
|
||||
|
@ -224,7 +263,18 @@ genrecovery() {
|
|||
fputs("\tLL_NOSCANDONE(EOFILE);\n",f);
|
||||
}
|
||||
else fputs("\tLL_SCANDONE(EOFILE);\n",f);
|
||||
fputs("\tLLoldlevel(s);\n}\n",f);
|
||||
fputs("\tLLoldlevel(s);\n",f);
|
||||
#ifdef NON_CORRECTING
|
||||
if (non_corr) {
|
||||
fputs("\tLLstartsymb = oldstartsymb;\n", f);
|
||||
fputs("\tif (nc_done == 1) { \n", f);
|
||||
fputs("\t\terr_seen = 1;\n", f);
|
||||
fputs("\tnc_done = oldncflag;\n", f);
|
||||
fputs("\t}\n", f);
|
||||
}
|
||||
#endif
|
||||
fputs("}\n", f);
|
||||
|
||||
}
|
||||
/* Now generate the sets */
|
||||
fputs("static char LLsets[] = {\n",f);
|
||||
|
@ -254,6 +304,46 @@ genrecovery() {
|
|||
install(f_rec, ".");
|
||||
}
|
||||
|
||||
#ifdef NON_CORRECTING
|
||||
STATIC
|
||||
genncrecovery() {
|
||||
register FILE *f;
|
||||
register p_token t;
|
||||
register int *q;
|
||||
int *index;
|
||||
|
||||
/* Generate the non-correcting error recovery file */
|
||||
|
||||
opentemp((string) 0);
|
||||
f = fpars;
|
||||
|
||||
genhdr();
|
||||
correct_prefix();
|
||||
save_grammar(f);
|
||||
|
||||
fprintf(f, "#define LLFIRST_NT %d\n", assval);
|
||||
fprintf(f, "#define LLSETSIZE %d\n", nbytes);
|
||||
|
||||
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("#define LLindex (LL_index+1)\nstatic short LL_index[] = {0,0,\n",f);
|
||||
for (q = index+1; q < &index[assval]; q++) {
|
||||
fprintf(f, "%d,\n", *q);
|
||||
}
|
||||
fputs(c_arrend, f);
|
||||
free((p_mem) index);
|
||||
|
||||
copyfile(nc_incl_file);
|
||||
copyfile(nc_rec_file);
|
||||
|
||||
doclose(f);
|
||||
install(f_nc, ".");
|
||||
}
|
||||
#endif
|
||||
|
||||
STATIC
|
||||
generate(f) p_file f; {
|
||||
/*
|
||||
|
@ -272,7 +362,7 @@ generate(f) p_file f; {
|
|||
for (ff = f->f_firsts; ff; ff = ff->ff_next) {
|
||||
macro(ff->ff_name,&nonterms[ff->ff_nont]);
|
||||
}
|
||||
|
||||
|
||||
/* For every nonterminal generate a function */
|
||||
for (s = f->f_nonterminals; s != -1; s = p->n_next) {
|
||||
p = &nonterms[s];
|
||||
|
@ -378,7 +468,7 @@ STATIC
|
|||
getparams() {
|
||||
/* getparams is called if a nonterminal has parameters. The names
|
||||
* of the parameters have to be found, and they should be declared
|
||||
*/
|
||||
*/
|
||||
long off;
|
||||
register int l;
|
||||
long ftell();
|
||||
|
@ -407,7 +497,7 @@ getparams() {
|
|||
}
|
||||
fputs(") ",fpars);
|
||||
/*
|
||||
* Now copy the declarations
|
||||
* Now copy the declarations
|
||||
*/
|
||||
l = getc(fact); /* patch: some implementations of fseek
|
||||
do not work properly after "ungetc"
|
||||
|
@ -469,7 +559,7 @@ 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;
|
||||
int delayed = 0;
|
||||
|
||||
|
@ -911,7 +1001,7 @@ codeforterm(q,safety,toplevel) register p_term q; {
|
|||
int term_is_persistent = (q->t_flags & PERSISTENT);
|
||||
int ispushed = NOPOP;
|
||||
|
||||
if (!(toplevel > 0 &&
|
||||
if (!(toplevel > 0 &&
|
||||
(safety == 0 || (!onerror && safety <= SAFESCANDONE)) &&
|
||||
(rep_kind == OPT || (rep_kind == FIXED && rep_count == 0)))) {
|
||||
ispushed = findindex(q->t_contains);
|
||||
|
@ -1091,21 +1181,21 @@ genswhead(q, rep_kind, rep_count, safety, ispushed) register p_term q; {
|
|||
|
||||
STATIC
|
||||
gencases(tokenlist, caseno, compacted)
|
||||
int *tokenlist;
|
||||
int *tokenlist;
|
||||
{
|
||||
/*
|
||||
* setp points to a bitset indicating which cases must
|
||||
* be generated.
|
||||
* YECH, the PCC compiler does not accept many cases without statements
|
||||
* inbetween, so after every case label an empty statement is
|
||||
* generated.
|
||||
* YECH, the PCC compiler does not accept many cases without
|
||||
* statements in between, so after every case label an empty
|
||||
* statement is generated.
|
||||
* The C-grammar used by PCC is really stupid on this point :
|
||||
* it contains the rule
|
||||
* statement : label statement
|
||||
* statement : label statement
|
||||
* which is right-recursive, and as is well known, LALR parsers don't
|
||||
* handle these things very good.
|
||||
* handle these things very well.
|
||||
* The grammar should have been written :
|
||||
* labeledstatement : labels statement ;
|
||||
* labeledstatement : labels statement ;
|
||||
* labels : labels label | ;
|
||||
*/
|
||||
register p_token p;
|
||||
|
@ -1119,7 +1209,7 @@ gencases(tokenlist, caseno, compacted)
|
|||
(p->t_tokno < 0400 ? "/* case '%s' */\n" :
|
||||
"/* case %s */\n") :
|
||||
p->t_tokno<0400 ? "case /* '%s' */ %d : ;\n"
|
||||
: "case /* %s */ %d : ;\n",
|
||||
: "case /* %s */ %d : ;\n",
|
||||
p->t_string, i);
|
||||
}
|
||||
}
|
||||
|
@ -1220,10 +1310,10 @@ out_list(tokenlist, listno, casecnt)
|
|||
register int i;
|
||||
register FILE *f = fpars;
|
||||
|
||||
fprintf(f, "static %s LL%d_tklist[] = {",
|
||||
fprintf(f, "static %s LL%d_tklist[] = {",
|
||||
casecnt <= 127 ? "char" : "short",
|
||||
listno);
|
||||
|
||||
|
||||
for (i = 0; i < ntokens; i++) {
|
||||
fprintf(f, "%c%d,", i % 10 == 0 ? '\n': ' ', tokenlist[i]);
|
||||
}
|
||||
|
@ -1260,6 +1350,10 @@ correct_prefix()
|
|||
fprintf(f, "#define LLnewlevel %snewlevel\n", s);
|
||||
fprintf(f, "#define LLoldlevel %soldlevel\n", s);
|
||||
fprintf(f, "#define LLmessage %smessage\n", s);
|
||||
#ifdef NON_CORRECTING
|
||||
fprintf(f, "#define LLnc_recovery %sncrecovery\n", s);
|
||||
fprintf(f, "#define LLstartsymb %sstartsymb\n", s);
|
||||
#endif
|
||||
}
|
||||
fprintf(f, "#include \"%s\"\n", f_include);
|
||||
}
|
||||
|
|
|
@ -33,6 +33,10 @@ p_token maxt;
|
|||
int ntokens;
|
||||
int nterms, nalts;
|
||||
int norder, torder;
|
||||
#ifdef NON_CORRECTING
|
||||
int nsubstarts;
|
||||
p_set start_firsts;
|
||||
#endif
|
||||
p_start start;
|
||||
int linecount;
|
||||
int assval;
|
||||
|
@ -42,6 +46,9 @@ FILE *finput;
|
|||
FILE *fact;
|
||||
char f_pars[] = PARSERFILE;
|
||||
char f_temp[] = ACTFILE;
|
||||
#ifdef NON_CORRECTING
|
||||
char f_nc[20];
|
||||
#endif
|
||||
char f_out[20];
|
||||
string f_input;
|
||||
char f_include[20];
|
||||
|
@ -64,8 +71,19 @@ string LLgenid = "/* LLgen generated code from source %s */\n";
|
|||
t_token lextoken;
|
||||
int nerrors;
|
||||
string rec_file, incl_file;
|
||||
#ifdef NON_CORRECTING
|
||||
string nc_rec_file, nc_incl_file;
|
||||
#endif
|
||||
int low_percentage = 10, high_percentage = 30;
|
||||
int min_cases_for_jmptable = 8;
|
||||
int jmptable_option;
|
||||
int ansi_c = 0;
|
||||
#ifdef NON_CORRECTING
|
||||
int non_corr = 0;
|
||||
int subpars_sim = 0;
|
||||
p_gram illegal_gram;
|
||||
#endif
|
||||
int strip_grammar = 0;
|
||||
int in_production; /* set when the parser is reading a production
|
||||
rule.
|
||||
*/
|
||||
|
|
|
@ -25,7 +25,9 @@
|
|||
# define ACTFILE "tempXXXXXX" /* temporary file to save actions */
|
||||
# define HFILE "%spars.h" /* file for "#define's " */
|
||||
# define RFILE "%spars.c" /* Error recovery */
|
||||
|
||||
#ifdef NON_CORRECTING
|
||||
# define NCFILE "%sncor.c" /* Non-corrcting error recovery */
|
||||
#endif
|
||||
extern FILE *finput;
|
||||
extern FILE *fpars;
|
||||
extern FILE *fact;
|
||||
|
@ -36,3 +38,6 @@ extern char f_out[];
|
|||
extern string f_input;
|
||||
extern char f_include[];
|
||||
extern char f_rec[];
|
||||
#ifdef NON_CORRECTING
|
||||
extern char f_nc[];
|
||||
#endif
|
||||
|
|
|
@ -41,13 +41,13 @@ extern char *sbrk();
|
|||
main(argc,argv) register string argv[]; {
|
||||
register string arg;
|
||||
string libpath();
|
||||
char *beg_sbrk;
|
||||
char *beg_sbrk = 0;
|
||||
|
||||
/* Initialize */
|
||||
|
||||
assval = 0400;
|
||||
/* read options */
|
||||
|
||||
|
||||
while (argc >= 2 && (arg = argv[1], *arg == '-')) {
|
||||
while (*++arg) {
|
||||
switch(*arg) {
|
||||
|
@ -84,7 +84,7 @@ main(argc,argv) register string argv[]; {
|
|||
fprintf(stderr,"duplicate -r flag\n");
|
||||
exit(1);
|
||||
}
|
||||
rec_file = ++arg;
|
||||
rec_file = ++arg;
|
||||
break;
|
||||
case 'i':
|
||||
case 'I':
|
||||
|
@ -92,7 +92,7 @@ main(argc,argv) register string argv[]; {
|
|||
fprintf(stderr,"duplicate -i flag\n");
|
||||
exit(1);
|
||||
}
|
||||
incl_file = ++arg;
|
||||
incl_file = ++arg;
|
||||
break;
|
||||
#endif /* not NDEBUG */
|
||||
case 'x':
|
||||
|
@ -104,8 +104,18 @@ main(argc,argv) register string argv[]; {
|
|||
case 'A':
|
||||
ansi_c = 1;
|
||||
continue;
|
||||
#ifdef NON_CORRECTING
|
||||
case 'n':
|
||||
case 'N':
|
||||
non_corr = 1;
|
||||
continue;
|
||||
case 's':
|
||||
case 'S':
|
||||
subpars_sim = 1;
|
||||
continue;
|
||||
#endif
|
||||
case 'g':
|
||||
case 'G':
|
||||
strip_grammar = 1;
|
||||
continue;
|
||||
default:
|
||||
|
@ -120,6 +130,13 @@ main(argc,argv) register string argv[]; {
|
|||
|
||||
if (verbose) beg_sbrk = sbrk(0);
|
||||
|
||||
#ifdef NON_CORRECTING
|
||||
if ((subpars_sim) && (!non_corr)) {
|
||||
fprintf(stderr,"option -s illegal without -n, turned off\n");
|
||||
subpars_sim = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Now check wether the sets should include nonterminals
|
||||
*/
|
||||
|
@ -139,6 +156,12 @@ main(argc,argv) register string argv[]; {
|
|||
# ifndef NDEBUG
|
||||
}
|
||||
# endif
|
||||
#ifdef NON_CORRECTING
|
||||
if (non_corr) {
|
||||
nc_incl_file = libpath("nc_incl");
|
||||
nc_rec_file = libpath ("nc_rec");
|
||||
}
|
||||
#endif
|
||||
mktemp(f_temp);
|
||||
mktemp(f_pars);
|
||||
if ((fact = fopen(f_temp,"w")) == NULL) {
|
||||
|
@ -154,6 +177,10 @@ main(argc,argv) register string argv[]; {
|
|||
*/
|
||||
sprintf(f_include, HFILE, prefix ? prefix : "L");
|
||||
sprintf(f_rec, RFILE, prefix ? prefix : "L");
|
||||
#ifdef NON_CORRECTING
|
||||
if (non_corr)
|
||||
sprintf(f_nc, NCFILE, prefix ? prefix : "L");
|
||||
#endif
|
||||
setinit(ntneeded);
|
||||
maxnt = &nonterms[nnonterms];
|
||||
maxt = &tokens[ntokens];
|
||||
|
@ -216,7 +243,7 @@ readgrammar(argc,argv) char *argv[]; {
|
|||
/*
|
||||
* There must be a start symbol!
|
||||
*/
|
||||
if (start == 0) {
|
||||
if (! nerrors && start == 0) {
|
||||
fatal(linecount,"Missing %%start");
|
||||
}
|
||||
if (nerrors) comfatal();
|
||||
|
@ -237,7 +264,7 @@ doparse(p) register p_file p; {
|
|||
}
|
||||
|
||||
/* VARARGS1 */
|
||||
error(lineno,s,t,u) string s,t,u; {
|
||||
error(lineno,s,t,u) string s,t,u; {
|
||||
/*
|
||||
* Just an error message
|
||||
*/
|
||||
|
@ -250,7 +277,7 @@ error(lineno,s,t,u) string s,t,u; {
|
|||
}
|
||||
|
||||
/* VARARGS1 */
|
||||
warning(lineno,s,t,u) string s,t,u; {
|
||||
warning(lineno,s,t,u) string s,t,u; {
|
||||
/*
|
||||
* Just a warning
|
||||
*/
|
||||
|
@ -292,7 +319,7 @@ copyfile(file) string file; {
|
|||
register FILE *f;
|
||||
|
||||
if ((f = fopen(file,"r")) == NULL) {
|
||||
fatal(0,"Cannot open libraryfile, call an expert");
|
||||
fatal(0,"Cannot open library file %s, call an expert",file);
|
||||
}
|
||||
while ((c = getc(f)) != EOF) putc(c,fpars);
|
||||
fclose(f);
|
||||
|
|
|
@ -51,6 +51,9 @@ name_init() {
|
|||
nont_info.i_esize = sizeof (t_nont);
|
||||
nont_info.i_incr = 50;
|
||||
search(TERMINAL,"EOFILE",ENTERING);
|
||||
#ifdef NON_CORRECTING
|
||||
illegal_gram = search(TERMINAL,"LLILLEGAL",ENTERING);
|
||||
#endif
|
||||
}
|
||||
|
||||
STATIC p_entry
|
||||
|
@ -65,10 +68,13 @@ newentry(str, next) string str; p_entry next; {
|
|||
p->h_name = str;
|
||||
p->h_next = next;
|
||||
p->h_type.g_lineno = linecount;
|
||||
#ifdef NON_CORRECTING
|
||||
p->h_type.g_erroneous = 0;
|
||||
#endif
|
||||
return p;
|
||||
}
|
||||
|
||||
string
|
||||
string
|
||||
store(s) string s; {
|
||||
/*
|
||||
* Store a string s in the name table
|
||||
|
@ -147,14 +153,14 @@ search(type,str,option) register string str; {
|
|||
"%s : is already defined",str);
|
||||
}
|
||||
p->h_type.g_lineno = linecount;
|
||||
return &(p->h_type);
|
||||
return &(p->h_type);
|
||||
}
|
||||
}
|
||||
p = newentry(store(str), h_root[i]);
|
||||
h_root[i] = p;
|
||||
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;
|
||||
|
@ -166,7 +172,7 @@ search(type,str,option) register string str; {
|
|||
if (str[2] == '\0') {
|
||||
switch(str[1]) {
|
||||
case 'n' :
|
||||
val = '\n';
|
||||
val = '\n';
|
||||
break;
|
||||
case 'r' :
|
||||
val = '\r';
|
||||
|
@ -175,19 +181,19 @@ search(type,str,option) register string str; {
|
|||
val = '\b';
|
||||
break;
|
||||
case 'f' :
|
||||
val = '\f';
|
||||
val = '\f';
|
||||
break;
|
||||
case 't' :
|
||||
val = '\t';
|
||||
val = '\t';
|
||||
break;
|
||||
case '\'':
|
||||
val = '\'';
|
||||
val = '\'';
|
||||
break;
|
||||
case '\\':
|
||||
val = '\\';
|
||||
val = '\\';
|
||||
break;
|
||||
default :
|
||||
error(linecount,e_literal);
|
||||
error(linecount,e_literal);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
|
@ -200,7 +206,7 @@ search(type,str,option) register string str; {
|
|||
val = 64*str[1] - 73*'0' +
|
||||
8*str[2] + str[3];
|
||||
}
|
||||
} else {
|
||||
} else {
|
||||
/*
|
||||
* No escape in literal
|
||||
*/
|
||||
|
@ -221,7 +227,7 @@ search(type,str,option) register string str; {
|
|||
return &(p->h_type);
|
||||
}
|
||||
/*
|
||||
* type == NONTERM || type == UNKNOWN
|
||||
* type == NONTERM || type == UNKNOWN
|
||||
* UNKNOWN and not yet declared means : NONTERM
|
||||
*/
|
||||
{
|
||||
|
|
|
@ -15,11 +15,11 @@ LLOPT= # -vvv -x
|
|||
|
||||
OBJECTS = main.$(SUF) gencode.$(SUF) compute.$(SUF) LLgen.$(SUF) tokens.$(SUF) \
|
||||
check.$(SUF) reach.$(SUF) global.$(SUF) name.$(SUF) sets.$(SUF) \
|
||||
Lpars.$(SUF) alloc.$(SUF) machdep.$(SUF) cclass.$(SUF)
|
||||
Lpars.$(SUF) alloc.$(SUF) machdep.$(SUF) cclass.$(SUF) savegram.$(SUF)
|
||||
CSRC = $(SRC_DIR)/main.c $(SRC_DIR)/gencode.c $(SRC_DIR)/compute.c \
|
||||
$(SRC_DIR)/check.c $(SRC_DIR)/reach.c $(SRC_DIR)/global.c \
|
||||
$(SRC_DIR)/name.c $(SRC_DIR)/sets.c $(SRC_DIR)/alloc.c \
|
||||
$(SRC_DIR)/machdep.c $(SRC_DIR)/cclass.c
|
||||
$(SRC_DIR)/machdep.c $(SRC_DIR)/cclass.c $(SRC_DIR)/savegram.c
|
||||
CFILES = LLgen.c tokens.c Lpars.c $(CSRC)
|
||||
GFILES = $(SRC_DIR)/tokens.g $(SRC_DIR)/LLgen.g
|
||||
FILES = $(SRC_DIR)/types.h $(SRC_DIR)/extern.h \
|
||||
|
|
385
util/LLgen/src/savegram.c
Normal file
385
util/LLgen/src/savegram.c
Normal file
|
@ -0,0 +1,385 @@
|
|||
/* Copyright (c) 1991 by the Vrije Universiteit, Amsterdam, the Netherlands.
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#ifdef NON_CORRECTING
|
||||
|
||||
/*
|
||||
* L L G E N
|
||||
*
|
||||
* An Extended LL(1) Parser Generator
|
||||
*
|
||||
* Author : Ceriel J.H. Jacobs
|
||||
*/
|
||||
|
||||
/*
|
||||
* savegram.c
|
||||
* Save the input grammar for non-correcting error recovery
|
||||
*
|
||||
* Grammar rules are `flattened' by introducing anonymous nonterminals.
|
||||
* [B]? becomes X; X: B | {empty}
|
||||
* [B]+ becomes X: B Y; Y: X | {empty}
|
||||
* [B]* becomes X; X: B X | {empty}
|
||||
* [B | C] becomes X; X: B | C
|
||||
* [B | C]* becomes X; X: B X | C X | {empty} etc.
|
||||
*/
|
||||
|
||||
|
||||
# include "types.h"
|
||||
# include "extern.h"
|
||||
# include "io.h"
|
||||
# include "assert.h"
|
||||
# include "sets.h"
|
||||
|
||||
#define LLALT 9999
|
||||
|
||||
static int nt_highest;
|
||||
extern int nbytes;
|
||||
extern p_mem alloc();
|
||||
extern p_set start_firsts;
|
||||
extern p_set setalloc();
|
||||
extern p_gram search();
|
||||
|
||||
STATIC save_rule();
|
||||
STATIC save_set();
|
||||
|
||||
/* t_list will contain terms to be `flattened' */
|
||||
static struct t_list {
|
||||
p_term term;
|
||||
int t_nt_num;
|
||||
} *t_list;
|
||||
|
||||
/* Subparse list will contain symbols in %substart */
|
||||
static struct subparse_list {
|
||||
p_gram sub_action;
|
||||
int sub_nt_num;
|
||||
} *sub_list;
|
||||
|
||||
/* Index in t_list */
|
||||
static int t_list_index;
|
||||
|
||||
/* Index in subparse_list */;
|
||||
static int sub_list_index;
|
||||
|
||||
/* File to save grammar to */
|
||||
static FILE *fgram;
|
||||
|
||||
/* Nonterminal number to simulate parsers that get called in actions
|
||||
used when LLgen called with -n -s options */
|
||||
int act_nt;
|
||||
|
||||
save_grammar(f) FILE *f; {
|
||||
/*
|
||||
* Save the grammar
|
||||
*/
|
||||
register p_nont p;
|
||||
register p_start st;
|
||||
register int nt_nr;
|
||||
|
||||
fgram = f;
|
||||
|
||||
/* Compute highest nonterminal nr. */
|
||||
nt_highest = nnonterms + assval - 1;
|
||||
|
||||
|
||||
/* Generate some constants in the grammar file */
|
||||
|
||||
/* Allocate terms list */
|
||||
t_list = (struct t_list *) alloc((unsigned) nterms * sizeof(struct t_list));
|
||||
t_list_index = 0;
|
||||
|
||||
sub_list = (struct subparse_list *) alloc(nsubstarts * sizeof(struct subparse_list));
|
||||
|
||||
fputs("static ", fgram);
|
||||
fputs((prefix ? prefix : "LL"), fgram);
|
||||
fputs("grammar[] = {\n", fgram);
|
||||
|
||||
/* Check if -n -s option is on */
|
||||
if (subpars_sim) {
|
||||
|
||||
/* Allocate action simulation nt */
|
||||
|
||||
act_nt = ++nt_highest;
|
||||
|
||||
/* write simualtion rule */
|
||||
fprintf(fgram, "/* Simulation rule */\n");
|
||||
fprintf(fgram, "%d,\n", act_nt);
|
||||
|
||||
/* Put a firstset and a fake followset */
|
||||
/* Followset optimization is not implemented for
|
||||
-s because it would be hard, and does not
|
||||
bring enough improvement to jutify the effort
|
||||
*/
|
||||
save_set(start_firsts);
|
||||
save_set(start_firsts);
|
||||
/* Simulation rule procudes empty */
|
||||
fprintf(fgram, "%d,\n", 1);
|
||||
for (st = start; st; st = st->ff_next)
|
||||
{
|
||||
fprintf(fgram, "%d, %d, %d, \n", st->ff_nont + assval,
|
||||
act_nt, LLALT);
|
||||
}
|
||||
fprintf(fgram, "%d, \n", 0);
|
||||
|
||||
}
|
||||
|
||||
/* Now process all rules */
|
||||
for (p = nonterms, nt_nr = assval; p < maxnt; p++, nt_nr++) {
|
||||
fprintf(fgram, "/* nr. %d %s */\n", nt_nr, p->n_name);
|
||||
fprintf(fgram, "%d, ",nt_nr);
|
||||
if (! p->n_rule) { /* undefined */
|
||||
f_input = p->n_string;
|
||||
error(p->n_lineno,"Nonterminal %s not defined",
|
||||
p->n_name);
|
||||
}
|
||||
|
||||
/* Save the first_set and follow set */
|
||||
save_set(p->n_nc_first);
|
||||
save_set(p->n_nc_follow);
|
||||
|
||||
if (p->n_flags & EMPTY)
|
||||
fprintf(fgram, "%d,\n", 1);
|
||||
else
|
||||
fprintf(fgram, "%d,\n", 0);
|
||||
|
||||
save_rule(p->n_rule, 0);
|
||||
|
||||
fprintf(fgram, "%d,\n", 0);
|
||||
}
|
||||
|
||||
/* Resolve terms, they are on t_list */
|
||||
|
||||
fprintf(fgram, "/* Fresh nonterminals */\n");
|
||||
|
||||
{ int i;
|
||||
for (i = 0; i < t_list_index; i++)
|
||||
{
|
||||
|
||||
/* Terms of the form [] without + ? * or number produce
|
||||
a NIL pointer in the term-list */
|
||||
if ((t_list + i)->term == (struct term *) 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
fprintf(fgram, "%d, ", (t_list + i)->t_nt_num);
|
||||
|
||||
/* Save the first and follow sets */
|
||||
|
||||
save_set((t_list + i)->term->t_nc_first);
|
||||
save_set((t_list + i)->term->t_nc_follow);
|
||||
|
||||
/* NOTE: A VARIABLE REPETITION COUNT TERMS RULE IS NOT
|
||||
ALLOWED TO PRODUCE EMPTY IN LLGEN
|
||||
*/
|
||||
|
||||
switch(r_getkind((t_list + i)->term)) {
|
||||
case FIXED:
|
||||
/* Already done by repeating new nonterminal */
|
||||
|
||||
/* FIXED term-rule may produce empty */
|
||||
if (empty((t_list +i)->term->t_rule))
|
||||
fprintf(fgram, "%d,\n", 1);
|
||||
else
|
||||
fprintf(fgram, "%d,\n", 0);
|
||||
|
||||
save_rule((t_list + i)->term->t_rule, 0);
|
||||
fprintf(fgram, "%d,\n", 0);
|
||||
break;
|
||||
case STAR:
|
||||
/* Save the rule, appending the new lhs for this rule */
|
||||
|
||||
/* Star rules always produce empty */
|
||||
fprintf(fgram, "1,\n");
|
||||
|
||||
save_rule((t_list + i)->term->t_rule,
|
||||
(t_list + i)->t_nt_num);
|
||||
fprintf(fgram, "%d,\n%d,\n", LLALT, 0);
|
||||
/* ALT EMPTY*/
|
||||
break;
|
||||
case PLUS:
|
||||
/* Save the rule appending a fresh nonterminal */
|
||||
|
||||
fprintf(fgram, "%d,\n", 0);
|
||||
|
||||
save_rule((t_list + i)->term->t_rule, ++nt_highest);
|
||||
fprintf(fgram, "%d,\n", 0); /* EOR */
|
||||
fprintf(fgram, "%d, ", nt_highest);
|
||||
/* First set of the extra nonterm is same as
|
||||
for the term */
|
||||
/* Except that the new nonterm also produces empty ! */
|
||||
save_set((t_list + i)->term->t_nc_first);
|
||||
save_set((t_list + i)->term->t_nc_follow);
|
||||
fprintf(fgram, "1,\n");
|
||||
fprintf(fgram, "%d, ", (t_list+i)->t_nt_num);
|
||||
fprintf(fgram, "%d,\n%d,\n", LLALT, 0); /* ALT EMPTY */
|
||||
break;
|
||||
case OPT:
|
||||
fprintf(fgram, "1,\n");
|
||||
save_rule((t_list + i)->term->t_rule, 0);
|
||||
fprintf(fgram, "%d,\n%d,\n", LLALT, 0); /* ALT EMPTY */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Resolve %substarts */
|
||||
if (!subpars_sim) {
|
||||
int i,s,check;
|
||||
p_start ff, gg;
|
||||
p_set temp_set;
|
||||
|
||||
for (i = 0; i < sub_list_index; i++) {
|
||||
fprintf(fgram, "%d, ", (sub_list + i)->sub_nt_num);
|
||||
/* Compute the first set */
|
||||
temp_set = setalloc();
|
||||
for (ff = g_getsubparse((sub_list + i)->sub_action);
|
||||
ff; ff = ff->ff_next){
|
||||
s = setunion(temp_set,
|
||||
(&nonterms[ff->ff_nont])->n_first);
|
||||
check = 0;
|
||||
for (gg =start; gg; gg = gg->ff_next)
|
||||
if (ff->ff_nont == gg->ff_nont)
|
||||
check = 1;
|
||||
if (check == 0)
|
||||
warning((sub_list + i)->sub_action->g_lineno,
|
||||
"\"%s\" is not a startsymbol",
|
||||
(&nonterms[ff->ff_nont])->n_name);
|
||||
}
|
||||
save_set(temp_set);
|
||||
save_set(temp_set);
|
||||
free(temp_set);
|
||||
|
||||
/* Produces empty */
|
||||
fprintf(fgram, "1,\n");
|
||||
|
||||
ff = g_getsubparse((sub_list + i)->sub_action);
|
||||
|
||||
for (; ff; ff = ff->ff_next)
|
||||
fprintf(fgram, "%d, %d, %d, \n", ff->ff_nont + assval,
|
||||
(sub_list + i)->sub_nt_num,
|
||||
LLALT);
|
||||
fprintf(fgram, "%d, \n", 0);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fgram, "%d\n};\n", 0);
|
||||
fprintf(fgram, "#define LLNNONTERMINALS %d\n", nt_highest - assval + 1);
|
||||
}
|
||||
|
||||
STATIC
|
||||
save_rule(p, tail) register p_gram p; int tail; {
|
||||
/*
|
||||
Walk through rule p, saving it. The non-terminal tail is
|
||||
appended to the rule. It needs to be appended in this function
|
||||
to process alt-rules correctly. Tail == 0 means don't append.
|
||||
*/
|
||||
|
||||
int in_alt;
|
||||
int illegal_num;
|
||||
/* Processing an alt needs some special care. When processing the
|
||||
first alternative, we don't want to write the alt-code;
|
||||
When appending something to the alt, it needs to be appended to
|
||||
every alternative and not at the end of the rule.
|
||||
*/
|
||||
|
||||
/* Look up the ILLEGAL token number */
|
||||
illegal_num = tokens[g_getcont(illegal_gram)].t_tokno;
|
||||
|
||||
in_alt = 0;
|
||||
for (;;) {
|
||||
switch(g_gettype(p)) {
|
||||
case ALTERNATION :
|
||||
if (in_alt)
|
||||
fprintf(fgram, "%d,\n", LLALT);
|
||||
else
|
||||
in_alt = 1;
|
||||
save_rule(g_getlink(p)->l_rule, tail);
|
||||
break;
|
||||
case TERM :
|
||||
/* Make entry in term list */
|
||||
(t_list + t_list_index)->term = g_getterm(p);
|
||||
/* Test for [] without specifier */
|
||||
if (g_getterm(p) == (struct term *) 0) {
|
||||
t_list_index++;
|
||||
break;
|
||||
}
|
||||
(t_list + t_list_index++)->t_nt_num = ++nt_highest;
|
||||
fprintf(fgram, "%d, ", nt_highest);
|
||||
/* Check if repetition, if so handle here */
|
||||
if (r_getkind(g_getterm(p)) == FIXED)
|
||||
{
|
||||
int k;
|
||||
for (k = 1; k < r_getnum(g_getterm(p)); k++)
|
||||
fprintf(fgram, "%d, ", nt_highest);
|
||||
}
|
||||
break;
|
||||
case NONTERM :
|
||||
fprintf(fgram, "%d, ", g_getcont(p) + assval);
|
||||
break;
|
||||
case TERMINAL:
|
||||
if (g_getcont(p) == g_getcont(illegal_gram)) {
|
||||
/* %illegal. Ignore. */
|
||||
break;
|
||||
}
|
||||
if (p->g_erroneous)
|
||||
fprintf(fgram, "%d, ", illegal_num);
|
||||
else
|
||||
fprintf(fgram, "%d, ",
|
||||
tokens[g_getcont(p)].t_tokno);
|
||||
break;
|
||||
case LITERAL:
|
||||
if (p->g_erroneous)
|
||||
fprintf(fgram, "%d, ", illegal_num);
|
||||
else
|
||||
fprintf(fgram, "%d, ",
|
||||
tokens[g_getcont(p)].t_tokno);
|
||||
break;
|
||||
case ACTION:
|
||||
if (subpars_sim) {
|
||||
fprintf(fgram, "%d, ", act_nt);
|
||||
}
|
||||
else if (g_getsubparse(p)) {
|
||||
/* Allocate nonterminal that will simulate
|
||||
subparser
|
||||
*/
|
||||
(sub_list + sub_list_index)->sub_nt_num =
|
||||
++nt_highest;
|
||||
(sub_list + sub_list_index++)->sub_action = p;
|
||||
|
||||
fprintf(fgram, "%d, ", nt_highest);
|
||||
}
|
||||
break;
|
||||
case EORULE :
|
||||
if ((! in_alt) && tail )
|
||||
/* If this rule is not an alt, append tail now.
|
||||
If it is an alt, the recursive call of this function
|
||||
has appended tail to each alternative
|
||||
*/
|
||||
fprintf(fgram, "%d, ", tail);
|
||||
return;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
STATIC
|
||||
save_set(p) p_set p; {
|
||||
register int k;
|
||||
register unsigned i;
|
||||
int j;
|
||||
|
||||
j = nbytes;
|
||||
for (;;) {
|
||||
i = (unsigned) *p++;
|
||||
for (k = 0; k < sizeof(int); k++) {
|
||||
fprintf(fgram,"0%o,",(int)(i & 0377));
|
||||
i >>= 8;
|
||||
if (--j == 0) {
|
||||
fputs("\n",fgram);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
#endif
|
|
@ -31,7 +31,7 @@ extern p_set setalloc();
|
|||
extern p_set get_set();
|
||||
extern int setunion();
|
||||
extern int setintersect();
|
||||
extern setminus();
|
||||
extern setminus();
|
||||
extern int setempty();
|
||||
extern int findindex();
|
||||
extern int setcount();
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
/*
|
||||
* tokens.g
|
||||
* Defines the tokens for the grammar of LLgen.
|
||||
* The lexical analyser and LLmessage are also included here.
|
||||
* The lexical analyser and LLmessage are also included here.
|
||||
*/
|
||||
|
||||
{
|
||||
|
@ -30,7 +30,7 @@ static string rcsidc = "$Id$";
|
|||
|
||||
/* Here are defined : */
|
||||
extern int scanner();
|
||||
extern LLmessage();
|
||||
extern LLmessage();
|
||||
extern int input();
|
||||
extern unput();
|
||||
extern skipcomment();
|
||||
|
@ -39,12 +39,18 @@ STATIC linedirective();
|
|||
# endif
|
||||
STATIC string cpy();
|
||||
STATIC string vallookup();
|
||||
STATIC copyact();
|
||||
|
||||
static int nparams;
|
||||
}
|
||||
/* Classes */
|
||||
|
||||
%token C_IDENT ; /* lextoken.t_string contains the identifier read */
|
||||
%token C_IDENT ; /* lextoken.t_string contains the identifier read */
|
||||
%token C_NUMBER ; /* lextoken.t_num contains the number read */
|
||||
%token C_LITERAL ; /* lextoken.t_string contains the literal read */
|
||||
%token C_EXPR ; /* A C expression (%if or %while) */
|
||||
%token C_PARAMS ; /* formal or actual parameters */
|
||||
%token C_ACTION ; /* a C action */
|
||||
|
||||
/* Keywords */
|
||||
|
||||
|
@ -60,6 +66,9 @@ STATIC string vallookup();
|
|||
%token C_AVOID ;
|
||||
%token C_PREFER ;
|
||||
%token C_DEFAULT ;
|
||||
%token C_SUBSTART ;
|
||||
%token C_ERRONEOUS ;
|
||||
%token C_ILLEGAL ;
|
||||
|
||||
%lexical scanner ;
|
||||
|
||||
|
@ -80,26 +89,143 @@ typedef struct keyword {
|
|||
*/
|
||||
|
||||
static t_keyw resword[] = {
|
||||
{ "token", C_TOKEN },
|
||||
{ "avoid", C_AVOID },
|
||||
{ "token", C_TOKEN },
|
||||
{ "avoid", C_AVOID },
|
||||
{ "prefer", C_PREFER },
|
||||
{ "persistent", C_PERSISTENT },
|
||||
{ "default", C_DEFAULT },
|
||||
{ "if", C_IF },
|
||||
{ "while", C_WHILE },
|
||||
{ "first", C_FIRST },
|
||||
{ "start", C_START },
|
||||
{ "if", C_IF },
|
||||
{ "while", C_WHILE },
|
||||
{ "first", C_FIRST },
|
||||
{ "start", C_START },
|
||||
{ "lexical", C_LEXICAL },
|
||||
{ "onerror", C_ONERROR },
|
||||
{ "prefix", C_PREFIX },
|
||||
{ 0, 0 }
|
||||
#ifdef NON_CORRECTING
|
||||
{ "substart", C_SUBSTART },
|
||||
{ "erroneous", C_ERRONEOUS },
|
||||
{ "illegal", C_ILLEGAL },
|
||||
#endif
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
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 */
|
||||
static int nostartline; /* = 0 if at the start of a line */
|
||||
# endif
|
||||
|
||||
STATIC
|
||||
copyact(ch1,ch2,flag,level) char ch1,ch2; {
|
||||
/*
|
||||
* Copy an action to file f. Opening bracket is ch1, closing bracket
|
||||
* is ch2.
|
||||
* If flag & 1, copy opening and closing parameters too.
|
||||
* If flag & 2, don't allow ','.
|
||||
*/
|
||||
static int text_seen = 0;
|
||||
register FILE *f;
|
||||
register ch; /* Current char */
|
||||
register match; /* used to read strings */
|
||||
int saved = linecount;
|
||||
/* save linecount */
|
||||
int sav_strip = strip_grammar;
|
||||
|
||||
f = fact;
|
||||
if (ch1 == '{' || flag != 1) strip_grammar = 0;
|
||||
if (!level) {
|
||||
text_seen = 0;
|
||||
nparams = 0; /* count comma's */
|
||||
putc('\0',f);
|
||||
fprintf(f,"# line %d \"%s\"\n", linecount,f_input);
|
||||
}
|
||||
if (level || (flag & 1)) putc(ch1,f);
|
||||
for (;;) {
|
||||
ch = input();
|
||||
if (ch == ch2) {
|
||||
if (!level) {
|
||||
if (text_seen) nparams++;
|
||||
}
|
||||
if (level || (flag & 1)) putc(ch,f);
|
||||
if (strip_grammar != sav_strip) {
|
||||
if (ch1 == '{' || flag != 1) putchar(ch);
|
||||
}
|
||||
strip_grammar = sav_strip;
|
||||
return;
|
||||
}
|
||||
switch(ch) {
|
||||
case ')':
|
||||
case '}':
|
||||
case ']':
|
||||
error(linecount,"Parentheses mismatch");
|
||||
break;
|
||||
case '(':
|
||||
text_seen = 1;
|
||||
copyact('(',')',flag,level+1);
|
||||
continue;
|
||||
case '{':
|
||||
text_seen = 1;
|
||||
copyact('{','}',flag,level+1);
|
||||
continue;
|
||||
case '[':
|
||||
text_seen = 1;
|
||||
copyact('[',']',flag,level+1);
|
||||
continue;
|
||||
case '/':
|
||||
ch = input();
|
||||
unput(ch);
|
||||
if (ch == '*') {
|
||||
putc('/', f);
|
||||
skipcomment(1);
|
||||
continue;
|
||||
}
|
||||
ch = '/';
|
||||
text_seen = 1;
|
||||
break;
|
||||
case ';':
|
||||
case ',':
|
||||
if (! level && text_seen) {
|
||||
text_seen = 0;
|
||||
nparams++;
|
||||
if (ch == ',' && (flag & 2)) {
|
||||
warning(linecount, "Parameters may not be separated with a ','");
|
||||
ch = ';';
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '\'':
|
||||
case '"' :
|
||||
/*
|
||||
* watch out for brackets in strings, they do not
|
||||
* count !
|
||||
*/
|
||||
text_seen = 1;
|
||||
match = ch;
|
||||
putc(ch,f);
|
||||
while((ch = input())) {
|
||||
if (ch == match) break;
|
||||
if (ch == '\\') {
|
||||
putc(ch,f);
|
||||
ch = input();
|
||||
}
|
||||
if (ch == '\n') {
|
||||
error(linecount,"Newline in string");
|
||||
unput(match);
|
||||
}
|
||||
putc(ch,f);
|
||||
}
|
||||
if (ch == match) break;
|
||||
/* Fall through */
|
||||
case EOF :
|
||||
if (!level) error(saved,"Action does not terminate");
|
||||
strip_grammar = sav_strip;
|
||||
return;
|
||||
default:
|
||||
if (c_class[ch] != ISSPA) text_seen = 1;
|
||||
}
|
||||
putc(ch,f);
|
||||
}
|
||||
}
|
||||
|
||||
scanner() {
|
||||
/*
|
||||
* Lexical analyser, what else
|
||||
|
@ -108,7 +234,11 @@ scanner() {
|
|||
register char *p = ltext;
|
||||
int reserved = 0; /* reserved word? */
|
||||
char *max = <ext[LTEXTSZ - 1];
|
||||
static int nextexpr;
|
||||
int expect_expr = nextexpr;
|
||||
long off;
|
||||
|
||||
nextexpr = 0;
|
||||
if (savedtok.t_tokno) {
|
||||
/* A token has been inserted.
|
||||
* Now deliver the last lextoken again
|
||||
|
@ -127,6 +257,21 @@ scanner() {
|
|||
}
|
||||
# endif
|
||||
switch(c_class[ch]) {
|
||||
case ISACT :
|
||||
if (ch == '{') {
|
||||
copyact('{', '}', in_production, 0);
|
||||
return C_ACTION;
|
||||
}
|
||||
assert(ch == '(');
|
||||
if (expect_expr) {
|
||||
copyact('(', ')', 1, 0);
|
||||
return C_EXPR;
|
||||
}
|
||||
off = ftell(fact);
|
||||
copyact('(', ')', in_production != 0 ? 0 : 2, 0);
|
||||
if (nparams == 0) fseek(fact, off, 0);
|
||||
lextoken.t_num = nparams;
|
||||
return C_PARAMS;
|
||||
case ISLIT :
|
||||
for (;;) {
|
||||
ch = input();
|
||||
|
@ -177,7 +322,7 @@ scanner() {
|
|||
unput(ch);
|
||||
*p = '\0';
|
||||
if (reserved) { /*
|
||||
* Now search for the keyword
|
||||
* Now search for the keyword
|
||||
*/
|
||||
register p_keyw w;
|
||||
|
||||
|
@ -187,6 +332,10 @@ scanner() {
|
|||
/*
|
||||
* Return token number.
|
||||
*/
|
||||
if (w->w_value == C_IF ||
|
||||
w->w_value == C_WHILE) {
|
||||
nextexpr = 1;
|
||||
}
|
||||
return w->w_value;
|
||||
}
|
||||
w++;
|
||||
|
@ -208,11 +357,11 @@ input() {
|
|||
*/
|
||||
register c;
|
||||
|
||||
if (c = backupc) {
|
||||
if (c = backupc) {
|
||||
/* Last char was "unput()". Deliver it again
|
||||
*/
|
||||
backupc = 0;
|
||||
return c;
|
||||
return c;
|
||||
}
|
||||
if ((c = getc(finput)) == EOF) {
|
||||
nonline = 0;
|
||||
|
@ -337,7 +486,7 @@ cpy(s,p,inserted) register string p; {
|
|||
register string t = 0;
|
||||
|
||||
switch(s) {
|
||||
case C_IDENT :
|
||||
case C_IDENT :
|
||||
if (!inserted) t = lextoken.t_string;
|
||||
else t = "identifier";
|
||||
break;
|
||||
|
@ -353,7 +502,7 @@ cpy(s,p,inserted) register string p; {
|
|||
t = "literal";
|
||||
break;
|
||||
case EOFILE :
|
||||
t = "endoffile";
|
||||
t = "end-of-file";
|
||||
break;
|
||||
}
|
||||
if (!t && (t = vallookup(s))) {
|
||||
|
@ -382,13 +531,15 @@ cpy(s,p,inserted) register string p; {
|
|||
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++='0'+(s&07);
|
||||
}
|
||||
}
|
||||
*p++ = '\'';
|
||||
return p;
|
||||
}
|
||||
|
||||
string strcpy();
|
||||
|
||||
LLmessage(d) {
|
||||
/*
|
||||
* d is either 0, in which case the current token has been deleted,
|
||||
|
@ -400,9 +551,16 @@ LLmessage(d) {
|
|||
|
||||
nerrors++;
|
||||
s = buf;
|
||||
if (d == 0) {
|
||||
s = cpy(LLsymb,s,0);
|
||||
if (d < 0) {
|
||||
strcpy(buf, "end-of-file expected");
|
||||
}
|
||||
else if (d == 0) {
|
||||
#ifdef LLNONCORR
|
||||
t = " unexpected";
|
||||
#else
|
||||
t = " deleted";
|
||||
#endif
|
||||
s = cpy(LLsymb,s,0);
|
||||
do *s++ = *t; while (*t++);
|
||||
} else {
|
||||
s = cpy(d,s,1);
|
||||
|
@ -411,12 +569,7 @@ LLmessage(d) {
|
|||
s = cpy(LLsymb,s,0);
|
||||
*s = '\0';
|
||||
}
|
||||
error(linecount, "%s", buf);
|
||||
/* Don't change this line to
|
||||
* error(linecount, buf).
|
||||
* The string in "buf" might contain '%' ...
|
||||
*/
|
||||
if (d) { /*
|
||||
if (d > 0) { /*
|
||||
* Save the current token and make up some
|
||||
* attributes for the inserted token
|
||||
*/
|
||||
|
@ -426,5 +579,17 @@ LLmessage(d) {
|
|||
else if (d == C_LITERAL) lextoken.t_string = "dummy_literal";
|
||||
else if (d == C_NUMBER) lextoken.t_num = 1;
|
||||
}
|
||||
#ifdef LLNONCORR
|
||||
else
|
||||
#endif
|
||||
error(linecount, "%s", buf);
|
||||
/* Don't change this line to
|
||||
* error(linecount, buf).
|
||||
* The string in "buf" might contain '%' ...
|
||||
*/
|
||||
#ifdef LLNONCORR
|
||||
in_production = 1;
|
||||
/* To prevent warnings from copyact */
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,12 +40,20 @@ typedef struct token {
|
|||
* structure for the grammar elements
|
||||
*/
|
||||
typedef struct gram {
|
||||
short x; /* for lay-out see comment below */
|
||||
short g_lineno; /* element found on this line number */
|
||||
int x; /* for lay-out see comment below */
|
||||
int g_lineno; /* element found on this line number */
|
||||
#ifdef NON_CORRECTING
|
||||
int g_erroneous; /* 1 if element declared erroneous */
|
||||
#endif
|
||||
union {
|
||||
int g_index;
|
||||
struct term * g_term;
|
||||
struct link * g_link;
|
||||
#ifdef NON_CORRECTING
|
||||
/* If this is an action with a %substart g_subparse
|
||||
points to the list of startsymbols of the subparser */
|
||||
struct ff_firsts *g_subparse;
|
||||
#endif
|
||||
} g_i;
|
||||
} t_gram,*p_gram;
|
||||
|
||||
|
@ -78,7 +86,10 @@ typedef struct gram {
|
|||
# define g_setterm(p,s) ((p)->g_i.g_term = (s))
|
||||
# define g_setlink(p,s) ((p)->g_i.g_link = (s))
|
||||
# define g_setnpar(p,s) { assert(((unsigned)(s))<=017);(p)->x=((p)->x&~0170)|((s)<<3);}
|
||||
|
||||
#ifdef NON_CORRECTING
|
||||
# define g_getsubparse(p) ((p)->g_i.g_subparse)
|
||||
# define g_setsubparse(p,s) ((p)->g_i.g_subparse = (s))
|
||||
#endif
|
||||
/*
|
||||
* Some constants to communicate with the symbol table search routine
|
||||
*/
|
||||
|
@ -101,7 +112,7 @@ typedef struct gram {
|
|||
* nonterminal structure
|
||||
*/
|
||||
typedef struct {
|
||||
short n_flags; /* low order four bits are reserved
|
||||
int n_flags; /* low order four bits are reserved
|
||||
* the parameter count
|
||||
*/
|
||||
# define getntparams(p) ((p)->n_flags&017)
|
||||
|
@ -110,7 +121,7 @@ typedef struct {
|
|||
# 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 LOCALS 020000 /* local declarations ? */
|
||||
# define REACHABLE 040000 /* can this nonterminal be reached ? */
|
||||
# define VERBOSE 0100000 /* Set if in LL.output file */
|
||||
char n_insafety;
|
||||
|
@ -119,8 +130,8 @@ typedef struct {
|
|||
# define setntsafe(p,i) {assert(((unsigned)(i))<=NOSAFETY);(p)->n_insafety=(i);}
|
||||
# define getntout(p) ((p)->n_outsafety)
|
||||
# define setntout(p,i) {assert(((unsigned)(i))<=NOSAFETY);(p)->n_outsafety=(i);}
|
||||
short n_count; /* pieces of code before this rule */
|
||||
short n_lineno; /* declared on line ... */
|
||||
int n_count; /* pieces of code before this rule */
|
||||
int n_lineno; /* declared on line ... */
|
||||
p_gram n_rule; /* pointer to right hand side of rule */
|
||||
union {
|
||||
p_set n_f; /* ptr to "first" set */
|
||||
|
@ -131,6 +142,10 @@ typedef struct {
|
|||
} n_x;
|
||||
# define n_first n_x.n_f
|
||||
# define n_string n_x.n_s
|
||||
#ifdef NON_CORRECTING
|
||||
p_set n_nc_first; /* Pointer to non-corr first set */
|
||||
p_set n_nc_follow; /* Pointer to non-corr follow set */
|
||||
#endif
|
||||
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 */
|
||||
|
@ -138,7 +153,7 @@ typedef struct {
|
|||
long n_off; /* index of parameters in action file */
|
||||
} t_nont, *p_nont;
|
||||
|
||||
/*
|
||||
/*
|
||||
* hash table structure
|
||||
*/
|
||||
typedef struct h_entry {
|
||||
|
@ -161,13 +176,16 @@ typedef struct link {
|
|||
*/
|
||||
p_gram l_rule; /* pointer to this rule */
|
||||
p_set l_symbs; /* set, when to take this rule */
|
||||
#ifdef NON_CORRECTING
|
||||
p_set l_nc_symbs;
|
||||
#endif
|
||||
p_set l_others; /* set, when to take another rule */
|
||||
} t_link, *p_link;
|
||||
|
||||
/*
|
||||
* Structure for a repitition specification
|
||||
*/
|
||||
typedef short t_reps,*p_reps;
|
||||
typedef int t_reps,*p_reps;
|
||||
|
||||
# define FIXED 00 /* a fixed number */
|
||||
# define STAR 01 /* 0 or more times */
|
||||
|
@ -187,7 +205,7 @@ typedef short t_reps,*p_reps;
|
|||
*/
|
||||
typedef struct term {
|
||||
t_reps t_repeats;
|
||||
short t_flags; /* Low order three bits for safety */
|
||||
int 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 */
|
||||
|
@ -199,6 +217,10 @@ 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 */
|
||||
#ifdef NON_CORRECTING
|
||||
p_set t_nc_first; /* set of non corr firsts */
|
||||
p_set t_nc_follow; /* set of non corr followers */
|
||||
#endif
|
||||
p_set t_contains; /* contains set */
|
||||
} t_term, *p_term;
|
||||
|
||||
|
|
Loading…
Reference in a new issue