1 /* Copyright (c) 1991 by the Vrije Universiteit, Amsterdam, the Netherlands.
2 * For full copyright and restrictions on use see the file COPYING in the top
3 * level of the LLgen tree.
9 * An Extended LL(1) Parser Generator
11 * Author : Ceriel J.H. Jacobs
16 * Defines the grammar of LLgen.
17 * Some routines that build the internal structure are also included
28 static string rcsid = "$Id: LLgen.g,v 2.28 1997/02/21 11:27:38 ceriel Exp $";
30 p_mem alloc(), ralloc();
35 static int acount; /* count #of global actions */
38 static p_gram alt_table;
43 static p_gram rule_table;
48 /* Here are defined : */
53 STATIC p_gram copyrule();
54 /* and of course LLparse() */
61 nonterms[porder].n_next = index;
65 nonterms[porder].n_next = -1;
73 tokens[porder].t_next = index;
77 tokens[porder].t_next = -1;
82 alt_table = (p_gram )alloc(ALTINCR*sizeof(t_gram));
85 rule_table = (p_gram )alloc(RULEINCR*sizeof(t_gram));
94 spec : { acount = 0; p_init(); }
97 * Put an endmarker in temporary file
101 free((p_mem) rule_table);
102 free((p_mem) alt_table);
106 def { register string p; }
111 | C_TOKEN listel [ ',' listel ]* ';'
113 * A token declaration
116 { p = store(lextoken.t_string); }
119 * A start symbol declaration
122 * Put the declaration in the list
125 register p_gram temp;
128 temp = search(NONTERM,lextoken.t_string,BOTH);
129 ff = (p_start) alloc(sizeof(t_start));
130 ff->ff_nont = g_getcont(temp);
134 while (ff = ff->ff_next) {
135 if (! strcmp(p, ff->ff_name)) {
136 error(linecount, "\"%s\" already used in a %%start", p);
144 * Declaration of a name for the lexical analyser.
145 * May appear only once
148 lexical = store(lextoken.t_string);
150 else error(linecount,"Duplicate %%lexical");
155 * Prefix of external names (default: LL)
158 prefix = store(lextoken.t_string);
159 if (strlen(prefix) > 6) {
161 "%%prefix too long");
165 else error(linecount,"Duplicate %%prefix");
170 #ifdef NON_CORRECTING
172 warning(linecount, "%%onerror conflicts with -n option");
177 onerror = store(lextoken.t_string);
179 else error(linecount,"Duplicate %%onerror");
182 | C_ACTION { acount++; }
184 * A global C-declaration
188 * declarations for macros
192 listel : C_IDENT { p_gram temp = search(TERMINAL,lextoken.t_string,ENTERING);
193 newtorder(g_getcont(temp));
194 tokens[g_getcont(temp)].t_lineno = linecount;
198 rule { register p_nont p;
200 register p_gram temp;
203 * grammar for a production rule
205 C_IDENT { temp = search(NONTERM,lextoken.t_string,BOTH);
206 p = &nonterms[g_getcont(temp)];
209 "Nonterminal %s already defined", lextoken.t_string);
212 * Remember the order in which the nonterminals
213 * were defined. Code must be generated in that
214 * order to keep track with the actions on the
217 newnorder(p - nonterms);
220 p->n_lineno = linecount;
221 p->n_off = ftell(fact);
223 [ C_PARAMS { if (lextoken.t_num > 0) {
224 p->n_flags |= PARAMS;
225 if (lextoken.t_num > 15) {
226 error(linecount,"Too many parameters");
228 else setntparams(p,lextoken.t_num);
232 [ C_ACTION { p->n_flags |= LOCALS; }
234 ':' { in_production = 1; }
236 { in_production = 0; }
238 * Do not use p->n_rule now! The nonterms array
239 * might have been re-allocated.
241 { nonterms[g_getcont(temp)].n_rule = rr;}
244 productions(p_gram *p;)
246 * One or more alternatives
255 { o_lc = linecount; }
256 simpleproduction(p,&conflres)
257 { if (conflres & DEF) haddefault = 1; }
259 [ '|' { n_lc = linecount; }
260 simpleproduction(&prod,&t)
261 { if (n_alts >= max_alts-2) {
262 alt_table = (p_gram ) ralloc(
264 (unsigned)(max_alts+=ALTINCR)*sizeof(t_gram));
269 "More than one %%default in alternation");
273 mkalt(*p,conflres,o_lc,&alt_table[n_alts++]);
280 ]+ { if (conflres & (COND|PREFERING|AVOIDING)) {
282 "Resolver on last alternative not allowed");
284 mkalt(*p,conflres,n_lc,&alt_table[n_alts++]);
286 g_settype((&alt_table[n_alts]),EORULE);
287 *p = copyrule(&alt_table[n_alts-altcnt],altcnt+1);
290 { if (conflres & (COND|PREFERING|AVOIDING)) {
292 "No alternation conflict resolver allowed here");
295 if (conflres & DEF) {
297 "No %%default allowed here");
302 { n_alts -= altcnt; }
307 mkalt(prod,condition,lc,res) p_gram prod; register p_gram res; {
309 * Create an alternation and initialise it.
317 list = (p_link) alloc(50 * sizeof(t_link));
322 l->l_flag = condition;
324 g_settype(res,ALTERNATION);
330 simpleproduction(p_gram *p; register int *conflres;)
336 [ C_DEFAULT { *conflres |= DEF; }
340 * Optional conflict reslover
342 C_IF C_EXPR { *conflres |= COND; }
343 | C_PREFER { *conflres |= PREFERING; }
344 | C_AVOID { *conflres |= AVOIDING; }
347 #ifdef NON_CORRECTING
348 if (n_rules >= max_rules-2) {
349 rule_table = (p_gram) ralloc(
351 (unsigned)(max_rules+=RULEINCR)*sizeof(t_gram));
354 rule_table[n_rules++] =
355 *search(TERMINAL, "LLILLEGAL", BOTH);
356 if (*conflres & DEF) {
357 error(linecount, "%%illegal not allowed in %%default rule");
362 [ %persistent elem(&elem)
363 { if (n_rules >= max_rules-2) {
364 rule_table = (p_gram) ralloc(
366 (unsigned)(max_rules+=RULEINCR)*sizeof(t_gram));
371 [ repeats(&kind, &cnt)
372 { if (g_gettype(&elem) != TERM) {
373 rule_table[n_rules] = elem;
374 g_settype((&rule_table[n_rules+1]),EORULE);
375 mkterm(copyrule(&rule_table[n_rules],2),
382 { if (g_gettype(&elem) == TERM) {
383 register p_term q = g_getterm(&elem);
385 if (! (q->t_flags & RESOLVER) &&
386 g_gettype(q->t_rule) != ALTERNATION &&
387 g_gettype(q->t_rule) != EORULE) {
388 while (g_gettype(q->t_rule) != EORULE) {
389 rule_table[n_rules++] = *q->t_rule++;
391 if (n_rules >= max_rules-2) {
392 rule_table = (p_gram) ralloc(
394 (unsigned)(max_rules+=RULEINCR)*sizeof(t_gram));
397 elem = *--(q->t_rule);
400 if (q == t_list - 1) {
409 ] { if (!termdeleted && g_gettype(&elem) == TERM) {
412 q = g_getterm(&elem);
415 if ((q->t_flags & RESOLVER) &&
416 (kind == PLUS || kind == FIXED)) {
418 "%%while not allowed in this term");
421 * A persistent fixed term is the same
422 * as a non-persistent fixed term.
423 * Should we complain?
424 if ((q->t_flags & PERSISTENT) &&
427 "Illegal %%persistent");
433 rule_table[n_rules++] = elem;
435 ]* { register p_term q;
437 g_settype((&rule_table[n_rules]),EORULE);
440 if (g_gettype(&rule_table[n_rules]) == TERM &&
442 q = g_getterm(&rule_table[n_rules]);
443 if (r_getkind(q) == FIXED &&
448 if (!*p) *p = copyrule(&rule_table[n_rules],
455 mkterm(prod,flags,lc,result) p_gram prod; register p_gram result; {
457 * Create a term, initialise it and return
458 * a grammar element containing it
464 t_list = (p_term) alloc(50 * sizeof(t_term));
471 g_settype(result,TERM);
473 result->g_lineno = lc;
478 elem (register p_gram pres;)
479 { register int t = 0;
483 #ifdef NON_CORRECTING
487 '[' { ln = linecount; }
488 [ C_WHILE C_EXPR { t |= RESOLVER; }
490 [ C_PERSISTENT { t |= PERSISTENT; }
494 mkterm(p1,t,ln,pres);
498 #ifdef NON_CORRECTING
505 C_IDENT { pe = search(UNKNOWN,lextoken.t_string,BOTH);
507 #ifdef NON_CORRECTING
509 if (g_gettype(pres) != TERMINAL){
511 "Erroneous only allowed on terminal");
515 pres->g_erroneous = 1;
520 [ C_PARAMS { if (lextoken.t_num > 15) {
521 error(linecount,"Too many parameters");
522 } else g_setnpar(pres,lextoken.t_num);
523 if (g_gettype(pres) == TERMINAL) {
525 "Terminal with parameters");
529 | C_LITERAL { pe = search(LITERAL,lextoken.t_string,BOTH);
531 #ifdef NON_CORRECTING
533 pres->g_erroneous = 1;
537 | { g_settype(pres,ACTION);
538 pres->g_lineno = linecount;
539 #ifdef NON_CORRECTING
540 g_setsubparse(pres, (p_start) 0);
547 #ifdef NON_CORRECTING
554 #ifdef NON_CORRECTING
555 register p_gram temp;
556 register p_start subp;
558 temp = search(NONTERM,lextoken.t_string,BOTH);
559 subp = (p_start) alloc (sizeof(t_start));
561 subp->ff_nont = g_getcont(temp);
562 subp->ff_name = (string) 0;
563 subp->ff_next = (p_start) 0;
564 g_setsubparse(pres, subp);
570 #ifdef NON_CORRECTING
571 register p_gram temp;
574 temp = search(NONTERM,lextoken.t_string,BOTH);
576 ff = g_getsubparse(pres);
578 if (ff->ff_nont == g_getcont(temp)) {
579 warning(linecount, "\"%s\" used twice in %%substart", lextoken.t_string);
586 ff = (p_start) alloc(sizeof(t_start));
587 ff->ff_nont = g_getcont(temp);
588 ff->ff_name = (string) 0;
589 ff->ff_next = g_getsubparse(pres);
590 g_setsubparse(pres, ff);
600 repeats(int *kind; int *cnt;) { int t1 = 0; } :
603 | [ '*' { *kind = STAR; }
604 | '+' { *kind = PLUS; }
609 if (*kind == STAR) *kind = OPT;
610 if (*kind == PLUS) *kind = FIXED;
619 { *t = lextoken.t_num;
620 if (*t <= 0 || *t >= 8192) {
621 error(linecount,"Illegal number");
626 firsts { register string p; }
628 { p = store(lextoken.t_string); }
631 * Store this %first in the list belonging
637 temp = search(NONTERM,lextoken.t_string,BOTH);
638 ff = (p_first) alloc(sizeof(t_first));
639 ff->ff_nont = g_getcont(temp);
641 ff->ff_next = pfile->f_firsts;
642 pfile->f_firsts = ff;
648 copyrule(p,length) register p_gram p; {
650 * Returns a pointer to a grammar rule that was created in
651 * p. The space pointed to by p can now be reused
656 t = (p_gram) alloc((unsigned) length * sizeof(t_gram));