Initial revision
This commit is contained in:
parent
6cbb37051b
commit
a21f936651
14 changed files with 1788 additions and 0 deletions
12
util/LLgen/lib/incl
Normal file
12
util/LLgen/lib/incl
Normal file
|
@ -0,0 +1,12 @@
|
|||
/* $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"
|
215
util/LLgen/lib/rec
Normal file
215
util/LLgen/lib/rec
Normal file
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
54
util/LLgen/src/alloc.c
Normal file
54
util/LLgen/src/alloc.c
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* (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;
|
||||
}
|
35
util/LLgen/src/assert.h
Normal file
35
util/LLgen/src/assert.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* (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
|
86
util/LLgen/src/extern.h
Normal file
86
util/LLgen/src/extern.h
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* (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?
|
||||
*/
|
71
util/LLgen/src/global.c
Normal file
71
util/LLgen/src/global.c
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* (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;
|
49
util/LLgen/src/io.h
Normal file
49
util/LLgen/src/io.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* (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;
|
58
util/LLgen/src/machdep.c
Normal file
58
util/LLgen/src/machdep.c
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* (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;
|
||||
}
|
333
util/LLgen/src/main.c
Normal file
333
util/LLgen/src/main.c
Normal file
|
@ -0,0 +1,333 @@
|
|||
/*
|
||||
* (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
|
239
util/LLgen/src/name.c
Normal file
239
util/LLgen/src/name.c
Normal file
|
@ -0,0 +1,239 @@
|
|||
/*
|
||||
* (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;
|
||||
}
|
121
util/LLgen/src/reach.c
Normal file
121
util/LLgen/src/reach.c
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* (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++;
|
||||
}
|
||||
}
|
45
util/LLgen/src/sets.h
Normal file
45
util/LLgen/src/sets.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* (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;
|
435
util/LLgen/src/tokens.g
Normal file
435
util/LLgen/src/tokens.g
Normal file
|
@ -0,0 +1,435 @@
|
|||
/*
|
||||
* (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;
|
||||
}
|
||||
}
|
||||
}
|
35
util/LLgen/src/tunable.h
Normal file
35
util/LLgen/src/tunable.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* (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 */
|
Loading…
Reference in a new issue