--- /dev/null
+/* $Header$ */
+
+#define LLin(x) (LLsets[(x)+LLi]&LLb)
+
+extern short *LLptr;
+extern char LLsets[];
+extern int LLi, LLb;
+extern int LLsymb;
+extern int LLcsymb;
+extern int LLscd;
+
+# include "Lpars.h"
--- /dev/null
+/*
+ * Some grammar independent code.
+ * This file is copied into Lpars.c.
+ */
+
+static char *rcsid = "$Header$";
+
+#define LLSTSIZ 1024
+static short LLstack[LLSTSIZ]; /* Recovery stack */
+short * LLptr; /* ptr in it */
+#define LLmax (&LLstack[LLSTSIZ-1]) /* if beyond this, overflow */
+int LLscd; /* lookahead done or not? */
+int LLb,LLi;
+int LLsymb;
+int LLcsymb;
+static int LLlevel;
+static short * LLbase;
+
+static struct LLsaved {
+ int LLs_i, LLs_b, LLs_s, LLs_c, LLs_t;
+ short *LLs_p, *LLs_x;
+} LLsaved[LL_MAX];
+
+/* In this file are defined: */
+extern LLcheck();
+extern LLscan();
+extern LLpush();
+extern LLlpush();
+extern int LLpop();
+extern int LLsskip();
+static LLerror();
+extern LLnewlevel();
+extern LLoldlevel();
+
+LLcheck() {
+ register c;
+ /*
+ * The symbol to be checked is on the stack.
+ */
+ if (!LLscd) {
+ if ((c = LL_LEXI()) <= 0) c = EOFILE;
+ LLsymb = c;
+ }
+ else LLscd = 0;
+ if (LLsymb == *--LLptr) return;
+ /*
+ * If we come here, an error has been detected.
+ * LLpop will try and recover
+ */
+ LLptr++;
+ while (LLindex[LLsymb] < 0) {
+ LLerror(0);
+ if ((LLsymb = LL_LEXI()) <= 0) LLsymb = EOFILE;
+ }
+ LLcsymb = LLindex[LLsymb];
+ LLb = LLbyte[LLcsymb];
+ LLi = LLcsymb>>3;
+ LLscd = 1;
+ if (!LLpop()) LLerror(*LLptr);
+ LLscd = 0;
+}
+
+LLscan(t) {
+ /*
+ * Check if the next symbol is equal to the parameter
+ */
+ if (!LLscd) {
+ if ((LLsymb = LL_LEXI()) <= 0) LLsymb = EOFILE;
+ }
+ else LLscd = 0;
+ if (LLsymb == t) return;
+ /*
+ * If we come here, an error has been detected
+ */
+ LLpush(t);
+ LLscd = 1;
+ while (LLindex[LLsymb] < 0) {
+ LLerror(0);
+ if ((LLsymb = LL_LEXI()) <= 0) LLsymb = EOFILE;
+ }
+ LLcsymb = LLindex[LLsymb];
+ LLb = LLbyte[LLcsymb];
+ LLi = LLcsymb>>3;
+ if (!LLpop()) LLerror(t);
+ LLscd = 0;
+}
+
+LLpush(t) {
+ if (LLptr == LLmax) {
+ LLerror(-1);
+ }
+ *LLptr++ = t;
+}
+
+LLlpush(d) {
+ register i;
+ register short *p;
+
+ p = &LLlists[d];
+ i = *p++;
+ while(i--) {
+ if (LLptr == LLmax) {
+ LLerror(-1);
+ }
+ *LLptr++ = *p++;
+ }
+}
+
+LLsskip() {
+ /*
+ * Error recovery, and not only that!
+ * Skip symbols until one is found that is on the stack.
+ * Return 1 if it is on top of the stack
+ */
+ register short *t;
+ register i;
+
+ for (;;) {
+ if (!LLscd) {
+lab:
+ if ((i = LL_LEXI()) <= 0) i = EOFILE;
+ LLsymb = i;
+ if ((i = LLindex[i]) < 0) {
+ LLerror(0);
+ goto lab;
+ /*
+ * Ugly, but we want speed
+ * on possibly correct symbols !!
+ * So, no breaks out of "for (;;)"
+ */
+ }
+ LLcsymb = i;
+ LLb = LLbyte[i];
+ LLi = (i>>3);
+ LLscd = 1;
+ }
+ t = LLptr-1;
+ i = *t;
+ if (!((i<=0 && LLsets[LLi-i]&LLb)||i==LLsymb)) {
+ while (--t >= LLbase) {
+ /*
+ * If the element on the stack is negative,
+ * its opposite is an index in the setarray,
+ * otherwise it is a terminal symbol
+ */
+ i = *t;
+ if ((i<=0&&LLsets[LLi-i]&LLb)||i==LLsymb){
+ break;
+ }
+ }
+ if (t >= LLbase) break;
+ LLerror(0);
+ LLscd = 0;
+ }
+ else {
+ return 1;
+ }
+ }
+ return t == LLptr - 1;
+}
+
+LLpop() {
+ register i;
+
+ i = LLsskip();
+ LLptr--;
+ return i;
+}
+
+static
+LLerror(d) {
+
+ LLmessage(d);
+ if (d < 0) exit(1);
+}
+
+LLnewlevel() {
+ register struct LLsaved *p;
+
+ if (!LLlevel++) {
+ LLptr = LLstack;
+ LLbase = LLstack;
+ LLpush(EOFILE);
+ }
+ else {
+ if (LLlevel > LL_MAX) LLerror(-1);
+ p = &LLsaved[LLlevel - 2];
+ p->LLs_p = LLptr;
+ p->LLs_i = LLi;
+ p->LLs_b = LLb;
+ p->LLs_s = LLsymb;
+ p->LLs_t = LLcsymb;
+ p->LLs_c = LLscd;
+ p->LLs_x = LLbase;
+ LLbase = LLptr;
+ LLpush(EOFILE);
+ }
+}
+
+LLoldlevel() {
+ register struct LLsaved *p;
+
+ LLcheck();
+ if (--LLlevel) {
+ p = &LLsaved[LLlevel-1];
+ LLptr = p->LLs_p;
+ LLi = p->LLs_i;
+ LLb = p->LLs_b;
+ LLsymb = p->LLs_s;
+ LLcsymb = p->LLs_t;
+ LLbase = p->LLs_x;
+ LLscd = p->LLs_c;
+ }
+}
+
--- /dev/null
+/*
+ * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ *
+ * This product is part of the Amsterdam Compiler Kit.
+ *
+ * Permission to use, sell, duplicate or disclose this software must be
+ * obtained in writing. Requests for such permissions may be sent to
+ *
+ * Dr. Andrew S. Tanenbaum
+ * Wiskundig Seminarium
+ * Vrije Universiteit
+ * Postbox 7161
+ * 1007 MC Amsterdam
+ * The Netherlands
+ *
+ */
+
+/*
+ * L L G E N
+ *
+ * An Extended LL(1) Parser Generator
+ *
+ * Author : Ceriel J.H. Jacobs
+ */
+
+/*
+ * alloc.c
+ * Interface to malloc() and realloc()
+ */
+
+# include "types.h"
+# include "extern.h"
+
+static string rcsid = "$Header$";
+
+static string e_nomem = "Out of memory";
+
+p_mem
+alloc(size) unsigned size; {
+ register p_mem p;
+ p_mem malloc();
+
+ if ((p = malloc(size)) == 0) fatal(linecount,e_nomem);
+ return p;
+}
+
+p_mem
+ralloc(p,size) p_mem p; unsigned size; {
+ register p_mem q;
+ p_mem realloc();
+
+ if ((q = realloc(p,size)) == 0) fatal(linecount,e_nomem);
+ return q;
+}
--- /dev/null
+/*
+ * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ *
+ * This product is part of the Amsterdam Compiler Kit.
+ *
+ * Permission to use, sell, duplicate or disclose this software must be
+ * obtained in writing. Requests for such permissions may be sent to
+ *
+ * Dr. Andrew S. Tanenbaum
+ * Wiskundig Seminarium
+ * Vrije Universiteit
+ * Postbox 7161
+ * 1007 MC Amsterdam
+ * The Netherlands
+ *
+ */
+
+/*
+ * L L G E N
+ *
+ * An Extended LL(1) Parser Generator
+ *
+ * Author : Ceriel J.H. Jacobs
+ */
+
+/*
+ * assert.h $Header$
+ * an assertion macro
+ */
+
+#ifndef NDEBUG
+#define assert(x) if(!(x)) badassertion("x",__FILE__,__LINE__)
+#else
+#define assert(x) /* nothing */
+#endif
--- /dev/null
+/*
+ * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ *
+ * This product is part of the Amsterdam Compiler Kit.
+ *
+ * Permission to use, sell, duplicate or disclose this software must be
+ * obtained in writing. Requests for such permissions may be sent to
+ *
+ * Dr. Andrew S. Tanenbaum
+ * Wiskundig Seminarium
+ * Vrije Universiteit
+ * Postbox 7161
+ * 1007 MC Amsterdam
+ * The Netherlands
+ *
+ */
+
+/*
+ * L L G E N
+ *
+ * An Extended LL(1) Parser Generator
+ *
+ * Author : Ceriel J.H. Jacobs
+ */
+
+/*
+ * extern.h $Header$
+ * Miscellanious constants and
+ * some variables that are visible in more than one file
+ */
+
+/*
+ * options for the identifier search routine
+ */
+# define JUSTLOOKING 0
+# define ENTERING 1
+# define BOTH 2
+
+/*
+ * Now for some declarations
+ */
+
+extern char ltext[]; /* input buffer */
+extern int nnonterms; /* number of nonterminals */
+extern int nterminals; /* number of terminals */
+extern p_start start; /* will contain startsymbols */
+extern int linecount; /* line number */
+extern int assval; /* to create difference between literals
+ * and other terminals
+ */
+extern t_nont nonterms[]; /* the nonterminal array */
+extern p_nont maxnt; /* is filled up until here */
+extern int order[]; /* order of nonterminals in the grammar,
+ * important because actions are copied to
+ * a temporary file in the order in which they
+ * were read
+ */
+extern int *maxorder; /* will contain &order[nnonterms] */
+extern t_entry h_entry[]; /* terminal and nonterminal entrys,
+ * first NTERMINAL entrys reserved
+ * for terminals
+ */
+extern p_entry max_t_ent; /* will contain &h_entry[nterminals] */
+# define min_nt_ent &h_entry[NTERMINALS]
+extern string pentry[]; /* pointers to various allocated things */
+extern string e_noopen; /* Error message string used often */
+extern int verbose; /* Level of verbosity */
+extern string lexical; /* name of lexical analyser */
+extern int ntneeded; /* ntneeded = 1 if nonterminals are included
+ * in the sets.
+ */
+extern int ntprint; /* ntprint = 1 if they must be printed too in
+ * the LL.output file (-x option)
+ */
+# ifndef NDEBUG
+extern int debug;
+# endif not NDEBUG
+extern p_file files,pfile; /* pointers to file structure.
+ * "files" points to the start of the
+ * list */
+extern string LLgenid; /* LLgen identification string */
+extern t_token lextoken; /* the current token */
+extern int nerrors;
+extern int fflag; /* Enable compiler to generate jump tables
+ * for switches?
+ */
--- /dev/null
+/*
+ * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ *
+ * This product is part of the Amsterdam Compiler Kit.
+ *
+ * Permission to use, sell, duplicate or disclose this software must be
+ * obtained in writing. Requests for such permissions may be sent to
+ *
+ * Dr. Andrew S. Tanenbaum
+ * Wiskundig Seminarium
+ * Vrije Universiteit
+ * Postbox 7161
+ * 1007 MC Amsterdam
+ * The Netherlands
+ *
+ */
+
+/*
+ * L L G E N
+ *
+ * An Extended LL(1) Parser Generator
+ *
+ * Author : Ceriel J.H. Jacobs
+ */
+
+/*
+ * global.c
+ * Contains declarations visible in several other source files
+ */
+
+# include "types.h"
+# include "io.h"
+# include "tunable.h"
+
+static string rcsid = "$Header$";
+
+char ltext[LTEXTSZ];
+t_entry h_entry[NTERMINALS+NNONTERMS+1];
+p_entry max_t_ent;
+t_nont nonterms[NNONTERMS+1];
+int nnonterms;
+int nterminals;
+int order[NNONTERMS+1];
+int *maxorder;
+p_start start;
+int linecount;
+int assval;
+string pentry[ENTSIZ];
+FILE *fout;
+FILE *fpars;
+FILE *finput;
+FILE *fact;
+p_nont maxnt;
+string f_pars = PARSERFILE;
+string f_out = OUTFILE;
+string f_temp = ACTFILE;
+string f_input;
+string e_noopen = "Cannot open %s";
+int verbose;
+string lexical;
+int ntneeded;
+int ntprint;
+# ifndef NDEBUG
+int debug;
+# endif not NDEBUG
+p_file files;
+p_file pfile;
+string LLgenid = "/* LLgen generated code from source %s */\n";
+t_token lextoken;
+int nerrors;
+int fflag;
--- /dev/null
+/*
+ * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ *
+ * This product is part of the Amsterdam Compiler Kit.
+ *
+ * Permission to use, sell, duplicate or disclose this software must be
+ * obtained in writing. Requests for such permissions may be sent to
+ *
+ * Dr. Andrew S. Tanenbaum
+ * Wiskundig Seminarium
+ * Vrije Universiteit
+ * Postbox 7161
+ * 1007 MC Amsterdam
+ * The Netherlands
+ *
+ */
+
+/*
+ * L L G E N
+ *
+ * An Extended LL(1) Parser Generator
+ *
+ * Author : Ceriel J.H. Jacobs
+ */
+
+/*
+ * io.h $Header$
+ * Some important file names and variables
+ */
+
+# include <stdio.h>
+# include <ctype.h>
+
+/* FILES */
+
+# define OUTFILE "LL.output" /* -v option */
+# define PARSERFILE "LL.xxx" /* This is what we want */
+# define ACTFILE "LL.temp" /* temporary file to save actions */
+# define HFILE "Lpars.h" /* file for "#define's " */
+# define RFILE "Lpars.c" /* Error recovery */
+
+extern FILE *finput;
+extern FILE *fpars;
+extern FILE *fact;
+extern FILE *fout;
+extern string f_pars;
+extern string f_temp;
+extern string f_out;
+extern string f_input;
--- /dev/null
+/*
+ * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ *
+ * This product is part of the Amsterdam Compiler Kit.
+ *
+ * Permission to use, sell, duplicate or disclose this software must be
+ * obtained in writing. Requests for such permissions may be sent to
+ *
+ * Dr. Andrew S. Tanenbaum
+ * Wiskundig Seminarium
+ * Vrije Universiteit
+ * Postbox 7161
+ * 1007 MC Amsterdam
+ * The Netherlands
+ *
+ */
+
+/*
+ * L L G E N
+ *
+ * An Extended LL(1) Parser Generator
+ *
+ * Author : Ceriel J.H. Jacobs
+ */
+
+/*
+ * machdep.c
+ * Machine dependant things
+ */
+
+
+# include "types.h"
+
+static string rcsid = "$Header$";
+
+/* In this file the following routines are defined: */
+extern UNLINK();
+extern RENAME();
+extern string libpath();
+
+UNLINK(x) string x; {
+ unlink(x); /* systemcall to remove file */
+}
+
+RENAME(x,y) string x,y; {
+ unlink(y);
+ if(link(x,y)!=0)fatal(1,"Cannot link to %s",y);
+ unlink(x);
+}
+
+string
+libpath(s) char *s; {
+ static char buf[100];
+
+ strcpy(buf,"/usr/local/lib/LLgen/");
+ strcat(buf,s);
+ return buf;
+}
--- /dev/null
+/*
+ * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ *
+ * This product is part of the Amsterdam Compiler Kit.
+ *
+ * Permission to use, sell, duplicate or disclose this software must be
+ * obtained in writing. Requests for such permissions may be sent to
+ *
+ * Dr. Andrew S. Tanenbaum
+ * Wiskundig Seminarium
+ * Vrije Universiteit
+ * Postbox 7161
+ * 1007 MC Amsterdam
+ * The Netherlands
+ *
+ */
+
+/*
+ * L L G E N
+ *
+ * An Extended LL(1) Parser Generator
+ *
+ * Author : Ceriel J.H. Jacobs
+ */
+
+/*
+ * main.c
+ * Contains main program, and some error message routines
+ */
+
+# include "types.h"
+# include "io.h"
+# include "extern.h"
+# include "sets.h"
+# include "assert.h"
+
+static string rcsid = "$Header$";
+
+static string rec_file;
+static string incl_file;
+
+/* In this file the following routines are defined: */
+extern int main();
+STATIC readgrammar();
+extern error();
+extern fatal();
+extern comfatal();
+extern copyfile();
+extern install();
+# ifndef NDEBUG
+extern badassertion();
+# endif not NDEBUG
+
+main(argc,argv) register string argv[]; {
+ register string arg;
+ string libpath();
+ int nflag = 0;
+
+ /* Initialize */
+
+ maxorder = order;
+ assval = 0400;
+ /* read options */
+
+ while (argc >= 2 && (arg = argv[1], *arg == '-')) {
+ while (*++arg) {
+ switch(*arg) {
+ case 'v':
+ case 'V':
+ verbose++;
+ continue;
+ case 'n':
+ case 'N':
+ nflag++;
+ continue;
+ case 'f':
+ case 'F':
+ fflag++;
+ continue;
+# ifndef NDEBUG
+ case 'a':
+ case 'A':
+ debug++;
+ continue;
+# endif not NDEBUG
+ case 'r':
+ case 'R':
+ if (rec_file) {
+ fprintf(stderr,"duplicate -r flag\n");
+ exit(1);
+ }
+ rec_file = ++arg;
+ break;
+ case 'i':
+ case 'I':
+ if (incl_file) {
+ fprintf(stderr,"duplicate -i flag\n");
+ exit(1);
+ }
+ incl_file = ++arg;
+ break;
+ case 'x':
+ case 'X':
+ ntneeded = 1;
+ ntprint = 1;
+ continue;
+ default:
+ fprintf(stderr,"illegal option : %c\n",*arg);
+ return 1;
+ }
+ break;
+ }
+ argv++;
+ argc--;
+ }
+ /*
+ * Now check wether the sets should include nonterminals
+ */
+ if (verbose == 2) ntneeded = 1;
+ else if (! verbose) ntneeded = 0;
+ /*
+ * Initialise
+ */
+ if (!rec_file) rec_file = libpath("rec");
+ if (!incl_file) incl_file = libpath("incl");
+ if ((fact = fopen(f_temp,"w")) == NULL) {
+ fputs("Cannot create temporary\n",stderr);
+ return 1;
+ }
+ name_init();
+ readgrammar(argc,argv);
+ if (nflag) comfatal();
+ setinit(ntneeded);
+ maxnt = &nonterms[nnonterms];
+ max_t_ent = &h_entry[nterminals];
+ fclose(fact);
+ /*
+ * Now, the grammar is read. Do some computations
+ */
+ co_reach(); /* Check for undefined and unreachable */
+ if (nerrors) comfatal();
+ createsets();
+ co_empty(); /* Which nonterminals produce empty? */
+ co_first(); /* Computes first sets */
+ co_follow(); /* Computes follow sets */
+ co_symb(); /* Computes choice sets in alternations */
+ conflchecks(); /* Checks for conflicts etc, and also
+ * takes care of LL.output etc
+ */
+ if (nerrors) comfatal();
+ co_contains(); /* Computes the contains sets */
+ co_safes(); /* Computes safe terms and nonterminals.
+ * Safe means : always called with a terminal
+ * symbol that is guarantied to be eaten by
+ * the term
+ */
+ if (argc-- == 1) {
+ fputs("No code generation for input from standard input\n",stderr);
+ } else gencode(argc);
+ UNLINK(f_temp);
+ UNLINK(f_pars);
+ return 0;
+}
+
+STATIC
+readgrammar(argc,argv) char *argv[]; {
+ /*
+ * Do just what the name suggests : read the grammar
+ */
+ register p_file p;
+ p_mem alloc();
+
+ linecount = 0;
+ f_input = "no filename";
+ /*
+ * Build the file structure
+ */
+ files = p = (p_file) alloc((unsigned) (argc+1) * sizeof(t_file));
+ if (argc-- == 1) {
+ finput = stdin;
+ p->f_name = f_input = "standard input";
+ p->f_firsts = 0;
+ p->f_start = maxorder;
+ pfile = p;
+ LLparse();
+ p->f_end = maxorder - 1;
+ p++;
+ } else {
+ while (argc--) {
+ if ((finput = fopen(f_input=argv[1],"r")) == NULL) {
+ fatal(0,e_noopen,f_input);
+ }
+ linecount = 0;
+ p->f_name = f_input;
+ p->f_start = maxorder;
+ p->f_firsts = 0;
+ pfile = p;
+ LLparse();
+ p->f_end = maxorder-1;
+ p++;
+ argv++;
+ fclose(finput);
+ }
+ }
+ p->f_start = maxorder+1;
+ p->f_end = maxorder;
+ if (! lexical) lexical = "yylex";
+ /*
+ * There must be a start symbol!
+ */
+ if (start == 0) {
+ fatal(linecount,"Missing %%start");
+ }
+ if (nerrors) comfatal();
+}
+
+/* VARARGS1 */
+error(lineno,s,t,u) string s,t,u; {
+ /*
+ * Just an error message
+ */
+ register FILE *f;
+
+ f = stderr;
+ ++nerrors;
+ if (lineno) fprintf(f,"\"%s\", line %d : ",f_input,lineno);
+ else fprintf(f,"\"%s\" : ",f_input);
+ fprintf(f,s,t,u);
+ putc('\n',f);
+}
+
+/* VARARGS1 */
+fatal(lineno,s,t,u) string s,t,u; {
+ /*
+ * Fatal error
+ */
+ error(lineno,s,t,u);
+ comfatal();
+}
+
+comfatal() {
+ /*
+ * Some common code for exit on errors
+ */
+ if (fact != NULL) {
+ fclose(fact);
+ UNLINK(f_temp);
+ }
+ if (fpars != NULL) fclose(fpars);
+ UNLINK(f_pars);
+ exit(1);
+}
+
+copyfile(n) {
+ /*
+ * Copies a file indicated by the parameter to filedescriptor fpars.
+ * If n != 0, the error recovery routines are copied,
+ * otherwise a standard header is.
+ */
+ register c;
+ register FILE *f;
+
+ if ((f = fopen(n?rec_file:incl_file,"r")) == NULL) {
+ fatal(0,"Cannot open libraryfile, call an expert");
+ }
+ while ((c = getc(f)) != EOF) putc(c,fpars);
+}
+
+install(target, source) string target, source; {
+ /*
+ * Copy the temporary file generated from source to target
+ * if allowed (which means that the target must be generated
+ * by LLgen from the source, or that the target is not present
+ */
+ register c;
+ register FILE *f1;
+ register FILE *f2;
+ register string s1;
+ register int i;
+ char buf[100];
+
+ /*
+ * First open temporary, generated for source
+ */
+ if ((f1 = fopen(f_pars,"r")) == NULL) {
+ fatal(0,e_noopen,f_pars);
+ }
+ i = 0;
+ /*
+ * Now open target for reading
+ */
+ if ((f2 = fopen(target,"r")) == NULL) {
+ i = 1;
+ fclose(f1);
+ }
+ else {
+ /*
+ * Create string recognised by LLgen. The target must
+ * start with that!
+ */
+ (int) sprintf(buf,LLgenid,source ? source : ".");
+ s1 = buf;
+ while (*s1 != '\0' && *s1++ == getc(f2)) { /* nothing */ }
+ /*
+ * Ai,ai, it did not
+ */
+ if (*s1 != '\0') {
+ fatal(0,"%s : not a file generated by LLgen",target);
+ }
+ rewind(f2);
+ /*
+ * Now compare the target with the temporary
+ */
+ while ((c = getc(f1)) != EOF && c == getc(f2)) { /* nothing */}
+ if (c != EOF || getc(f2) != EOF) i = 1;
+ fclose(f1);
+ fclose(f2);
+ }
+ /*
+ * Here, if i != 0 the target must be recreated
+ */
+ if (i) RENAME(f_pars,target);
+}
+
+#ifndef NDEBUG
+badassertion(asstr,file,line) char *asstr, *file; {
+
+ fprintf(stderr,"Assertion \"%s\" failed %s(%d)\n",asstr,file,line);
+ if (fact != NULL) fclose(fact);
+ if (fpars != NULL) fclose(fpars);
+ abort();
+}
+#endif
--- /dev/null
+/*
+ * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ *
+ * This product is part of the Amsterdam Compiler Kit.
+ *
+ * Permission to use, sell, duplicate or disclose this software must be
+ * obtained in writing. Requests for such permissions may be sent to
+ *
+ * Dr. Andrew S. Tanenbaum
+ * Wiskundig Seminarium
+ * Vrije Universiteit
+ * Postbox 7161
+ * 1007 MC Amsterdam
+ * The Netherlands
+ *
+ */
+
+/*
+ * L L G E N
+ *
+ * An Extended LL(1) Parser Generator
+ *
+ * Author : Ceriel J.H. Jacobs
+ */
+
+/*
+ * name.c
+ * Defines the symboltable search routine and an initialising routine
+ */
+
+# include "types.h"
+# include "tunable.h"
+# include "extern.h"
+# include "assert.h"
+# include "io.h"
+
+static string rcsid = "$Header$";
+
+# define HASHSIZE 128
+
+static char name[NAMESZ]; /* space for names */
+static int iname; /* index in nametable */
+static p_entry h_root[HASHSIZE]; /* hash table */
+static string e_literal = "Illegal literal";
+
+/* Defined in this file are: */
+extern string store();
+extern name_init();
+STATIC int hash();
+extern t_gram search();
+
+string
+store(s) register string s; {
+ /*
+ * Store a string s in the name table
+ */
+ register string t,u;
+
+ u = t = &name[iname];
+ do { if (u > &name[NAMESZ-1]) fatal(linecount,"name table overflow");
+ else *u++ = *s;
+ } while (*s++);
+ iname = u - name;
+ return t;
+}
+
+name_init() {
+ /*
+ * Initialise hash-table and enter special terminal EOFILE
+ */
+ register p_entry *p;
+ t_gram search();
+
+ for(p = h_root; p<= &h_root[HASHSIZE-1]; p++) *p = 0;
+ search(TERMINAL,"EOFILE",ENTERING);
+}
+
+STATIC int
+hash(str) string str; {
+ /*
+ * Compute the hash for string str
+ */
+ register i;
+ register string l;
+
+ l = str;
+ i = 0;
+ while (*l != '\0') i += *l++ & 0377;
+ i += l - str;
+ return i % HASHSIZE;
+}
+
+t_gram
+search(type,str,option) register string str; {
+ /*
+ * Search for object str.
+ * It has type UNKNOWN, LITERAL, TERMINAL or NONTERM.
+ * option can be ENTERING, JUSTLOOKING or BOTH.
+ */
+ register int val;
+ register p_entry p;
+ t_gram r;
+ register int i;
+
+ g_init(&r);
+ g_setcont(&r,UNDEFINED);
+ r.g_lineno = linecount;
+ i = hash(str);
+ /*
+ * Walk hash chain
+ */
+ for (p = h_root[i]; p != (p_entry) 0; p = p->h_next) {
+ if(!strcmp(p->h_name,str)) {
+ val = p - h_entry;
+ if (type == LITERAL &&
+ (val >= NTERMINALS || p->h_num >= 0400)) continue;
+ if (val>=NTERMINALS) {
+ /* Should be a nonterminal */
+ if (type == TERMINAL) {
+ error(linecount,
+ "%s : terminal expected",
+ str);
+ }
+ g_settype(&r,NONTERM);
+ g_setnont(&r,val - NTERMINALS);
+ } else {
+ if (type != LITERAL && p->h_num < 0400) {
+ continue;
+ }
+ if (type == NONTERM) {
+ error(linecount,
+ "%s : nonterminal expected",
+ str);
+ continue;
+ }
+ g_setnont(&r, val);
+ g_settype(&r, TERMINAL);
+ }
+ if (option==ENTERING) {
+ error(linecount,
+ "%s : already defined",str);
+ }
+ return r;
+ }
+ }
+ if (option == JUSTLOOKING) return r;
+ if (type == TERMINAL || type == LITERAL) {
+ if (nterminals == NTERMINALS) {
+ fatal(linecount,"too many terminals");
+ }
+ p = &h_entry[nterminals];
+ } else {
+ /*
+ * type == NONTERM || type == UNKNOWN
+ * UNKNOWN and not yet declared means : NONTERM
+ */
+ if (nnonterms == NNONTERMS) {
+ fatal(linecount,"too many nonterminals");
+ }
+ p = &h_entry[NTERMINALS+nnonterms];
+ }
+ p->h_name = store(str);
+ p->h_next = h_root[i];
+ h_root[i] = p;
+ if (type == NONTERM || type == UNKNOWN) {
+ register p_nont q;
+
+ q = &nonterms[nnonterms];
+ q->n_rule = 0;
+ q->n_string = f_input;
+ q->n_follow = 0;
+ q->n_flags = 0;
+ q->n_contains = 0;
+ p->h_num = 0;
+ g_settype(&r, NONTERM);
+ g_setnont(&r, nnonterms);
+ nnonterms++;
+ return r;
+ }
+ if (type == LITERAL) {
+ if (str[0] == '\\') {
+ /*
+ * Handle escapes in literals
+ */
+ if (str[2] == '\0') {
+ switch(str[1]) {
+ case 'n' :
+ val = '\n';
+ break;
+ case 'r' :
+ val = '\r';
+ break;
+ case 'b' :
+ val = '\b';
+ break;
+ case 'f' :
+ val = '\f';
+ break;
+ case 't' :
+ val = '\t';
+ break;
+ case '\'':
+ val = '\'';
+ break;
+ case '\\':
+ val = '\\';
+ break;
+ default :
+ error(linecount,e_literal);
+ }
+ } else {
+ /*
+ * Here, str[2] != '\0'
+ */
+ if (str[1] > '3' || str[1] < '0' ||
+ str[2] > '7' || str[2] < '0' ||
+ str[3] > '7' || str[3] < '0' ||
+ str[4] != '\0') error(linecount,e_literal);
+ val = 64*str[1] - 73*'0' + 8*str[2] + str[3];
+ }
+ } else {
+ /*
+ * No escape in literal
+ */
+ if (str[1] == '\0') val = str[0];
+ else error(linecount,e_literal);
+ }
+ p->h_num = val;
+ } else {
+ /*
+ * Here, type = TERMINAL
+ */
+ p->h_num = assval++;
+ }
+ g_settype(&r, TERMINAL);
+ g_setnont(&r, nterminals);
+ nterminals++;
+ return r;
+}
--- /dev/null
+/*
+ * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ *
+ * This product is part of the Amsterdam Compiler Kit.
+ *
+ * Permission to use, sell, duplicate or disclose this software must be
+ * obtained in writing. Requests for such permissions may be sent to
+ *
+ * Dr. Andrew S. Tanenbaum
+ * Wiskundig Seminarium
+ * Vrije Universiteit
+ * Postbox 7161
+ * 1007 MC Amsterdam
+ * The Netherlands
+ *
+ */
+
+/*
+ * L L G E N
+ *
+ * An Extended LL(1) Parser Generator
+ *
+ * Author : Ceriel J.H. Jacobs
+ */
+
+/*
+ * reach.c
+ * Determine which nonterminals are reachable, and also check that they
+ * are all defined.
+ */
+
+# include "tunable.h"
+# include "types.h"
+# include "extern.h"
+# include "io.h"
+# include "assert.h"
+
+static string rcsid = "$Header$";
+
+/* In this file the following routines are defined: */
+extern co_reach();
+STATIC reachable();
+STATIC reachwalk();
+
+co_reach() {
+ /*
+ * Check for undefined or unreachable nonterminals.
+ * An undefined nonterminal is a fatal error!
+ */
+ register p_nont p;
+ register p_start st;
+ register p_file x = files;
+ register int *s;
+
+ /* Check for undefined nonterminals */
+ for (p = nonterms; p < maxnt; p++) {
+ if (! p->n_rule) {
+ f_input = p->n_string;
+ fatal(p->n_lineno,"nonterminal %s not defined",
+ (min_nt_ent + (p - nonterms))->h_name);
+ }
+ }
+ /*
+ * Walk the grammar rules, starting with the startsymbols
+ * Mark the nonterminals that are encountered with the flag
+ * REACHABLE, and walk their rules, if not done before
+ */
+ for (st = start; st; st = st->ff_next) reachable(st->ff_nont);
+ /*
+ * Now check for unreachable nonterminals
+ */
+ for (; x->f_end < maxorder; x++) {
+ f_input = x->f_name;
+ for (s = x->f_start; s <= x->f_end; s++) {
+ p = &nonterms[*s];
+ if (! (p->n_flags & REACHABLE)) {
+ error(p->n_lineno,"nonterminal %s unreachable",
+ (min_nt_ent + (p - nonterms))->h_name);
+ }
+ }
+ }
+}
+
+STATIC
+reachable(p) register p_nont p; {
+ /*
+ * Enter the fact that p is reachable, and look for implications
+ */
+ if (! (p->n_flags & REACHABLE)) {
+ p->n_flags |= REACHABLE;
+ /*
+ * Now walk its grammar rule
+ */
+ reachwalk(p->n_rule);
+ }
+}
+
+STATIC
+reachwalk(p) register p_gram p; {
+ /*
+ * Walk through rule p, looking for nonterminals.
+ * The nonterminals found are entered as reachable
+ */
+
+ for (;;) {
+ switch(g_gettype(p)) {
+ case ALTERNATION :
+ reachwalk(((p_link) pentry[g_getcont(p)])->l_rule);
+ break;
+ case TERM :
+ reachwalk(((p_term) pentry[g_getcont(p)])->t_rule);
+ break;
+ case NONTERM :
+ reachable(&nonterms[g_getnont(p)]);
+ break;
+ case EORULE :
+ return;
+ }
+ p++;
+ }
+}
--- /dev/null
+/*
+ * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ *
+ * This product is part of the Amsterdam Compiler Kit.
+ *
+ * Permission to use, sell, duplicate or disclose this software must be
+ * obtained in writing. Requests for such permissions may be sent to
+ *
+ * Dr. Andrew S. Tanenbaum
+ * Wiskundig Seminarium
+ * Vrije Universiteit
+ * Postbox 7161
+ * 1007 MC Amsterdam
+ * The Netherlands
+ *
+ */
+
+/*
+ * L L G E N
+ *
+ * An Extended LL(1) Parser Generator
+ *
+ * Author : Ceriel J.H. Jacobs
+ */
+
+/*
+ * sets.h $Header$
+ * Some macros that deal with bitsets and their size
+ */
+
+# define BITS (8 * sizeof (int))
+# define IN(a,i) ((a)[(i)/BITS] & (1<<((i) % BITS)))
+# define NTIN(a,i) ((a)[((i)+tbitset)/BITS]&(1<<((i)%BITS)))
+# define PUTIN(a,i) ((a)[(i)/BITS] |=(1<<((i) % BITS)))
+# define NTPUTIN(a,i) ((a)[((i)+tbitset)/BITS]|=(1<<((i)%BITS)))
+# define NBYTES(n) (((n) + 7) / 8)
+/*
+ * The next two macros operate on byte counts!
+ */
+# define NINTS(n) (((n) + (int) (sizeof(int) - 1)) / (int) sizeof(int))
+# define ALIGN(n) (NINTS(n) * (int) sizeof (int))
+
+extern int tbitset;
+extern p_set *setptr,*maxptr,*topptr;
+extern int tsetsize,setsize;
--- /dev/null
+/*
+ * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ *
+ * This product is part of the Amsterdam Compiler Kit.
+ *
+ * Permission to use, sell, duplicate or disclose this software must be
+ * obtained in writing. Requests for such permissions may be sent to
+ *
+ * Dr. Andrew S. Tanenbaum
+ * Wiskundig Seminarium
+ * Vrije Universiteit
+ * Postbox 7161
+ * 1007 MC Amsterdam
+ * The Netherlands
+ *
+ */
+
+/*
+ * L L G E N
+ *
+ * An Extended LL(1) Parser Generator
+ *
+ * Author : Ceriel J.H. Jacobs
+ */
+
+/*
+ * tokens.g
+ * Defines the tokens for the grammar of LLgen.
+ * The lexical analyser and LLmes are also included here.
+ */
+
+{
+# include "types.h"
+# include "io.h"
+# include "tunable.h"
+# include "extern.h"
+# include "assert.h"
+
+static string rcsid = "$Header$";
+
+/* Here are defined : */
+extern int scanner();
+extern LLmessage();
+extern int input();
+extern unput();
+extern skipcomment();
+STATIC linedirective();
+STATIC string cpy();
+STATIC string vallookup();
+}
+
+/* Classes */
+
+%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 */
+
+/* Keywords */
+
+%token C_TOKEN ;
+%token C_START ;
+%token C_IF ;
+%token C_WHILE ;
+%token C_PERSISTENT ;
+%token C_FIRST ;
+%token C_LEXICAL ;
+%token C_AVOID ;
+%token C_PREFER ;
+%token C_DEFAULT ;
+
+%lexical scanner ;
+
+{
+
+/*
+ * Structure for a keyword
+ */
+
+struct keyword {
+ string w_word;
+ int w_value;
+};
+
+/*
+ * The list of keywords, the most often used keywords come first.
+ * Linear search is used, as there are not many keywords
+ */
+
+static struct keyword resword[] = {
+ { "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 },
+ { "lexical", C_LEXICAL },
+ { 0, 0 }
+};
+
+static t_token savedtok; /* to save lextoken in case of an insertion */
+static int nostartline; /* = 0 if at the start of a line */
+
+scanner() {
+ /*
+ * Lexical analyser, what else
+ */
+ register ch; /* Current char */
+ register i;
+ register reserved = 0; /* reserved word? */
+ int last; /* Char before current char */
+
+ if (savedtok.t_tokno) { /*
+ * A token has been inserted.
+ * Now deliver the last lextoken again
+ */
+ lextoken = savedtok;
+ savedtok.t_tokno = 0;
+ return lextoken.t_tokno;
+ }
+ for (;;) { /*
+ * First, skip space, comments, line directives, etc
+ */
+ do ch = input();
+ while(isspace(ch));
+ if (ch == '/') skipcomment(0);
+ else if (ch == '#' && !nostartline) linedirective();
+ else break;
+ }
+ /*
+ * Now we have a first character of a token
+ */
+ switch(ch) {
+ case EOF :
+ return EOF;
+ case '\'': /*
+ * Literal, put it in ltext
+ */
+ i = 0;
+ for (;;) {
+ last = ch;
+ ch = input();
+ if (ch == '\n' || ch == EOF) {
+ error(linecount,"missing '");
+ break;
+ }
+ if (ch == '\'' && last != '\\') break;
+ ltext[i] = ch;
+ if (i < LTEXTSZ - 1) ++i;
+ }
+ ltext[i] = '\0';
+ lextoken.t_string = ltext;
+ return C_LITERAL;
+ case '%' : /*
+ * Start of a reserved word
+ */
+ reserved = 1;
+ ch = input();
+ /* Fall through */
+ default :
+ i = 0;
+ if (isdigit(ch)) {
+ if (reserved) {
+ error(linecount," A reserved number ?");
+ }
+ while (isdigit(ch)) {
+ i = 10 * i + (ch - '0');
+ ch= input();
+ }
+ lextoken.t_num = i;
+ unput(ch);
+ return C_NUMBER;
+ }
+ if (isalpha(ch) || ch == '_') {
+ do {
+ if (reserved && isupper(ch)) ch += 'a' - 'A';
+ ltext[i] = ch;
+ if (i < LTEXTSZ - 1) ++i;
+ ch = input();
+ } while (isalnum(ch) || ch == '_');
+ } else return ch;
+ unput(ch);
+ }
+ ltext[i] = '\0';
+ if (reserved) { /*
+ * Now search for the keyword
+ */
+ register struct keyword *w;
+
+ w = resword;
+ while (w->w_word) {
+ if (! strcmp(ltext,w->w_word)) {
+ /*
+ * Found it. Return token number.
+ */
+ return w->w_value;
+ }
+ w++;
+ }
+ error(linecount,"illegal reserved word");
+ }
+ lextoken.t_string = ltext;
+ return C_IDENT;
+}
+
+static int backupc; /* for unput() */
+static int nonline; /* = 1 if last char read was a newline */
+
+input() {
+ /*
+ * Low level input routine, used by all other input routines
+ */
+ register c;
+ register FILE *f;
+
+ if(backupc) { /*
+ * Last char was "unput()". Deliver it again
+ */
+ c = backupc;
+ backupc = 0;
+ return c;
+ }
+ f = finput;
+ if ((c = getc(f)) == EOF) return c;
+ nostartline = 1;
+ if (!nonline) {
+ linecount++;
+ nostartline = 0;
+ nonline = 1;
+ }
+ if (c == ' ' || c == '\t') { /*
+ * Deliver space, but only once
+ */
+ do c = getc(f);
+ while (c == ' ' || c == '\t');
+ ungetc(c,f);
+ return ' ';
+ }
+ if (c == '\n') nonline = 0;
+ return c;
+}
+
+unput(c) {
+ /*
+ * "unread" c
+ */
+ backupc = c;
+}
+
+skipcomment(flag) {
+ /*
+ * Skip comment. If flag != 0, the comment is inside a fragment
+ * of C-code, so the newlines in it must be copied to enable the
+ * C-compiler to keep a correct line count
+ */
+ register ch;
+ int saved; /* line count on which comment starts */
+
+ saved = linecount;
+ if (input() != '*') error(linecount,"illegal comment");
+ ch = input();
+ while (ch != EOF) {
+ if (flag && ch == '\n') putc(ch,fact);
+ while (ch == '*') {
+ if ((ch = input()) == '/') return;
+ if (flag && ch == '\n') putc(ch,fact);
+ }
+ ch = input();
+ }
+ error(saved,"Comment does not terminate");
+}
+
+STATIC
+linedirective() {
+ /*
+ * Read a line directive
+ */
+ register ch;
+ register i;
+ string s_error = "Illegal line directive";
+ string store();
+ register string c;
+
+ do { /*
+ * Skip to next digit
+ * Do not skip newlines
+ */
+ ch = input();
+ } while (ch != '\n' && ! isdigit(ch));
+ if (ch == '\n') {
+ error(linecount,s_error);
+ return;
+ }
+ i = ch - '0';
+ ch = input();
+ while (isdigit(ch)) {
+ i = i*10 + (ch - '0');
+ ch = input();
+ }
+ while (ch != '\n' && ch != '"') ch = input();
+ if (ch == '"') {
+ c = ltext;
+ do {
+ *c++ = ch = input();
+ } while (ch != '"' && ch != '\n');
+ if (ch == '\n') {
+ error(linecount,s_error);
+ return;
+ }
+ *--c = '\0';
+ do {
+ ch = input();
+ } while (ch != '\n');
+ /*
+ * Remember the file name
+ */
+ if (strcmp(f_input,ltext)) f_input = store(ltext);
+ }
+ linecount = i;
+}
+
+STATIC string
+vallookup(s) {
+ /*
+ * Look up the keyword that has token number s
+ */
+ register struct keyword *p = resword;
+
+ while (p->w_value) {
+ if (p->w_value == s) return p->w_word;
+ p++;
+ }
+ return 0;
+}
+
+STATIC string
+cpy(s,p,flag) register s; register string p; {
+ /*
+ * Create a piece of error message for token s and put it at p.
+ * flag = 0 if the token s was deleted (in which case we have
+ * attributes), else it was inserted
+ */
+ register string t = 0;
+
+ switch(s) {
+ case C_IDENT :
+ if (!flag) t = lextoken.t_string;
+ else t = "identifier";
+ break;
+ case C_NUMBER :
+ t = "number";
+ break;
+ case C_LITERAL :
+ if (!flag) {
+ *p++ = '"';
+ *p++ = '\'';
+ t = lextoken.t_string;
+ break;
+ }
+ t = "literal";
+ break;
+ case EOFILE :
+ t = "endoffile";
+ break;
+ }
+ if (!t) {
+ t = vallookup(s);
+ if (t) {
+ *p++ = '%';
+ }
+ }
+ if (t) { /*
+ * We have a string for the token. Copy it
+ */
+ while (*t) *p++ = *t++;
+ if (s == C_LITERAL && !flag) {
+ *p++ = '\'';
+ *p++ = '"';
+ }
+ return p;
+ }
+ /*
+ * The token is a literal
+ */
+ *p++ = '\'';
+ if (s >= 040 && s <= 0176) *p++ = s;
+ else switch(s) {
+ case '\b' : *p++ = '\\'; *p++ = 'b'; break;
+ case '\f' : *p++ = '\\'; *p++ = 'f'; break;
+ case '\n' : *p++ = '\\'; *p++ = 'n'; break;
+ case '\r' : *p++ = '\\'; *p++ = 'r'; break;
+ case '\t' : *p++ = '\\'; *p++ = 't'; break;
+ default : *p++='0'+((s&0377)>>6); *p++='0'+((s>>3)&07);
+ *p++='0'+(s&07);
+ }
+ *p++ = '\'';
+ return p;
+}
+
+LLmessage(d) {
+ /*
+ * d is either 0, in which case the current token has been deleted,
+ * or non-zero, in which case it represents a token that is inserted
+ * before the current token
+ */
+ register string s,t;
+ char buf[128];
+
+ nerrors++;
+ s = buf;
+ if (d == 0) {
+ s = cpy(LLsymb,s,0);
+ t = " deleted";
+ do *s++ = *t; while (*t++);
+ } else {
+ s = cpy(d,s,1);
+ t = " inserted in front of ";
+ do *s++ = *t++; while (*t);
+ s = cpy(LLsymb,s,0);
+ *s = '\0';
+ }
+ error(linecount,buf);
+ if (d) { /*
+ * Save the current token and make up some
+ * attributes for the inserted token
+ */
+ savedtok = lextoken;
+ if (d == C_IDENT) lextoken.t_string = "dummy_identifier";
+ else if (d == C_LITERAL) lextoken.t_string = "dummy_literal";
+ else if (d == C_NUMBER) lextoken.t_num = 1;
+ }
+}
+}
--- /dev/null
+/*
+ * (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
+ *
+ * This product is part of the Amsterdam Compiler Kit.
+ *
+ * Permission to use, sell, duplicate or disclose this software must be
+ * obtained in writing. Requests for such permissions may be sent to
+ *
+ * Dr. Andrew S. Tanenbaum
+ * Wiskundig Seminarium
+ * Vrije Universiteit
+ * Postbox 7161
+ * 1007 MC Amsterdam
+ * The Netherlands
+ *
+ */
+
+/*
+ * L L G E N
+ *
+ * An Extended LL(1) Parser Generator
+ *
+ * Author : Ceriel J.H. Jacobs
+ */
+
+/*
+ * tunable.h $Header$
+ * Tunable constants
+ */
+
+# define NNONTERMS 150 /* size of nonterminal array */
+# define NTERMINALS 150 /* size of terminal array */
+# define NAMESZ 3000 /* size of name table */
+# define LTEXTSZ 51 /* size of token */
+# define ENTSIZ 900 /* size of entry table, max 8191 */