summaryrefslogtreecommitdiff
path: root/rules.y
diff options
context:
space:
mode:
Diffstat (limited to 'rules.y')
-rw-r--r--rules.y1689
1 files changed, 1689 insertions, 0 deletions
diff --git a/rules.y b/rules.y
new file mode 100644
index 0000000..cca58d7
--- /dev/null
+++ b/rules.y
@@ -0,0 +1,1689 @@
+/* Miranda token declarations and syntax rules for "YACC" */
+
+/**************************************************************************
+ * Copyright (C) Research Software Limited 1985-90. All rights reserved. *
+ * The Miranda system is distributed as free software under the terms in *
+ * the file "COPYING" which is included in the distribution. *
+ * *
+ * Revised to C11 standard and made 64bit compatible, January 2020 *
+ *------------------------------------------------------------------------*/
+
+/* miranda symbols */
+
+%token VALUE EVAL WHERE IF TO LEFTARROW COLONCOLON COLON2EQ
+ TYPEVAR NAME CNAME CONST DOLLAR2 OFFSIDE ELSEQ
+ ABSTYPE WITH DIAG EQEQ FREE INCLUDE EXPORT TYPE
+ OTHERWISE SHOWSYM PATHNAME BNF LEX ENDIR ERRORSY ENDSY
+ EMPTYSY READVALSY LEXDEF CHARCLASS ANTICHARCLASS LBEGIN
+
+%right ARROW
+%right PLUSPLUS ':' MINUSMINUS
+%nonassoc DOTDOT
+%right VEL
+%right '&'
+%nonassoc '>' GE '=' NE LE '<'
+%left '+' '-'
+%left '*' '/' REM DIV
+%right '^'
+%left '.' /* fiddle to make '#' behave */
+%left '!'
+%right INFIXNAME INFIXCNAME
+%token CMBASE /* placeholder to start combinator values - see combs.h */
+
+%{
+/* the following definition has to be kept in line with the token declarations
+ above */
+char *yysterm[]= {
+ 0,
+ "VALUE",
+ "EVAL",
+ "where",
+ "if",
+ "&>",
+ "<-",
+ "::",
+ "::=",
+ "TYPEVAR",
+ "NAME",
+ "CONSTRUCTOR-NAME",
+ "CONST",
+ "$$",
+ "OFFSIDE",
+ "OFFSIDE =",
+ "abstype",
+ "with",
+ "//",
+ "==",
+ "%free",
+ "%include",
+ "%export",
+ "type",
+ "otherwise",
+ "show",
+ "PATHNAME",
+ "%bnf",
+ "%lex",
+ "%%",
+ "error",
+ "end",
+ "empty",
+ "readvals",
+ "NAME",
+ "`char-class`",
+ "`char-class`",
+ "%%begin",
+ "->",
+ "++",
+ "--",
+ "..",
+ "\\/",
+ ">=",
+ "~=",
+ "<=",
+ "mod",
+ "div",
+ "$NAME",
+ "$CONSTRUCTOR"};
+
+%}
+
+/* Miranda syntax rules */
+/* the associated semantic actions perform the compilation */
+
+%{
+#include "data.h"
+#include "big.h"
+#include "lex.h"
+extern word nill,k_i,Void;
+extern word message,standardout;
+extern word big_one;
+#define isltmess_t(t) (islist_t(t)&&tl[t]==message)
+#define isstring_t(t) (islist_t(t)&&tl[t]==char_t)
+extern word SYNERR,errs,echoing,gvars;
+extern word listdiff_fn,indent_fn,outdent_fn;
+word lastname=0;
+word suppressids=NIL;
+word idsused=NIL;
+word tvarscope=0;
+word includees=NIL,embargoes=NIL,exportfiles=NIL,freeids=NIL,exports=NIL;
+word lexdefs=NIL,lexstates=NIL,inlex=0,inexplist=0;
+word inbnf=0,col_fn=0,fnts=NIL,eprodnts=NIL,nonterminals=NIL,sreds=0;
+word ihlist=0,ntspecmap=NIL,ntmap=NIL,lasth=0;
+word obrct=0;
+
+void evaluate(x)
+word x;
+{ word t;
+ t=type_of(x);
+ if(t==wrong_t)return;
+ lastexp=x;
+ x=codegen(x);
+ if(polyshowerror)return;
+ if(process())
+ /* setup new process for each evaluation */
+ { (void)signal(SIGINT,(sighandler)dieclean);
+ /* if interrupted will flush output etc before going */
+ compiling=0;
+ resetgcstats();
+ output(isltmess_t(t)?x:
+ cons(ap(standardout,isstring_t(t)?x
+ :ap(mkshow(0,0,t),x)),NIL));
+ (void)signal(SIGINT,SIG_IGN);/* otherwise could do outstats() twice */
+ putchar('\n');
+ outstats();
+ exit(0); }
+}
+
+void obey(x) /* like evaluate but no fork, no stats, no extra '\n' */
+word x;
+{ word t=type_of(x);
+ x=codegen(x);
+ if(polyshowerror)return;
+ compiling=0;
+ output(isltmess_t(t)?x:
+ cons(ap(standardout,isstring_t(t)?x:ap(mkshow(0,0,t),x)),NIL));
+}
+
+int isstring(x)
+word x;
+{ return(x==NILS||tag[x]==CONS&&is_char(hd[x]));
+}
+
+word compose(x) /* used in compiling 'cases' */
+word x;
+{ word y=hd[x];
+ if(hd[y]==OTHERWISE)y=tl[y]; /* OTHERWISE was just a marker - lose it */
+ else y=tag[y]==LABEL?label(hd[y],ap(tl[y],FAIL)):
+ ap(y,FAIL); /* if all guards false result is FAIL */
+ x = tl[x];
+ if(x!=NIL)
+ { while(tl[x]!=NIL)y=label(hd[hd[x]],ap(tl[hd[x]],y)), x=tl[x];
+ y=ap(hd[x],y);
+ /* first alternative has no label - label of enclosing rhs applies */
+ }
+ return(y);
+}
+
+int eprod(word);
+
+word starts(x) /* x is grammar rhs - returns list of nonterminals in start set */
+word x;
+{ L: switch(tag[x])
+ { case ID: return(cons(x,NIL));
+ case LABEL:
+ case LET:
+ case LETREC: x=tl[x]; goto L;
+ case AP: switch(hd[x])
+ { case G_SYMB:
+ case G_SUCHTHAT:
+ case G_RULE: return(NIL);
+ case G_OPT:
+ case G_FBSTAR:
+ case G_STAR: x=tl[x]; goto L;
+ default: if(hd[x]==outdent_fn)
+ { x=tl[x]; goto L; }
+ if(tag[hd[x]]==AP)
+ if(hd[hd[x]]==G_ERROR)
+ { x=tl[hd[x]]; goto L; }
+ if(hd[hd[x]]==G_SEQ)
+ { if(eprod(tl[hd[x]]))
+ return(UNION(starts(tl[hd[x]]),starts(tl[x])));
+ x=tl[hd[x]]; goto L; } else
+ if(hd[hd[x]]==G_ALT)
+ return(UNION(starts(tl[hd[x]]),starts(tl[x])));
+ else
+ if(hd[hd[x]]==indent_fn)
+ { x=tl[x]; goto L; }
+ }
+ default: return(NIL);
+ }
+}
+
+int eprod(x) /* x is grammar rhs - does x admit empty production? */
+word x;
+{ L: switch(tag[x])
+ { case ID: return(member(eprodnts,x));
+ case LABEL:
+ case LET:
+ case LETREC: x=tl[x]; goto L;
+ case AP: switch(hd[x])
+ { case G_SUCHTHAT:
+ case G_ANY:
+ case G_SYMB: return(0);
+ case G_RULE: return(1);
+ case G_OPT:
+ case G_FBSTAR:
+ case G_STAR: return(1);
+ default: if(hd[x]==outdent_fn)
+ { x=tl[x]; goto L; }
+ if(tag[hd[x]]==AP)
+ if(hd[hd[x]]==G_ERROR)
+ { x=tl[hd[x]]; goto L; }
+ if(hd[hd[x]]==G_SEQ)
+ return(eprod(tl[hd[x]])&&eprod(tl[x])); else
+ if(hd[hd[x]]==G_ALT)
+ return(eprod(tl[hd[x]])||eprod(tl[x]));
+ else
+ if(hd[hd[x]]==indent_fn)
+ { x=tl[x]; goto L; }
+ }
+ default: return(x==G_STATE||x==G_UNIT);
+ /* G_END is special case, unclear whether it counts as an e-prodn.
+ decide no for now, sort this out later */
+ }
+}
+
+word add_prod(d,ps,hr)
+word d,ps,hr;
+{ word p,n=dlhs(d);
+ for(p=ps;p!=NIL;p=tl[p])
+ if(dlhs(hd[p])==n)
+ if(dtyp(d)==undef_t&&dval(hd[p])==UNDEF)
+ { dval(hd[p])=dval(d); return(ps); } else
+ if(dtyp(d)!=undef_t&&dtyp(hd[p])==undef_t)
+ { dtyp(hd[p])=dtyp(d); return(ps); }
+ else
+ errs=hr,
+ printf(
+ "%ssyntax error: conflicting %s of nonterminal \"%s\"\n",
+ echoing?"\n":"",
+ dtyp(d)==undef_t?"definitions":"specifications",
+ get_id(n)),
+ acterror();
+ return(cons(d,ps));
+}
+/* clumsy - this algorithm is quadratic in number of prodns - fix later */
+
+word getloc(nt,prods) /* get here info for nonterminal */
+word nt,prods;
+{ while(prods!=NIL&&dlhs(hd[prods])!=nt)prods=tl[prods];
+ if(prods!=NIL)return(hd[dval(hd[prods])]);
+ return(0); /* should not happen, but just in case */
+}
+
+void findnt(nt) /* set errs to here info of undefined nonterminal */
+word nt;
+{ word p=ntmap;
+ while(p!=NIL&&hd[hd[p]]!=nt)p=tl[p];
+ if(p!=NIL)
+ { errs=tl[hd[p]]; return; }
+ p=ntspecmap;
+ while(p!=NIL&&hd[hd[p]]!=nt)p=tl[p];
+ if(p!=NIL)errs=tl[hd[p]];
+}
+
+#define isap2(fn,x) (tag[x]==AP&&tag[hd[x]]==AP&&hd[hd[x]]==(fn))
+#define firstsymb(term) tl[hd[term]]
+
+void binom(rhs,x)
+/* performs the binomial optimisation on rhs of nonterminal x
+ x: x alpha1| ... | x alphaN | rest ||need not be in this order
+ ==>
+ x: rest (alpha1|...|alphaN)*
+*/
+word rhs,x;
+{ word *p= &tl[rhs]; /* rhs is of form label(hereinf, stuff) */
+ word *lastp=0,*holdrhs,suffix,alpha=NIL;
+ if(tag[*p]==LETREC)p = &tl[*p]; /* ignore trailing `where defs' */
+ if(isap2(G_ERROR,*p))p = &tl[hd[*p]];
+ holdrhs=p;
+ while(isap2(G_ALT,*p))
+ if(firstsymb(tl[hd[*p]])==x)
+ alpha=cons(tl[tl[hd[*p]]],alpha),
+ *p=tl[*p],p = &tl[*p];
+ else lastp=p,p = &tl[tl[*p]];
+ /* note each (G_ALT a b) except the outermost is labelled */
+ if(lastp&&firstsymb(*p)==x)
+ alpha=cons(tl[*p],alpha),
+ *lastp=tl[hd[*lastp]];
+ if(alpha==NIL)return;
+ suffix=hd[alpha],alpha=tl[alpha];
+ while(alpha!=NIL)
+ suffix=ap2(G_ALT,hd[alpha],suffix),
+ alpha=tl[alpha];
+ *holdrhs=ap2(G_SEQ,*holdrhs,ap(G_FBSTAR,suffix));
+}
+/* should put some labels on the alpha's - fix later */
+
+word getcol_fn()
+{ extern char *dicp,*dicq;
+ if(!col_fn)
+ strcpy(dicp,"bnftokenindentation"),
+ dicq=dicp+20,
+ col_fn=name();
+ return(col_fn);
+}
+
+void startbnf()
+{ ntspecmap=ntmap=nonterminals=NIL;
+ if(fnts==0)col_fn=0; /* reinitialise, a precaution */
+}
+
+word ih_abstr(x) /* abstract inherited attributes from grammar rule */
+word x;
+{ word ih=ihlist;
+ while(ih!=NIL) /* relies on fact that ihlist is reversed */
+ x=lambda(hd[ih],x),ih=tl[ih];
+ return(x);
+}
+
+int can_elide(x) /* is x of the form $1 applied to ih attributes in order? */
+word x;
+{ word ih;
+ if(ihlist)
+ for(ih=ihlist;ih!=NIL&&tag[x]==AP;ih=tl[ih],x=hd[x])
+ if(hd[ih]!=tl[x])return(0);
+ return(x==mkgvar(1));
+}
+
+int e_re(x) /* does regular expression x match empty string ? */
+word x;
+{ L: if(tag[x]==AP)
+ { if(hd[x]==LEX_STAR||hd[x]==LEX_OPT)return(1);
+ if(hd[x]==LEX_STRING)return(tl[x]==NIL);
+ if(tag[hd[x]]!=AP)return(0);
+ if(hd[hd[x]]==LEX_OR)
+ { if(e_re(tl[hd[x]]))return(1);
+ x=tl[x]; goto L; } else
+ if(hd[hd[x]]==LEX_SEQ)
+ { if(!e_re(tl[hd[x]]))return(0);
+ x=tl[x]; goto L; } else
+ if(hd[hd[x]]==LEX_RCONTEXT)
+ { x=tl[hd[x]]; goto L; }
+ }
+ return(0);
+}
+
+%}
+
+%%
+
+entity: /* the entity to be parsed is either a definition script or an
+ expression (the latter appearing as a command line) */
+
+ error|
+
+ script
+ = { lastname=0; /* outstats(); */ }|
+ /* statistics not usually wanted after compilation */
+
+/* MAGIC exp '\n' script
+ = { lastexp=$2; }| /* change to magic scripts 19.11.2013 */
+
+ VALUE exp
+ = { lastexp=$2; }| /* next line of `$+' */
+
+ EVAL exp
+ = { if(!SYNERR&&yychar==0)
+ { evaluate($2); }
+ }|
+
+ EVAL exp COLONCOLON
+ /* boring problem - how to make sure no junk chars follow here?
+ likewise TO case -- trick used above doesn't work, yychar is
+ here always -1 Why? Too fiddly to bother with just now */
+ = { word t=type_of($2);
+ if(t!=wrong_t)
+ { lastexp=$2;
+ if(tag[$2]==ID&&id_type($2)==wrong_t)t=wrong_t;
+ out_type(t);
+ putchar('\n'); }
+ }|
+
+ EVAL exp TO
+ = { FILE *fil=NULL,*efil;
+ word t=type_of($2);
+ char *f=token(),*ef;
+ if(f)keep(f); ef=token(); /* wasteful of dic space, FIX LATER */
+ if(f){ fil= fopen(f,$3?"a":"w");
+ if(fil==NULL)
+ printf("cannot open \"%s\" for writing\n",f); }
+ else printf("filename missing after \"&>\"\n");
+ if(ef)
+ { efil= fopen(ef,$3?"a":"w");
+ if(efil==NULL)
+ printf("cannot open \"%s\" for writing\n",ef); }
+ if(t!=wrong_t)$2=codegen(lastexp=$2);
+ if(!polyshowerror&&t!=wrong_t&&fil!=NULL&&(!ef||efil))
+ { int pid;/* launch a concurrent process to perform task */
+ sighandler oldsig;
+ oldsig=signal(SIGINT,SIG_IGN); /* ignore interrupts */
+ if(pid=fork())
+ { /* "parent" */
+ if(pid==-1)perror("cannot create process");
+ else printf("process %d\n",pid);
+ fclose(fil);
+ if(ef)fclose(efil);
+ (void)signal(SIGINT,oldsig); }else
+ { /* "child" */
+ (void)signal(SIGQUIT,SIG_IGN); /* and quits */
+#ifndef SYSTEM5
+ (void)signal(SIGTSTP,SIG_IGN); /* and stops */
+#endif
+ close(1); dup(fileno(fil)); /* subvert stdout */
+ close(2); dup(fileno(ef?efil:fil)); /* subvert stderr */
+ /* FUNNY BUG - if redirect stdout stderr to same file by two
+ calls to freopen, their buffers get conflated - whence do
+ by subverting underlying file descriptors, as above
+ (fix due to Martin Guy) */
+ /* formerly used dup2, but not present in system V */
+ fclose(stdin);
+ /* setbuf(stdout,NIL);
+ /* not safe to change buffering of stream already in use */
+ /* freopen would have reset the buffering automatically */
+ lastexp = NIL; /* what else should we set to NIL? */
+ /*atcount= 1; */
+ compiling= 0;
+ resetgcstats();
+ output(isltmess_t(t)?$2:
+ cons(ap(standardout,isstring_t(t)?$2:
+ ap(mkshow(0,0,t),$2)),NIL));
+ putchar('\n');
+ outstats();
+ exit(0); } } };
+
+script:
+ /* empty */|
+ defs;
+
+exp:
+ op | /* will later suppress in favour of (op) in arg */
+ e1;
+
+op:
+ '~'
+ = { $$ = NOT; }|
+ '#'
+ = { $$ = LENGTH; }|
+ diop;
+
+diop:
+ '-'
+ = { $$ = MINUS; }|
+ diop1;
+
+diop1:
+ '+'
+ = { $$ = PLUS; }|
+ PLUSPLUS
+ = { $$ = APPEND; }|
+ ':'
+ = { $$ = P; }|
+ MINUSMINUS
+ = { $$ = listdiff_fn; }|
+ VEL
+ = { $$ = OR; }|
+ '&'
+ = { $$ = AND; }|
+ relop |
+ '*'
+ = { $$ = TIMES; }|
+ '/'
+ = { $$ = FDIV; }|
+ DIV
+ = { $$ = INTDIV; }|
+ REM
+ = { $$ = MOD; }|
+ '^'
+ = { $$ = POWER; }|
+ '.'
+ = { $$ = B; }|
+ '!'
+ = { $$ = ap(C,SUBSCRIPT); }|
+ INFIXNAME|
+ INFIXCNAME;
+
+relop:
+ '>'
+ = { $$ = GR; }|
+ GE
+ = { $$ = GRE; }|
+ eqop
+ = { $$ = EQ; }|
+ NE
+ = { $$ = NEQ; }|
+ LE
+ = { $$ = ap(C,GRE); }|
+ '<'
+ = { $$ = ap(C,GR); };
+
+eqop:
+ EQEQ| /* silently accept for benefit of Haskell users */
+ '=';
+
+rhs:
+ cases WHERE ldefs
+ = { $$ = block($3,compose($1),0); }|
+ exp WHERE ldefs
+ = { $$ = block($3,$1,0); }|
+ exp|
+ cases
+ = { $$ = compose($1); };
+
+cases:
+ exp ',' if exp
+ = { $$ = cons(ap2(COND,$4,$1),NIL); }|
+ exp ',' OTHERWISE
+ = { $$ = cons(ap(OTHERWISE,$1),NIL); }|
+ cases reindent ELSEQ alt
+ = { $$ = cons($4,$1);
+ if(hd[hd[$1]]==OTHERWISE)
+ syntax("\"otherwise\" must be last case\n"); };
+
+alt:
+ here exp
+ = { errs=$1,
+ syntax("obsolete syntax, \", otherwise\" missing\n");
+ $$ = ap(OTHERWISE,label($1,$2)); }|
+ here exp ',' if exp
+ = { $$ = label($1,ap2(COND,$5,$2)); }|
+ here exp ',' OTHERWISE
+ = { $$ = ap(OTHERWISE,label($1,$2)); };
+
+if:
+ /* empty */
+ = { extern word strictif;
+ if(strictif)syntax("\"if\" missing\n"); }|
+ IF;
+
+indent:
+ /* empty */
+ = { if(!SYNERR){layout(); setlmargin();}
+ };
+/* note that because of yacc's one symbol look ahead, indent must usually be
+ invoked one symbol earlier than the non-terminal to which it applies
+ - see `production:' for an exception */
+
+outdent:
+ separator
+ = { unsetlmargin(); };
+
+separator:
+ OFFSIDE | ';' ;
+
+reindent:
+ /* empty */
+ = { if(!SYNERR)
+ { unsetlmargin(); layout(); setlmargin(); }
+ };
+
+liste: /* NB - returns list in reverse order */
+ exp
+ = { $$ = cons($1,NIL); }|
+ liste ',' exp /* left recursive so as not to eat YACC stack */
+ = { $$ = cons($3,$1); };
+
+e1:
+ '~' e1 %prec '='
+ = { $$ = ap(NOT,$2); }|
+ e1 PLUSPLUS e1
+ = { $$ = ap2(APPEND,$1,$3); }|
+ e1 ':' e1
+ = { $$ = cons($1,$3); }|
+ e1 MINUSMINUS e1
+ = { $$ = ap2(listdiff_fn,$1,$3); }|
+ e1 VEL e1
+ = { $$ = ap2(OR,$1,$3); }|
+ e1 '&' e1
+ = { $$ = ap2(AND,$1,$3); }|
+ reln |
+ e2;
+
+es1: /* e1 or presection */
+ '~' e1 %prec '='
+ = { $$ = ap(NOT,$2); }|
+ e1 PLUSPLUS e1
+ = { $$ = ap2(APPEND,$1,$3); }|
+ e1 PLUSPLUS
+ = { $$ = ap(APPEND,$1); }|
+ e1 ':' e1
+ = { $$ = cons($1,$3); }|
+ e1 ':'
+ = { $$ = ap(P,$1); }|
+ e1 MINUSMINUS e1
+ = { $$ = ap2(listdiff_fn,$1,$3); }|
+ e1 MINUSMINUS
+ = { $$ = ap(listdiff_fn,$1); }|
+ e1 VEL e1
+ = { $$ = ap2(OR,$1,$3); }|
+ e1 VEL
+ = { $$ = ap(OR,$1); }|
+ e1 '&' e1
+ = { $$ = ap2(AND,$1,$3); }|
+ e1 '&'
+ = { $$ = ap(AND,$1); }|
+ relsn |
+ es2;
+
+e2:
+ '-' e2 %prec '-'
+ = { $$ = ap(NEG,$2); }|
+ '#' e2 %prec '.'
+ = { $$ = ap(LENGTH,$2); }|
+ e2 '+' e2
+ = { $$ = ap2(PLUS,$1,$3); }|
+ e2 '-' e2
+ = { $$ = ap2(MINUS,$1,$3); }|
+ e2 '*' e2
+ = { $$ = ap2(TIMES,$1,$3); }|
+ e2 '/' e2
+ = { $$ = ap2(FDIV,$1,$3); }|
+ e2 DIV e2
+ = { $$ = ap2(INTDIV,$1,$3); } |
+ e2 REM e2
+ = { $$ = ap2(MOD,$1,$3); }|
+ e2 '^' e2
+ = { $$ = ap2(POWER,$1,$3); } |
+ e2 '.' e2
+ = { $$ = ap2(B,$1,$3); }|
+ e2 '!' e2
+ = { $$ = ap2(SUBSCRIPT,$3,$1); }|
+ e3;
+
+es2: /* e2 or presection */
+ '-' e2 %prec '-'
+ = { $$ = ap(NEG,$2); }|
+ '#' e2 %prec '.'
+ = { $$ = ap(LENGTH,$2); }|
+ e2 '+' e2
+ = { $$ = ap2(PLUS,$1,$3); }|
+ e2 '+'
+ = { $$ = ap(PLUS,$1); }|
+ e2 '-' e2
+ = { $$ = ap2(MINUS,$1,$3); }|
+ e2 '-'
+ = { $$ = ap(MINUS,$1); }|
+ e2 '*' e2
+ = { $$ = ap2(TIMES,$1,$3); }|
+ e2 '*'
+ = { $$ = ap(TIMES,$1); }|
+ e2 '/' e2
+ = { $$ = ap2(FDIV,$1,$3); }|
+ e2 '/'
+ = { $$ = ap(FDIV,$1); }|
+ e2 DIV e2
+ = { $$ = ap2(INTDIV,$1,$3); } |
+ e2 DIV
+ = { $$ = ap(INTDIV,$1); } |
+ e2 REM e2
+ = { $$ = ap2(MOD,$1,$3); }|
+ e2 REM
+ = { $$ = ap(MOD,$1); }|
+ e2 '^' e2
+ = { $$ = ap2(POWER,$1,$3); } |
+ e2 '^'
+ = { $$ = ap(POWER,$1); } |
+ e2 '.' e2
+ = { $$ = ap2(B,$1,$3); }|
+ e2 '.'
+ = { $$ = ap(B,$1); }|
+ e2 '!' e2
+ = { $$ = ap2(SUBSCRIPT,$3,$1); }|
+ e2 '!'
+ = { $$ = ap2(C,SUBSCRIPT,$1); }|
+ es3;
+
+e3:
+ comb INFIXNAME e3
+ = { $$ = ap2($2,$1,$3); }|
+ comb INFIXCNAME e3
+ = { $$ = ap2($2,$1,$3); }|
+ comb;
+
+es3: /* e3 or presection */
+ comb INFIXNAME e3
+ = { $$ = ap2($2,$1,$3); }|
+ comb INFIXNAME
+ = { $$ = ap($2,$1); }|
+ comb INFIXCNAME e3
+ = { $$ = ap2($2,$1,$3); }|
+ comb INFIXCNAME
+ = { $$ = ap($2,$1); }|
+ comb;
+
+comb:
+ comb arg
+ = { $$ = ap($1,$2); }|
+ arg;
+
+reln:
+ e2 relop e2
+ = { $$ = ap2($2,$1,$3); }|
+ reln relop e2
+ = { word subject;
+ subject = hd[hd[$1]]==AND?tl[tl[$1]]:tl[$1];
+ $$ = ap2(AND,$1,ap2($2,subject,$3));
+ }; /* EFFICIENCY PROBLEM - subject gets re-evaluated (and
+ retypechecked) - fix later */
+
+relsn: /* reln or presection */
+ e2 relop e2
+ = { $$ = ap2($2,$1,$3); }|
+ e2 relop
+ = { $$ = ap($2,$1); }|
+ reln relop e2
+ = { word subject;
+ subject = hd[hd[$1]]==AND?tl[tl[$1]]:tl[$1];
+ $$ = ap2(AND,$1,ap2($2,subject,$3));
+ }; /* EFFICIENCY PROBLEM - subject gets re-evaluated (and
+ retypechecked) - fix later */
+
+arg:
+ { if(!SYNERR)lexstates=NIL,inlex=1; }
+ LEX lexrules ENDIR
+ = { inlex=0; lexdefs=NIL;
+ if(lexstates!=NIL)
+ { word echoed=0;
+ for(;lexstates!=NIL;lexstates=tl[lexstates])
+ { if(!echoed)printf(echoing?"\n":""),echoed=1;
+ if(!(tl[hd[lexstates]]&1))
+ printf("warning: lex state %s is never entered\n",
+ get_id(hd[hd[lexstates]])); else
+ if(!(tl[hd[lexstates]]&2))
+ printf("warning: lex state %s has no associated rules\n",
+ get_id(hd[hd[lexstates]])); }
+ }
+ if($3==NIL)syntax("%lex with no rules\n");
+ else tag[$3]=LEXER;
+ /* result is lex-list, in reverse order, of items of the form
+ cons(scstuff,cons(matcher,rhs))
+ where scstuff is of the form
+ cons(0-or-list-of-startconditions,1+newstartcondition)
+ */
+ $$ = $3; }|
+ NAME |
+ CNAME |
+ CONST |
+ READVALSY
+ = { $$ = readvals(0,0); }|
+ SHOWSYM
+ = { $$ = show(0,0); }|
+ DOLLAR2
+ = { $$ = lastexp;
+ if(lastexp==UNDEF)
+ syntax("no previous expression to substitute for $$\n"); }|
+ '[' ']'
+ = { $$ = NIL; }|
+ '[' exp ']'
+ = { $$ = cons($2,NIL); }|
+ '[' exp ',' exp ']'
+ = { $$ = cons($2,cons($4,NIL)); }|
+ '[' exp ',' exp ',' liste ']'
+ = { $$ = cons($2,cons($4,reverse($6))); }|
+ '[' exp DOTDOT exp ']'
+ = { $$ = ap3(STEPUNTIL,big_one,$4,$2); }|
+ '[' exp DOTDOT ']'
+ = { $$ = ap2(STEP,big_one,$2); }|
+ '[' exp ',' exp DOTDOT exp ']'
+ = { $$ = ap3(STEPUNTIL,ap2(MINUS,$4,$2),$6,$2); }|
+ '[' exp ',' exp DOTDOT ']'
+ = { $$ = ap2(STEP,ap2(MINUS,$4,$2),$2); }|
+ '[' exp '|' qualifiers ']'
+ = { $$ = SYNERR?NIL:compzf($2,$4,0); }|
+ '[' exp DIAG qualifiers ']'
+ = { $$ = SYNERR?NIL:compzf($2,$4,1); }|
+ '(' op ')' /* RSB */
+ = { $$ = $2; }|
+ '(' es1 ')' /* presection or parenthesised e1 */
+ = { $$ = $2; }|
+ '(' diop1 e1 ')' /* postsection */
+ = { $$ = (tag[$2]==AP&&hd[$2]==C)?ap(tl[$2],$3): /* optimisation */
+ ap2(C,$2,$3); }|
+ '(' ')'
+ = { $$ = Void; }| /* the void tuple */
+ '(' exp ',' liste ')'
+ = { if(tl[$4]==NIL)$$=pair($2,hd[$4]);
+ else { $$=pair(hd[tl[$4]],hd[$4]);
+ $4=tl[tl[$4]];
+ while($4!=NIL)$$=tcons(hd[$4],$$),$4=tl[$4];
+ $$ = tcons($2,$$); }
+ /* representation of the tuple (a1,...,an) is
+ tcons(a1,tcons(a2,...pair(a(n-1),an))) */
+ };
+
+lexrules:
+ lexrules lstart here re indent { if(!SYNERR)inlex=2; }
+ ARROW exp lpostfix { if(!SYNERR)inlex=1; } outdent
+ = { if($9<0 && e_re($4))
+ errs=$3,
+ syntax("illegal lex rule - lhs matches empty\n");
+ $$ = cons(cons(cons($2,1+$9),cons($4,label($3,$8))),$1); }|
+ lexdefs
+ = { $$ = NIL; };
+
+lstart:
+ /* empty */
+ = { $$ = 0; }|
+ '<' cnames '>'
+ = { word ns=NIL;
+ for(;$2!=NIL;$2=tl[$2])
+ { word *x = &lexstates,i=1;
+ while(*x!=NIL&&hd[hd[*x]]!=hd[$2])i++,x = &tl[*x];
+ if(*x == NIL)*x = cons(cons(hd[$2],2),NIL);
+ else tl[hd[*x]] |= 2;
+ ns = add1(i,ns); }
+ $$ = ns; };
+
+cnames:
+ CNAME
+ = { $$=cons($1,NIL); }|
+ cnames CNAME
+ = { if(member($1,$2))
+ printf("%ssyntax error: repeated name \"%s\" in start conditions\n",
+ echoing?"\n":"",get_id($2)),
+ acterror();
+ $$ = cons($2,$1); };
+
+lpostfix:
+ /* empty */
+ = { $$ = -1; }|
+ LBEGIN CNAME
+ = { word *x = &lexstates,i=1;
+ while(*x!=NIL&&hd[hd[*x]]!=$2)i++,x = &tl[*x];
+ if(*x == NIL)*x = cons(cons($2,1),NIL);
+ else tl[hd[*x]] |= 1;
+ $$ = i;
+ }|
+ LBEGIN CONST
+ = { if(!isnat($2)||get_int($2)!=0)
+ syntax("%begin not followed by IDENTIFIER or 0\n");
+ $$ = 0; };
+
+lexdefs:
+ lexdefs LEXDEF indent '=' re outdent
+ = { lexdefs = cons(cons($2,$5),lexdefs); }|
+ /* empty */
+ = { lexdefs = NIL; };
+
+re: /* regular expression */
+ re1 '|' re
+ { $$ = ap2(LEX_OR,$1,$3); }|
+ re1;
+
+re1:
+ lterm '/' lterm
+ { $$ = ap2(LEX_RCONTEXT,$1,$3); }|
+ lterm '/'
+ { $$ = ap2(LEX_RCONTEXT,$1,0); }|
+ lterm;
+
+lterm:
+ lfac lterm
+ { $$ = ap2(LEX_SEQ,$1,$2); }|
+ lfac;
+
+lfac:
+ lunit '*'
+ { if(e_re($1))
+ syntax("illegal regular expression - arg of * matches empty\n");
+ $$ = ap(LEX_STAR,$1); }|
+ lunit '+'
+ { $$ = ap2(LEX_SEQ,$1,ap(LEX_STAR,$1)); }|
+ lunit '?'
+ { $$ = ap(LEX_OPT,$1); }|
+ lunit;
+
+lunit:
+ '(' re ')'
+ = { $$ = $2; }|
+ CONST
+ = { if(!isstring($1))
+ printf("%ssyntax error - unexpected token \"",
+ echoing?"\n":""),
+ out(stdout,$1),printf("\" in regular expression\n"),
+ acterror();
+ $$ = $1==NILS?ap(LEX_STRING,NIL):
+ tl[$1]==NIL?ap(LEX_CHAR,hd[$1]):
+ ap(LEX_STRING,$1);
+ }|
+ CHARCLASS
+ = { if($1==NIL)
+ syntax("empty character class `` cannot match\n");
+ $$ = tl[$1]==NIL?ap(LEX_CHAR,hd[$1]):ap(LEX_CLASS,$1); }|
+ ANTICHARCLASS
+ = { $$ = ap(LEX_CLASS,cons(ANTICHARCLASS,$1)); }|
+ '.'
+ = { $$ = LEX_DOT; }|
+ name
+ = { word x=lexdefs;
+ while(x!=NIL&&hd[hd[x]]!=$1)x=tl[x];
+ if(x==NIL)
+ printf(
+ "%ssyntax error: undefined lexeme %s in regular expression\n",
+ echoing?"\n":"",
+ get_id($1)),
+ acterror();
+ else $$ = tl[hd[x]]; };
+
+name: NAME|CNAME;
+
+qualifiers:
+ exp
+ = { $$ = cons(cons(GUARD,$1),NIL); }|
+ generator
+ = { $$ = cons($1,NIL); }|
+ qualifiers ';' generator
+ = { $$ = cons($3,$1); }|
+ qualifiers ';' exp
+ = { $$ = cons(cons(GUARD,$3),$1); };
+
+generator:
+ e1 ',' generator
+ = { /* fix syntax to disallow patlist on lhs of iterate generator */
+ if(hd[$3]==GENERATOR)
+ { word e=tl[tl[$3]];
+ if(tag[e]==AP&&tag[hd[e]]==AP&&
+ (hd[hd[e]]==ITERATE||hd[hd[e]]==ITERATE1))
+ syntax("ill-formed generator\n"); }
+ $$ = cons(REPEAT,cons(genlhs($1),$3)); idsused=NIL; }|
+ generator1;
+
+generator1:
+ e1 LEFTARROW exp
+ = { $$ = cons(GENERATOR,cons(genlhs($1),$3)); idsused=NIL; }|
+ e1 LEFTARROW exp ',' exp DOTDOT
+ = { word p = genlhs($1); idsused=NIL;
+ $$ = cons(GENERATOR,
+ cons(p,ap2(irrefutable(p)?ITERATE:ITERATE1,
+ lambda(p,$5),$3)));
+ };
+
+defs:
+ def|
+ defs def;
+
+def:
+ v act2 indent '=' here rhs outdent
+ = { word l = $1, r = $6;
+ word f = head(l);
+ if(tag[f]==ID&&!isconstructor(f)) /* fnform defn */
+ while(tag[l]==AP)r=lambda(tl[l],r),l=hd[l];
+ r = label($5,r); /* to help locate type errors */
+ declare(l,r),lastname=l; }|
+
+ spec
+ = { word h=reverse(hd[$1]),hr=hd[tl[$1]],t=tl[tl[$1]];
+ while(h!=NIL&&!SYNERR)specify(hd[h],t,hr),h=tl[h];
+ $$ = cons(nill,NIL); }|
+
+ ABSTYPE here typeforms indent WITH lspecs outdent
+ = { extern word TABSTRS;
+ extern char *dicp,*dicq;
+ word x=reverse($6),ids=NIL,tids=NIL;
+ while(x!=NIL&&!SYNERR)
+ specify(hd[hd[x]],cons(tl[tl[hd[x]]],NIL),hd[tl[hd[x]]]),
+ ids=cons(hd[hd[x]],ids),x=tl[x];
+ /* each id in specs has its id_type set to const(t,NIL) as a way
+ of flagging that t is an abstract type */
+ x=reverse($3);
+ while(x!=NIL&&!SYNERR)
+ { word shfn;
+ decltype(hd[x],abstract_t,undef_t,$2);
+ tids=cons(head(hd[x]),tids);
+ /* check for presence of showfunction */
+ (void)strcpy(dicp,"show");
+ (void)strcat(dicp,get_id(hd[tids]));
+ dicq = dicp+strlen(dicp)+1;
+ shfn=name();
+ if(member(ids,shfn))
+ t_showfn(hd[tids])=shfn;
+ x=tl[x]; }
+ TABSTRS = cons(cons(tids,ids),TABSTRS);
+ $$ = cons(nill,NIL); }|
+
+ typeform indent act1 here EQEQ type act2 outdent
+ = { word x=redtvars(ap($1,$6));
+ decltype(hd[x],synonym_t,tl[x],$4);
+ $$ = cons(nill,NIL); }|
+
+ typeform indent act1 here COLON2EQ construction act2 outdent
+ = { word rhs = $6, r_ids = $6, n=0;
+ while(r_ids!=NIL)r_ids=tl[r_ids],n++;
+ while(rhs!=NIL&&!SYNERR)
+ { word h=hd[rhs],t=$1,stricts=NIL,i=0;
+ while(tag[h]==AP)
+ { if(tag[tl[h]]==AP&&hd[tl[h]]==strict_t)
+ stricts=cons(i,stricts),tl[h]=tl[tl[h]];
+ t=ap2(arrow_t,tl[h],t),h=hd[h],i++; }
+ if(tag[h]==ID)
+ declconstr(h,--n,t);
+ /* warning - type not yet in reduced form */
+ else { stricts=NIL;
+ if(echoing)putchar('\n');
+ printf("syntax error: illegal construct \"");
+ out_type(hd[rhs]);
+ printf("\" on right of ::=\n");
+ acterror(); } /* can this still happen? check later */
+ if(stricts!=NIL) /* ! operators were present */
+ { word k = id_val(h);
+ while(stricts!=NIL)
+ k=ap2(MKSTRICT,i-hd[stricts],k),
+ stricts=tl[stricts];
+ id_val(h)=k; /* overwrite id_val of original constructor */
+ }
+ r_ids=cons(h,r_ids);
+ rhs = tl[rhs]; }
+ if(!SYNERR)decltype($1,algebraic_t,r_ids,$4);
+ $$ = cons(nill,NIL); }|
+
+ indent setexp EXPORT parts outdent
+ = { inexplist=0;
+ if(exports!=NIL)
+ errs=$2,
+ syntax("multiple %export statements are illegal\n");
+ else { if($4==NIL&&exportfiles==NIL&&embargoes!=NIL)
+ exportfiles=cons(PLUS,NIL);
+ exports=cons($2,$4); } /* cons(hereinfo,identifiers) */
+ $$ = cons(nill,NIL); }|
+
+ FREE here '{' specs '}'
+ = { if(freeids!=NIL)
+ errs=$2,
+ syntax("multiple %free statements are illegal\n"); else
+ { word x=reverse($4);
+ while(x!=NIL&&!SYNERR)
+ { specify(hd[hd[x]],tl[tl[hd[x]]],hd[tl[hd[x]]]);
+ freeids=cons(head(hd[hd[x]]),freeids);
+ if(tl[tl[hd[x]]]==type_t)
+ t_class(hd[freeids])=free_t;
+ else id_val(hd[freeids])=FREE; /* conventional value */
+ x=tl[x]; }
+ fil_share(hd[files])=0; /* parameterised scripts unshareable */
+ freeids=alfasort(freeids);
+ for(x=freeids;x!=NIL;x=tl[x])
+ hd[x]=cons(hd[x],cons(datapair(get_id(hd[x]),0),
+ id_type(hd[x])));
+ /* each element of freeids is of the form
+ cons(id,cons(original_name,type)) */
+ }
+ $$ = cons(nill,NIL); }|
+
+ INCLUDE bindings modifiers outdent
+ /* fiddle - 'indent' done by yylex() on reading fileid */
+ = { extern char *dicp;
+ extern word CLASHES,BAD_DUMP;
+ includees=cons(cons($1,cons($3,$2)),includees);
+ /* $1 contains file+hereinfo */
+ $$ = cons(nill,NIL); }|
+
+ here BNF { startbnf(); inbnf=1;} names outdent productions ENDIR
+ /* fiddle - `indent' done by yylex() while processing directive */
+ = { word lhs=NIL,p=$6,subjects,body,startswith=NIL,leftrecs=NIL;
+ ihlist=inbnf=0;
+ nonterminals=UNION(nonterminals,$4);
+ for(;p!=NIL;p=tl[p])
+ if(dval(hd[p])==UNDEF)nonterminals=add1(dlhs(hd[p]),nonterminals);
+ else lhs=add1(dlhs(hd[p]),lhs);
+ nonterminals=setdiff(nonterminals,lhs);
+ if(nonterminals!=NIL)
+ errs=$1,
+ member($4,hd[nonterminals])/*||findnt(hd[nonterminals])*/,
+ printf("%sfatal error in grammar, ",echoing?"\n":""),
+ printf("undefined nonterminal%s: ",
+ tl[nonterminals]==NIL?"":"s"),
+ printlist("",nonterminals),
+ acterror(); else
+ { /* compute list of nonterminals admitting empty prodn */
+ eprodnts=NIL;
+ L:for(p=$6;p!=NIL;p=tl[p])
+ if(!member(eprodnts,dlhs(hd[p]))&&eprod(dval(hd[p])))
+ { eprodnts=cons(dlhs(hd[p]),eprodnts); goto L; }
+ /* now compute startswith reln between nonterminals
+ (performing binomial transformation en route)
+ and use to detect unremoved left recursion */
+ for(p=$6;p!=NIL;p=tl[p])
+ if(member(lhs=starts(dval(hd[p])),dlhs(hd[p])))
+ binom(dval(hd[p]),dlhs(hd[p])),
+ startswith=cons(cons(dlhs(hd[p]),starts(dval(hd[p]))),
+ startswith);
+ else startswith=cons(cons(dlhs(hd[p]),lhs),startswith);
+ startswith=tclos(sortrel(startswith));
+ for(;startswith!=NIL;startswith=tl[startswith])
+ if(member(tl[hd[startswith]],hd[hd[startswith]]))
+ leftrecs=add1(hd[hd[startswith]],leftrecs);
+ if(leftrecs!=NIL)
+ errs=getloc(hd[leftrecs],$6),
+ printf("%sfatal error in grammar, ",echoing?"\n":""),
+ printlist("irremovable left recursion: ",leftrecs),
+ acterror();
+ if($4==NIL) /* implied start symbol */
+ $4=cons(dlhs(hd[lastlink($6)]),NIL);
+ fnts=1; /* fnts is flag indicating %bnf in use */
+ if(tl[$4]==NIL) /* only one start symbol */
+ subjects=getfname(hd[$4]),
+ body=ap2(G_CLOSE,str_conv(get_id(hd[$4])),hd[$4]);
+ else
+ { body=subjects=Void;
+ while($4!=NIL)
+ subjects=pair(getfname(hd[$4]),subjects),
+ body=pair(
+ ap2(G_CLOSE,str_conv(get_id(hd[$4])),hd[$4]),
+ body),
+ $4=tl[$4];
+ }
+ declare(subjects,label($1,block($6,body, 0)));
+ }};
+
+setexp:
+ here
+ = { $$=$1;
+ inexplist=1; }; /* hack to fix lex analyser */
+
+bindings:
+ /* empty */
+ = { $$ = NIL; }|
+ '{' bindingseq '}'
+ = { $$ = $2; };
+
+bindingseq:
+ bindingseq binding
+ = { $$ = cons($2,$1); }|
+ binding
+ = { $$ = cons($1,NIL); };
+
+binding:
+ NAME indent '=' exp outdent
+ = { $$ = cons($1,$4); }|
+ typeform indent act1 EQEQ type act2 outdent
+ = { word x=redtvars(ap($1,$5));
+ word arity=0,h=hd[x];
+ while(tag[h]==AP)arity++,h=hd[h];
+ $$ = ap(h,make_typ(arity,0,synonym_t,tl[x]));
+ };
+
+modifiers:
+ /* empty */
+ = { $$ = NIL; }|
+ negmods
+ = { word a,b,c=0;
+ for(a=$1;a!=NIL;a=tl[a])
+ for(b=tl[a];b!=NIL;b=tl[b])
+ { if(hd[hd[a]]==hd[hd[b]])c=hd[hd[a]];
+ if(tl[hd[a]]==tl[hd[b]])c=tl[hd[a]];
+ if(c)break; }
+ if(c)printf(
+ "%ssyntax error: conflicting aliases (\"%s\")\n",
+ echoing?"\n":"",
+ get_id(c)),
+ acterror();
+ };
+
+negmods:
+ negmods negmod
+ = { $$ = cons($2,$1); }|
+ negmod
+ = { $$ = cons($1,NIL); };
+
+negmod:
+ NAME '/' NAME
+ = { $$ = cons($1,$3); }|
+ CNAME '/' CNAME
+ = { $$ = cons($1,$3); }|
+ '-' NAME
+ = { $$ = cons(make_pn(UNDEF),$2); }/*|
+ '-' CNAME */; /* no - cannot suppress constructors selectively */
+
+here:
+ /* empty */
+ = { extern word line_no;
+ lasth = $$ = fileinfo(get_fil(current_file),line_no);
+ /* (script,line_no) for diagnostics */
+ };
+
+act1:
+ /* empty */
+ = { tvarscope=1; };
+
+act2:
+ /* empty */
+ = { tvarscope=0; idsused= NIL; };
+
+ldefs:
+ ldef
+ = { $$ = cons($1,NIL);
+ dval($1) = tries(dlhs($1),cons(dval($1),NIL));
+ if(!SYNERR&&get_ids(dlhs($1))==NIL)
+ errs=hd[hd[tl[dval($1)]]],
+ syntax("illegal lhs for local definition\n");
+ }|
+ ldefs ldef
+ = { if(dlhs($2)==dlhs(hd[$1]) /*&&dval(hd[$1])!=UNDEF*/)
+ { $$ = $1;
+ if(!fallible(hd[tl[dval(hd[$1])]]))
+ errs=hd[dval($2)],
+ printf("%ssyntax error: \
+unreachable case in defn of \"%s\"\n",echoing?"\n":"",get_id(dlhs($2))),
+ acterror();
+ tl[dval(hd[$1])]=cons(dval($2),tl[dval(hd[$1])]); }
+ else if(!SYNERR)
+ { word ns=get_ids(dlhs($2)),hr=hd[dval($2)];
+ if(ns==NIL)
+ errs=hr,
+ syntax("illegal lhs for local definition\n");
+ $$ = cons($2,$1);
+ dval($2)=tries(dlhs($2),cons(dval($2),NIL));
+ while(ns!=NIL&&!SYNERR) /* local nameclash check */
+ { nclashcheck(hd[ns],$1,hr);
+ ns=tl[ns]; }
+ /* potentially quadratic - fix later */
+ }
+ };
+
+ldef:
+ spec
+ = { errs=hd[tl[$1]];
+ syntax("`::' encountered in local defs\n");
+ $$ = cons(nill,NIL); }|
+ typeform here EQEQ
+ = { errs=$2;
+ syntax("`==' encountered in local defs\n");
+ $$ = cons(nill,NIL); }|
+ typeform here COLON2EQ
+ = { errs=$2;
+ syntax("`::=' encountered in local defs\n");
+ $$ = cons(nill,NIL); }|
+ v act2 indent '=' here rhs outdent
+ = { word l = $1, r = $6;
+ word f = head(l);
+ if(tag[f]==ID&&!isconstructor(f)) /* fnform defn */
+ while(tag[l]==AP)r=lambda(tl[l],r),l=hd[l];
+ r = label($5,r); /* to help locate type errors */
+ $$ = defn(l,undef_t,r); };
+
+vlist:
+ v
+ = { $$ = cons($1,NIL); }|
+ vlist ',' v /* left recursive so as not to eat YACC stack */
+ = { $$ = cons($3,$1); }; /* reverse order, NB */
+
+v:
+ v1 |
+ v1 ':' v
+ = { $$ = cons($1,$3); };
+
+v1:
+ v1 '+' CONST /* n+k pattern */
+ = { if(!isnat($3))
+ syntax("inappropriate use of \"+\" in pattern\n");
+ $$ = ap2(PLUS,$3,$1); }|
+ '-' CONST
+ = { /* if(tag[$2]==DOUBLE)
+ $$ = cons(CONST,sto_dbl(-get_dbl($2))); else */
+ if(tag[$2]==INT)
+ $$ = cons(CONST,bignegate($2)); else
+ syntax("inappropriate use of \"-\" in pattern\n"); }|
+ v2 INFIXNAME v1
+ = { $$ = ap2($2,$1,$3); }|
+ v2 INFIXCNAME v1
+ = { $$ = ap2($2,$1,$3); }|
+ v2;
+
+v2:
+ v3 |
+ v2 v3
+ = { $$ = ap(hd[$1]==CONST&&tag[tl[$1]]==ID?tl[$1]:$1,$2); };
+ /* repeated name apparatus may have wrapped CONST around leading id
+ - not wanted */
+
+v3:
+ NAME
+ = { if(sreds&&member(gvars,$1))syntax("illegal use of $num symbol\n");
+ /* cannot use grammar variable in a binding position */
+ if(memb(idsused,$1))$$ = cons(CONST,$1);
+ /* picks up repeated names in a template */
+ else idsused= cons($1,idsused); } |
+ CNAME |
+ CONST
+ = { if(tag[$1]==DOUBLE)
+ syntax("use of floating point literal in pattern\n");
+ $$ = cons(CONST,$1); }|
+ '[' ']'
+ = { $$ = nill; }|
+ '[' vlist ']'
+ = { word x=$2,y=nill;
+ while(x!=NIL)y = cons(hd[x],y), x = tl[x];
+ $$ = y; }|
+ '(' ')'
+ = { $$ = Void; }|
+ '(' v ')'
+ = { $$ = $2; }|
+ '(' v ',' vlist ')'
+ = { if(tl[$4]==NIL)$$=pair($2,hd[$4]);
+ else { $$=pair(hd[tl[$4]],hd[$4]);
+ $4=tl[tl[$4]];
+ while($4!=NIL)$$=tcons(hd[$4],$$),$4=tl[$4];
+ $$ = tcons($2,$$); }
+ /* representation of the tuple (a1,...,an) is
+ tcons(a1,tcons(a2,...pair(a(n-1),an))) */
+ };
+
+type:
+ type1 |
+ type ARROW type
+ = { $$ = ap2(arrow_t,$1,$3); };
+
+type1:
+ type2 INFIXNAME type1
+ = { $$ = ap2($2,$1,$3); }|
+ type2;
+
+type2:
+ /* type2 argtype /* too permissive - fix later */
+ /* = { $$ = ap($1,$2); }| */
+ tap|
+ argtype;
+
+tap:
+ NAME argtype
+ = { $$ = ap($1,$2); }|
+ tap argtype
+ = { $$ = ap($1,$2); };
+
+argtype:
+ NAME
+ = { $$ = transtypeid($1); }|
+ /* necessary while prelude not meta_tchecked (for prelude)*/
+ typevar
+ = { if(tvarscope&&!memb(idsused,$1))
+ printf("%ssyntax error: unbound type variable ",echoing?"\n":""),
+ out_type($1),putchar('\n'),acterror();
+ $$ = $1; }|
+ '(' typelist ')'
+ = { $$ = $2; }|
+ '[' type ']' /* at release one was `typelist' */
+ = { $$ = ap(list_t,$2); }|
+ '[' type ',' typel ']'
+ = { syntax(
+ "tuple-type with missing parentheses (obsolete syntax)\n"); };
+
+typelist:
+ /* empty */
+ = { $$ = void_t; }| /* voidtype */
+ type |
+ type ',' typel
+ = { word x=$3,y=void_t;
+ while(x!=NIL)y = ap2(comma_t,hd[x],y), x = tl[x];
+ $$ = ap2(comma_t,$1,y); };
+
+typel:
+ type
+ = { $$ = cons($1,NIL); }|
+ typel ',' type /* left recursive so as not to eat YACC stack */
+ = { $$ = cons($3,$1); };
+
+parts: /* returned in reverse order */
+ parts NAME
+ = { $$ = add1($2,$1); }|
+ parts '-' NAME
+ = { $$ = $1; embargoes=add1($3,embargoes); }|
+ parts PATHNAME
+ = { $$ = $1; }| /*the pathnames are placed on exportfiles in yylex*/
+ parts '+'
+ = { $$ = $1;
+ exportfiles=cons(PLUS,exportfiles); }|
+ NAME
+ = { $$ = add1($1,NIL); }|
+ '-' NAME
+ = { $$ = NIL; embargoes=add1($2,embargoes); }|
+ PATHNAME
+ = { $$ = NIL; }|
+ '+'
+ = { $$ = NIL;
+ exportfiles=cons(PLUS,exportfiles); };
+
+specs: /* returns a list of cons(id,cons(here,type))
+ in reverse order of appearance */
+ specs spec
+ = { word x=$1,h=hd[$2],t=tl[$2];
+ while(h!=NIL)x=cons(cons(hd[h],t),x),h=tl[h];
+ $$ = x; }|
+ spec
+ = { word x=NIL,h=hd[$1],t=tl[$1];
+ while(h!=NIL)x=cons(cons(hd[h],t),x),h=tl[h];
+ $$ = x; };
+
+spec:
+ typeforms indent here COLONCOLON ttype outdent
+ = { $$ = cons($1,cons($3,$5)); };
+ /* hack: `typeforms' includes `namelist' */
+
+lspecs: /* returns a list of cons(id,cons(here,type))
+ in reverse order of appearance */
+ lspecs lspec
+ = { word x=$1,h=hd[$2],t=tl[$2];
+ while(h!=NIL)x=cons(cons(hd[h],t),x),h=tl[h];
+ $$ = x; }|
+ lspec
+ = { word x=NIL,h=hd[$1],t=tl[$1];
+ while(h!=NIL)x=cons(cons(hd[h],t),x),h=tl[h];
+ $$ = x; };
+
+lspec:
+ namelist indent here {inbnf=0;} COLONCOLON type outdent
+ = { $$ = cons($1,cons($3,$6)); };
+
+namelist:
+ NAME ',' namelist
+ = { $$ = cons($1,$3); }|
+ NAME
+ = { $$ = cons($1,NIL); };
+
+typeforms:
+ typeforms ',' typeform act2
+ = { $$ = cons($3,$1); }|
+ typeform act2
+ = { $$ = cons($1,NIL); };
+
+typeform:
+ CNAME typevars
+ = { syntax("upper case identifier out of context\n"); }|
+ NAME typevars /* warning if typevar is repeated */
+ = { $$ = $1;
+ idsused=$2;
+ while($2!=NIL)
+ $$ = ap($$,hd[$2]),$2 = tl[$2];
+ }|
+ typevar INFIXNAME typevar
+ = { if(eqtvar($1,$3))
+ syntax("repeated type variable in typeform\n");
+ idsused=cons($1,cons($3,NIL));
+ $$ = ap2($2,$1,$3); }|
+ typevar INFIXCNAME typevar
+ = { syntax("upper case identifier cannot be used as typename\n"); };
+
+ttype:
+ type|
+ TYPE
+ = { $$ = type_t; };
+
+typevar:
+ '*'
+ = { $$ = mktvar(1); }|
+ TYPEVAR;
+
+typevars:
+ /* empty */
+ = { $$ = NIL; }|
+ typevar typevars
+ = { if(memb($2,$1))
+ syntax("repeated type variable on lhs of type def\n");
+ $$ = cons($1,$2); };
+
+construction:
+ constructs
+ = { extern word SGC; /* keeps track of sui-generis constructors */
+ if( tl[$1]==NIL && tag[hd[$1]]!=ID )
+ /* 2nd conjunct excludes singularity types */
+ SGC=cons(head(hd[$1]),SGC);
+ };
+
+constructs:
+ construct
+ = { $$ = cons($1,NIL); }|
+ constructs '|' construct
+ = { $$ = cons($3,$1); };
+
+construct:
+ field here INFIXCNAME field
+ = { $$ = ap2($3,$1,$4);
+ id_who($3)=$2; }|
+ construct1;
+
+construct1:
+ '(' construct ')'
+ = { $$ = $2; }|
+ construct1 field1
+ = { $$ = ap($1,$2); }|
+ here CNAME
+ = { $$ = $2;
+ id_who($2)=$1; };
+
+field:
+ type|
+ argtype '!'
+ = { $$ = ap(strict_t,$1); };
+
+field1:
+ argtype '!'
+ = { $$ = ap(strict_t,$1); }|
+ argtype;
+
+names: /* used twice - for bnf list, and for inherited attr list */
+ /* empty */
+ = { $$ = NIL; }|
+ names NAME
+ = { if(member($1,$2))
+ printf("%ssyntax error: repeated identifier \"%s\" in %s list\n",
+ echoing?"\n":"",get_id($2),inbnf?"bnf":"attribute"),
+ acterror();
+ $$ = inbnf?add1($2,$1):cons($2,$1);
+ };
+
+productions:
+ lspec
+ = { word h=reverse(hd[$1]),hr=hd[tl[$1]],t=tl[tl[$1]];
+ inbnf=1;
+ $$=NIL;
+ while(h!=NIL&&!SYNERR)
+ ntspecmap=cons(cons(hd[h],hr),ntspecmap),
+ $$=add_prod(defn(hd[h],t,UNDEF),$$,hr),
+ h=tl[h];
+ }|
+ production
+ = { $$ = cons($1,NIL); }|
+ productions lspec
+ = { word h=reverse(hd[$2]),hr=hd[tl[$2]],t=tl[tl[$2]];
+ inbnf=1;
+ $$=$1;
+ while(h!=NIL&&!SYNERR)
+ ntspecmap=cons(cons(hd[h],hr),ntspecmap),
+ $$=add_prod(defn(hd[h],t,UNDEF),$$,hr),
+ h=tl[h];
+ }|
+ productions production
+ = { $$ = add_prod($2,$1,hd[dval($2)]); };
+
+production:
+ NAME params ':' indent grhs outdent
+ /* found by experiment that indent must follow ':' here */
+ = { $$ = defn($1,undef_t,$5); };
+
+params: /* places inherited attributes, if any, on ihlist */
+ /* empty */
+ = { ihlist=0; }|
+ { inbnf=0; } '(' names ')'
+ = { inbnf=1;
+ if($3==NIL)syntax("unexpected token ')'\n");
+ ihlist=$3; }
+
+grhs:
+ here phrase
+ = { $$ = label($1,$2); };
+
+phrase:
+ error_term
+ = { $$ = ap2(G_ERROR,G_ZERO,$1); }|
+ phrase1
+ = { $$=hd[$1], $1=tl[$1];
+ while($1!=NIL)
+ $$=label(hd[$1],$$),$1=tl[$1],
+ $$=ap2(G_ALT,hd[$1],$$),$1=tl[$1];
+ }|
+ phrase1 '|' error_term
+ = { $$=hd[$1], $1=tl[$1];
+ while($1!=NIL)
+ $$=label(hd[$1],$$),$1=tl[$1],
+ $$=ap2(G_ALT,hd[$1],$$),$1=tl[$1];
+ $$ = ap2(G_ERROR,$$,$3); };
+ /* we right rotate G_ALT's to facilitate left factoring (see trans) */
+
+phrase1:
+ term
+ = { $$=cons($1,NIL); }|
+ phrase1 '|' here term
+ = { $$ = cons($4,cons($3,$1)); };
+
+term:
+ count_factors
+ = { word n=0,f=$1,rule=Void;
+ /* default value of a production is () */
+ /* rule=mkgvar(sreds); /* formerly last symbol */
+ if(f!=NIL&&hd[f]==G_END)sreds++;
+ if(ihlist)rule=ih_abstr(rule);
+ while(n<sreds)rule=lambda(mkgvar(++n),rule);
+ sreds=0;
+ rule=ap(G_RULE,rule);
+ while(f!=NIL)rule=ap2(G_SEQ,hd[f],rule),f=tl[f];
+ $$ = rule; }|
+ count_factors {inbnf=2;} indent '=' here rhs outdent
+ = { if($1!=NIL&&hd[$1]==G_END)sreds++;
+ if(sreds==1&&can_elide($6))
+ inbnf=1,sreds=0,$$=hd[$1]; /* optimisation */
+ else
+ { word f=$1,rule=label($5,$6),n=0;
+ inbnf=1;
+ if(ihlist)rule=ih_abstr(rule);
+ while(n<sreds)rule=lambda(mkgvar(++n),rule);
+ sreds=0;
+ rule=ap(G_RULE,rule);
+ while(f!=NIL)rule=ap2(G_SEQ,hd[f],rule),f=tl[f];
+ $$ = rule; }
+ };
+
+error_term:
+ ERRORSY
+ = { word rule = ap(K,Void); /* default value of a production is () */
+ if(ihlist)rule=ih_abstr(rule);
+ $$ = rule; }|
+ ERRORSY { inbnf=2,sreds=2; } indent '=' here rhs outdent
+ = { word rule = label($5,$6);
+ if(ihlist)rule=ih_abstr(rule);
+ $$ = lambda(pair(mkgvar(1),mkgvar(2)),rule);
+ inbnf=1,sreds=0; };
+
+count_factors:
+ EMPTYSY
+ = { sreds=0; $$=NIL; }|
+ EMPTYSY factors
+ = { syntax("unexpected token after empty\n");
+ sreds=0; $$=NIL; }|
+ { obrct=0; } factors
+ = { word f=$2;
+ if(obrct)
+ syntax(obrct>0?"unmatched { in grammar rule\n":
+ "unmatched } in grammar rule\n");
+ for(sreds=0;f!=NIL;f=tl[f])sreds++;
+ if(hd[$2]==G_END)sreds--;
+ $$ = $2; };
+
+factors:
+ factor
+ = { $$ = cons($1,NIL); }|
+ factors factor
+ = { if(hd[$1]==G_END)
+ syntax("unexpected token after end\n");
+ $$ = cons($2,$1); };
+
+factor:
+ unit|
+ '{' unit '}'
+ = { $$ = ap(outdent_fn,ap2(indent_fn,getcol_fn(),$2)); }|
+ '{' unit
+ = { obrct++;
+ $$ = ap2(indent_fn,getcol_fn(),$2); }|
+ unit '}'
+ = { if(--obrct<0)syntax("unmatched `}' in grammar rule\n");
+ $$ = ap(outdent_fn,$1); } ;
+
+unit:
+ symbol|
+ symbol '*'
+ = { $$ = ap(G_STAR,$1); }|
+ symbol '+'
+ = { $$ = ap2(G_SEQ,$1,ap2(G_SEQ,ap(G_STAR,$1),ap(G_RULE,ap(C,P)))); }|
+ symbol '?'
+ = { $$ = ap(G_OPT,$1); };
+
+symbol:
+ NAME
+ = { extern word NEW;
+ nonterminals=newadd1($1,nonterminals);
+ if(NEW)ntmap=cons(cons($1,lasth),ntmap); }|
+ ENDSY
+ = { $$ = G_END; }|
+ CONST
+ = { if(!isstring($1))
+ printf("%ssyntax error: illegal terminal ",echoing?"\n":""),
+ out(stdout,$1),printf(" (should be string-const)\n"),
+ acterror();
+ $$ = ap(G_SYMB,$1); }|
+ '^'
+ = { $$=G_STATE; }|
+ {inbnf=0;} '[' exp {inbnf=1;} ']'
+ = { $$ = ap(G_SUCHTHAT,$3); }|
+ '-'
+ = { $$ = G_ANY; };
+
+%%
+/* end of Miranda rules */
+