3 Commits

Author SHA1 Message Date
David Given
8f5c67b225 Rename branch.
--HG--
branch : unlabeled-1.2.1-branch
2015-06-18 23:39:30 +02:00
keie
76b352bd38 A -incorrect- variant that uses EM_DIR/ERR_PATH etc.
--HG--
branch : unlabeled-1.2.1
1984-10-04 10:06:12 +00:00
cvs2hg
5c4c721226 fixup commit for branch 'unlabeled-1.2.1'
--HG--
branch : unlabeled-1.2.1
1984-06-21 11:10:17 +00:00
35 changed files with 690 additions and 13272 deletions

View File

@@ -1,32 +0,0 @@
Copyright (c) 1987, 1990, 1993, 2005 Vrije Universiteit, Amsterdam, The Netherlands.
All rights reserved.
Redistribution and use of the Amsterdam Compiler Kit in source and
binary forms, with or without modification, are permitted provided
that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Vrije Universiteit nor the names of the
software authors or contributors may be used to endorse or
promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL VRIJE UNIVERSITEIT OR ANY AUTHORS OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -1,84 +0,0 @@
LLGEN V1.0
==========
Copyright © 1991-2005 by the Vrije Universiteit, Amsterdam, the Netherlands.
2006-02-03
INTRODUCTION
============
LLgen is a LL(1) parser in the style of yacc. It will generate an efficient
recursive descent parser for Extended Context-Free grammars, with an optional
non-correcting error recovery mechanism.
For more information, see the white papers in the doc directory. (You may need
to build LLgen first to be able to read them.)
INSTALLATION
============
LLgen depends on the following software:
gcc: currently, LLgen only builds on gcc, due largely to the lack of any
non-gcc test systems. Please contact the support mailing list (see
below) if this is a problem.
groff: used to build the documentation.
LLgen uses Prime Mover as its build tool. To build, do:
./pm install
This will compile LLgen and install it into /usr/local (which you must be able
to write to). If you want it installed elsewhere, use -D to change the PREFIX
variable:
./pm -DPREFIX="/home/dg/" install
(If you do change the prefix, you must supply it whenever you invoke pm. And
there must be a trailing / in the path you give it.)
Invoking ./pm by itself will compile it but not install it; look in the bin
directory for an image of
USING LLGEN
===========
Please see the white papers in PREFIX/share/doc/LLgen, or the man page (called
LLgen).
LLgen itself uses a parser compiled in LLgen, so you can study the files in
the src directory for examples. If you wish to modify LLgen's own parser, the
bootstrap.sh script will update LLgen's source from the parser *.g files.
LLgen itself may then be recompiled with pm in the usual way. (Although you
may want to keep a copy of a known good LLgen around in case you break
something!)
SUPPORT
=======
LLgen is part of the Amsterdam Compiler Kit (although standalone and
distributed seperately). For more details, please see:
http://tack.sourceforge.net
There is a mailing list available at:
http://sourceforge.net/mail/?group_id=130811
LICENSE
=======
LLgen is © 1991-2005 by the Vrije Universiteit and is distributed under a
license equivalent to the three-clause BSD license. See the COPYING file
for details.
Prime Mover is © 2006 David Given and is distributed under the MIT license.
Do './pm --license' for details.
-----------------------------------------------------------------------------
David Given
dg@cowlark.com
2006-02-04
/* $Id$ */

View File

@@ -1,16 +0,0 @@
#!/bin/sh
# $Id$
#
# Script to rebuild LLgen's own parser with LLgen.
set -e
if ! (which LLgen > /dev/null); then
echo "You can only bootstrap the LLgen parser if you've already got"
echo "LLgen installed."
fi
(cd src && LLgen -vvv -x tokens.g LLgen.g)
echo ""
echo "You should now be able to rebuild LLgen with the new parser."

View File

@@ -1,144 +0,0 @@
-- This file is part of Prime Mover v0.1pre1.
-- (C) 2006 David Given
--
-- pm includefile to compile *host* C programs.
-- Standard Lua boilerplate.
local io_open = io.open
local string_gsub = string.gsub
local string_gfind = string.gfind
local table_insert = table.insert
local table_getn = table.getn
local filetime = pm.filetime
-- Define some variables.
CC = "gcc %CBUILDFLAGS% %CDYNINCLUDES% %CINCLUDES% %CEXTRAFLAGS% -c -o %out% %in%"
CPROGRAM = "gcc %CBUILDFLAGS% %CLINKFLAGS% %CEXTRAFLAGS% -o %out% %in% %CLIBRARIES%"
CDEPENDS = "gcc %CBUILDFLAGS% %CDYNINCLUDES% %CINCLUDES% %CEXTRAFLAGS% -MM -MG -MF %out% %in%"
AR = "%RM% %out% && ar cr %out% %in%"
CBUILDFLAGS = "-g -Os"
CINCLUDES = {}
CEXTRAFLAGS = ""
CLINKFLAGS = ""
CDYNINCLUDES = ""
CLIBRARIES = ""
--- Manage C file dependencies ----------------------------------------------
local dependency_cache = {}
local function load_dependency_file(fn)
local o = dependency_cache[fn]
if o then
return o
end
-- Read in the dependency file.
local f = io_open(fn)
if not f then
print("failed to open "..fn)
return nil
end
f = f:read("*a")
-- Massage the dependency file into a string containing one unescaped
-- filename per line.
f = string_gsub(f, "^.*[^\\]: *", "")
f = string_gsub(f, "\\\r?\n", "")
f = string_gsub(f, "([^\\]) +", "%1\n")
f = string_gsub(f, "\\", "")
-- Parse the string.
o = {}
for l in string_gfind(f, "[^\n]+") do
table_insert(o, l)
end
dependency_cache[fn] = o
return o
end
-- This clause specialises 'simple' to add support for smart dependencies of C
-- files.
simple_with_clike_dependencies = simple {
class = "simple_with_clike_dependencies",
makedepends = {"%CDEPENDS%"},
__init = function(self, p)
simple.__init(self, p)
-- If we're a class, don't verify.
if ((type(p) == "table") and p.class) then
return
end
-- If dynamicheaders is an object, turn it into a singleton list.
if self.dynamicheaders then
if (type(self.dynamicheaders) ~= "table") then
self:__error("doesn't know what to do with dynamicheaders, which ",
"should be a list or an object but was a ", type(self.dynamicheaders))
end
if self.dynamicheaders.class then
self.dynamicheaders = {self.dynamicheaders}
end
end
end,
__dependencies = function(self, inputs, outputs)
local obj = simple {
CDYNINCLUDES = self.CDYNINCLUDES,
command = self.makedepends,
outputs = {"%U%-%I%.d"},
unpack(inputs)
}
local o = obj:__build()
local depends = load_dependency_file(o[1])
if not depends then
self:__error("could not determine the dependencies for ",
pm.rendertable(inputs))
end
return depends
end,
__buildadditionalchildren = function(self)
self.CDYNINCLUDES = ""
if self.dynamicheaders then
for _, i in ipairs(self.dynamicheaders) do
local o = i:__build()
if o[1] then
self.CDYNINCLUDES = self.CDYNINCLUDES..' "-I'..string_gsub(o[1], "/[^/]*$", "")..'"'
end
end
end
end
}
-- These are the publically useful clauses.
cfile = simple_with_clike_dependencies {
class = "cfile",
command = {"%CC%"},
outputs = {"%U%-%I%.o"},
}
cprogram = simple {
class = "cprogram",
command = {"%CPROGRAM%"},
outputs = {"%U%-%I%"},
}
clibrary = simple {
class = "clibrary",
command = {
"%AR%"
},
outputs = {"%U%-%I%.a"},
}

View File

@@ -1,139 +0,0 @@
.\" $Id$
.TH LLGEN 1 "$Revision$"
.ad
.SH NAME
LLgen, an extended LL(1) parser generator
.SH SYNOPSIS
LLgen [ \-vxwans ] [ \-j[\fInum\fP] ] [ \-l\fInum\fP ] [ \-h\fInum\fP ] file ...
.SH DESCRIPTION
\fILLgen\fP
converts a context-free grammar into a set of
functions which form a recursive descent parser with no backtrack.
The grammar may be ambiguous;
ambiguities can be broken by user specifications.
.PP
\fILLgen\fP
reads each
\fIfile\fP
in sequence.
Together, these files must constitute a context-free grammar.
For each file,
\fILLgen\fP
generates an output file, which must be compiled by the
C-compiler.
In addition, it generates the files
\fILpars.c\fP
and
\fILpars.h.\fP
\fILpars.h\fP
contains the
\fIdefine\fP
statements that associate the
\fILLgen\fP-assigned `token-codes' with user declared `token-names'.
This allows other source files, for instance the source file
containing the lexical analyzer,
to access the token-codes by
using the token-names.
\fILpars.c\fP
contains the error recovery routines and tables. It must also
be compiled by the C-compiler. When the generated parser uses non-correcting
error recovery (
\fB\-n\fP
option)
\fILLgen\fP
also generates a file
\fILncor.c\fP
that contains the non-correcting recovery mechanism.
.PP
\fILLgen\fP
will only update those output files that differ from their previous
version.
This allows
\fILLgen\fP
to be used with
\fImake\fP
(1) convieniently.
.PP
To obtain a working program, the user must also supply a
lexical analyzer, as well as
\fImain\fP
and
\fILLmessage\fP,
an error reporting routine;
\fILex\fP
(1) is a useful program for creating lexical analysers usable
by
\fILLgen\fP.
.PP
\fILLgen\fP accepts the following flags:
.IP \fB\-v\fP
create a file called
\fILL.output\fP,
which contains a description of the conflicts that
were not resolved.
If the flag is given more than once,
\fILLgen\fP
will be more "verbose".
If it is given three times, a complete description of the
grammar will be supplied.
.IP \fB\-x\fP
the sets that are computed are extended with the nonterminal
symbols and these extended sets are also included in the
\fILL.output\fP
file.
.IP \fB\-w\fP
no warnings are given.
.IP \fB\-a\fP
Produce ANSI C function headers and prototypes.
.IP \fB\-n\fP
Produce a parser with non-correcting error recovery.
.IP \fB\-s\fP
Simulate the calling of all defined subparsers in all semantic actions. When
using non-correcting error recovery, subparsers that are called in semantic
actions may cause problems; this flag provides a `brute-force' solution.
.IP \fB\-j\fP[\fInum\fP]
when this flag is given, \fILLgen\fP will generate dense switches,
so that the compiler can generate a jump table for it. This will only be
done for switches that have density between
\fIlow_percentage\fP and \fIhigh_percentage\fP, as explained below.
Usually, compilers generate a jumptable when the density of the switch
is above a certain threshold. When jump tables are to be used more often,
\fIhigh_percentage\fP must be set to this threshold, and \fIlow_percentage\fP
must be set to a minimum threshold. There is a time-space trade-off here.
.I num
is the minimum number of cases in a switch for the \fB\-j\fP option to be
effective. The default value (if
.I num
is not given) is 8.
.IP \fB\-l\fP\fInum\fP
The \fIlow_percentage\fP, as described above. Default value is 10.
.IP \fB\-h\fP\fInum\fP
The \fIhigh_percentage\fP, as described above. Default value is 30.
.SH FILES
LL.output verbose output file
.br
Lpars.c the error recovery routines
.br
Lncor.c non-correcting error recovery mechanism
.br
Lpars.h defines for token names
.SH "SEE ALSO"
\fIlex\fP(1)
.br
\fImake\fP(1)
.br
\fILLgen, an Extended LL(1) Parser Generator\fP
by C.J.H. Jacobs.
.br
\fITop-down Non-Correcting Error Recovery in LLgen\fP
by A.W van Deudekom and P.J. Kooiman
.SH DIAGNOSTICS
Are intended to be self-explanatory. They are reported
on standard error. A more detailed report is found in the
\fILL.output\fP
file.
.SH AUTHOR
Ceriel J. H. Jacobs
.br
The non-correcting error recovery mechanism is written by
A.W van Deudekom and P.J. Kooiman.

File diff suppressed because it is too large Load Diff

View File

@@ -1,54 +0,0 @@
%T An ALL(1) Compiler Generator
%A D. R. Milton
%A L. W. Kirchhoff
%A B. R. Rowland
%B Proc. of the SIGPLAN '79 Symposium on Compiler Construction
%D August 1979
%J SIGPLAN Notices
%N 8
%P 152-157
%V 14
%T Lex - A Lexical Analyser Generator
%A M. E. Lesk
%I Bell Laboratories
%D October 1975
%C Murray Hill, New Jersey
%R Comp. Sci. Tech. Rep. No. 39
%T Yacc: Yet Another Compiler Compiler
%A S. C. Johnson
%I Bell Laboratories
%D 1975
%C Murray Hill, New Jersey
%R Comp. Sci. Tech. Rep. No. 32
%T The C Programming Language
%A B. W. Kernighan
%A D. M. Ritchie
%I Prentice-Hall, Inc.
%C Englewood Cliffs, New Jersey
%D 1978
%A M. Griffiths
%T LL(1) Grammars and Analysers
%E F. L. Bauer and J. Eickel
%B Compiler Construction, An Advanced Course
%I Springer-Verlag
%C New York, N.Y.
%D 1974
%T Make - A Program for Maintaining Computer Programs
%A S. I. Feldman
%J Software - Practice and Experience
%V 10
%N 8
%P 255-265
%D August 1979
%T Methods for the Automatic Construction of Error Correcting Parsers
%A J. R\*:ohrich
%J Acta Informatica
%V 13
%P 115-139
%D 1980

File diff suppressed because it is too large Load Diff

View File

@@ -1,68 +0,0 @@
/* $Id$ */
#ifdef LL_DEBUG
#include <assert.h>
#include <stdio.h>
#define LL_assert(x) assert(x)
#else
#define LL_assert(x) /* nothing */
#endif
extern int LLsymb;
#define LL_SAFE(x) /* Nothing */
#define LL_SSCANDONE(x) if (LLsymb != x) LLsafeerror(x)
#define LL_SCANDONE(x) if (LLsymb != x) LLerror(x)
#define LL_NOSCANDONE(x) LLscan(x)
#ifdef LL_FASTER
#define LLscan(x) if ((LLsymb = LL_LEXI()) != x) LLerror(x)
#endif
extern unsigned int LLscnt[];
extern unsigned int LLtcnt[];
extern int LLcsymb;
#if LL_NON_CORR
extern int LLstartsymb;
#endif
#define LLsdecr(d) {LL_assert(LLscnt[d] > 0); LLscnt[d]--;}
#define LLtdecr(d) {LL_assert(LLtcnt[d] > 0); LLtcnt[d]--;}
#define LLsincr(d) LLscnt[d]++
#define LLtincr(d) LLtcnt[d]++
#if LL_ANSI_C
extern int LL_LEXI(void);
extern void LLread(void);
extern int LLskip(void);
extern int LLnext(int);
extern void LLerror(int);
extern void LLsafeerror(int);
extern void LLnewlevel(unsigned int *);
extern void LLoldlevel(unsigned int *);
#ifndef LL_FASTER
extern void LLscan(int);
#endif
#ifndef LLNOFIRSTS
extern int LLfirst(int, int);
#endif
#if LL_NON_CORR
extern void LLnc_recover(void);
#endif
#else /* not LL_ANSI_C */
extern LLread();
extern int LLskip();
extern int LLnext();
extern LLerror();
extern LLsafeerror();
extern LLnewlevel();
extern LLoldlevel();
#ifndef LL_FASTER
extern LLscan();
#endif
#ifndef LLNOFIRSTS
extern int LLfirst();
#endif
#if LL_NON_CORR
extern LLnc_recover();
#endif
#endif /* not LL_ANSI_C */

View File

@@ -1,70 +0,0 @@
#define LLALT 9999 /* Alternative is following */
#define LLTERMINAL 1 /* Symbol is a terminal */
#define LLNONTERMINAL 2 /* Symbol is a nonterminal */
#define LLEORULE 0 /* No more alternatives */
struct lhs { /* LHS of a rule */
int nr; /* Nr of the nonterminal */
struct symbol *rhs; /* Pointer to RHS */
char first[LLSETSIZE]; /* First set */
char follow[LLSETSIZE]; /* Follow set */
char empty; /* Set if nonterminal produces empty */
};
struct symbol { /* Symbol in the RHS of a rule */
int x; /* LLTERMINAL or LLNONTERMINAL */
int nr; /* Nr of the symbol */
struct symbol *link; /* Ptr to next rule with this symbol */
struct symbol *next; /* Ptr to next symbol in this rule */
struct lhs *lhs; /* Ptr to LHS */
};
struct terminal { /* Array with links to terminals in a */
struct symbol *link; /* rule */
};
struct nonterminal { /* Array with links to nt's in a rule */
struct symbol *link; /* and pointer to LHS's */
struct lhs *rule;
};
struct stack_elt { /* Stack element */
int flags; /* Some flags */
int nr; /* Nr of symbol */
int ref_count; /* Nr of predecessors */
int hyp_ref_count; /* Temporary nr of predecessors */
int matched; /* Nr of LHS trying to match */
int nr_nexts; /* Nr of successors */
struct edge *edges; /* Array of edges to other stack elt's*/
};
/* Possible flags in a stack element */
#define LLHEAD 1 /* Stack element is a head */
#define LLDUMMY 2 /* Stack element is substituted */
#define LLGEN_SEARCH 8 /* Set by 'generate_heads()' */
struct edge { /* Edges of a stack element */
char flags; /* Some flags */
struct stack_elt *ptr; /* Array with pointers to stack elt's */
};
/* Possible flags in an edge */
#define LLLOOP 1 /* Belongs to a loop */
#define LLLOOP_SEARCH 2 /* Used by 'loop()' */
#define LLHYP_SEARCH 4 /* Used by 'hyp_run()' */
#define PRINT_SEARCH 8 /* DEBUG */
#define LLMARK_SEARCH 16 /* Used by 'mark_loop()' */
#define LLYES 32
#define LLNO 64
#define LLEOSTACK -1 /* Indicates last element of a stack */
#define LLHEADS_BUF_INCR 10 /* Nr of elements the buffer will be */
#define LLCLEANUP_BUF_INCR 25 /* increased by */
#define LL_VIS_INCR 200
/* Macro's to manipulate bit sets */
#define LLIN(a, i) ((a)[(i)/8] & (1 << ((i) % 8)))
#define LLPUTIN(a, i) ((a)[(i)/8] |= (1 << ((i) % 8)))

File diff suppressed because it is too large Load Diff

View File

@@ -1,442 +0,0 @@
/*
* Some grammar independent code.
* This file is copied into Lpars.c.
*/
#ifndef lint
static char *rcsid = "$Id$";
#endif
unsigned int LLtcnt[LL_NTERMINALS];
unsigned int LLscnt[LL_NSETS];
int LLcsymb, LLsymb;
static int LLlevel;
#if LL_NON_CORR
int LLstartsymb;
static int fake_eof = 0;
#endif
#if LL_ANSI_C
#define LL_VOIDCST (void)
void LLmessage(int);
#else
#define LL_VOIDCST
#endif
#ifdef LL_USERHOOK
#if LL_ANSI_C
static int LLdoskip(int);
static int LLuserhook(int, int*);
#else
static int LLdoskip();
static int LLuserhook();
#endif
#endif
#ifndef LL_FASTER
#if LL_ANSI_C
void LLscan(int t)
#else
LLscan(t)
int t;
#endif
{
/*
* Check if the next symbol is equal to the parameter
*/
#if LL_NON_CORR
/* See if the error recovery has eaten an eof */
if (fake_eof) {
LLsymb = EOFILE;
fake_eof = 0;
}
else {
LLsymb = LL_LEXI();
}
if (LLsymb == t) {
#else
if ((LLsymb = LL_LEXI()) == t) {
#endif
#if LL_NON_CORR
/* Check if a previous parser has 'crashed', in that
* case continue with non-correcting parser
*/
if (err_seen && !nc_done) {
LLnc_recover();
nc_done = 1;
/* Remember that the error recovery has eaten an eof */
fake_eof = 1;
if (t != LLsymb) {
LLerror(t);
}
else
return;
}
#endif
return;
}
/*
* If we come here, an error has been detected
*/
LLerror(t);
}
#endif
#if LL_ANSI_C
void LLread(void) {
#else
LLread() {
#endif
#if LL_NON_CORR
/* Again, check if another parser has crashed,
* in that case intercept and go to the
* non-correcting parser
*/
if (err_seen && !nc_done) {
LLnc_recover();
nc_done = 1;
/* Pretend we read end of file */
LLsymb = EOFILE;
LLcsymb = LLindex[EOFILE];
fake_eof = 0;
return;
}
if (fake_eof) {
LLsymb = EOFILE;
LLcsymb = LLindex[EOFILE];
fake_eof = 0;
return;
}
#endif
for (;;) {
if ((LLcsymb = LLindex[(LLsymb = LL_LEXI())]) >= 0) return;
LLmessage(0);
}
/* NOTREACHED */
}
#if LL_ANSI_C
void LLerror(int t)
#else
LLerror(t)
int t;
#endif
{
register int i;
if (t == EOFILE && LLsymb <= 0) return;
#ifdef LL_NEWMESS
if (t == EOFILE) {
#ifdef LL_USERHOOK
static int lst[] = { EOFILE, 0 };
LL_VOIDCST LLuserhook(EOFILE, lst);
#endif /* LL_USERHOOK */
if (LLsymb != EOFILE && LLsymb > 0) {
LLmessage(-1);
while ((LLsymb = LL_LEXI()) > 0 && LLsymb != EOFILE)
/* nothing */ ;
}
return;
}
#endif
#if LL_NON_CORR
if ((!nc_done) && (LLsymb > 0) && (LLsymb != EOFILE)) {
LLmessage(0);
LLnc_recover();
nc_done = 1;
LLsymb = EOFILE;
}
#endif
if ((LLcsymb = LLindex[LLsymb]) < 0) {
LLmessage(0);
LLread();
}
i = LLindex[t];
LLtcnt[i]++;
#ifdef LL_USERHOOK
LL_VOIDCST LLdoskip(t);
#else
LL_VOIDCST LLskip();
#endif
LLtcnt[i]--;
if (LLsymb != t) {
#if LL_NON_CORR
/* A little kludge here; when using non-correcting recovery
* it can happen that a program is correct but incomplete.
* Here, we test this, and make sure the appropriate
* message is generated
*/
if (! nc_done) {
int oldLLsymb;
oldLLsymb = LLsymb;
LLsymb = EOFILE;
LLmessage(0);
nc_done = 1;
/* Not really, but to prevent more than 1 error message */
LLsymb = oldLLsymb;
}
#endif
LLmessage(t);
}
}
#if LL_ANSI_C
void LLsafeerror(int t)
#else
LLsafeerror(t)
int t;
#endif
{
if (t == EOFILE && LLsymb <= 0) return;
#ifdef LL_NEWMESS
if (t == EOFILE) {
#ifdef LL_USERHOOK
static int lst[] = { EOFILE, 0 };
LL_VOIDCST LLuserhook(EOFILE, lst);
#endif /* LL_USERHOOK */
if (LLsymb != EOFILE && LLsymb > 0) {
LLmessage(-1);
while ((LLsymb = LL_LEXI()) > 0 && LLsymb != EOFILE)
/* nothing */ ;
}
return;
}
#endif
#if LL_NON_CORR
if ((!nc_done) && (LLsymb > 0) && (LLsymb != EOFILE)) {
LLmessage(0);
LLnc_recover();
nc_done = 1;
LLsymb = EOFILE;
}
/* A little kludge here; when using non-correcting recovery
* it can happen that a program is correct but incomplete.
* Here, we test this, and make sure the appropriate
* message is generated
*/
if (! nc_done) {
int oldLLsymb;
oldLLsymb = LLsymb;
LLsymb = EOFILE;
LLmessage(0);
nc_done = 1;
/* Not really, but to prevent more than 1 error message */
LLsymb = oldLLsymb;
}
#endif
LLmessage(t);
}
#ifndef LLNOFIRSTS
#if LL_ANSI_C
int LLfirst(int x, int d) {
#else
int LLfirst(x, d) {
#endif
register int i;
return (i = LLindex[x]) >= 0 &&
(LLsets[d + (i >> 3)] & (1 << (i & 07)));
}
#endif
#if LL_ANSI_C
int LLnext(int n)
#else
int LLnext(n)
int n;
#endif
{
/* returns: 0 if the current symbol is'nt skipped, and it
is'nt a member of "n",
1 if we have a new symbol, but it is'nt a member,
2 if the current symbol is a member,
and 3 if we have a new symbol and it is a member.
So, the low order bit indicates wether we have a new symbol,
and the next bit indicates wether it is a member of "n".
*/
int retval = 0;
if (LLskip()) retval = 1;
if (n <= 0 && LLsets[(LLcsymb >> 3) - n] & (1 << (LLcsymb & 07))) {
retval |= 2;
}
else if (n > 0 && LLcsymb == LLindex[n]) retval |= 2;
return retval;
}
#if LL_ANSI_C
int LLskip(void) {
#else
int LLskip() {
#endif
/* returns 0 if the current symbol is'nt skipped, and
1 if it is, t.i., we have a new symbol
*/
#ifdef LL_USERHOOK
return LLdoskip(0);
}
#if LL_ANSI_C
extern void LL_USERHOOK(int, int *);
static int LLuserhook(int e, int *list)
#else
static int LLuserhook(e, list)
int e;
int *list;
#endif
{
int old = LLsymb;
LL_USERHOOK(e, list);
LLread();
return LLsymb != old;
}
#if LL_ANSI_C
static void LLmklist(register int *list)
#else
static LLmklist(list)
register int *list;
#endif
{
char Xset[LL_SSIZE];
register char *p;
register int i;
for (p = &Xset[0]; p < &Xset[LL_SSIZE]; ) *p++ = 0;
for (i = 0; i < LL_NTERMINALS; i++) {
if (LLtcnt[i] != 0) Xset[i >> 3] |= (1 << (i & 07));
}
for (i = LL_NSETS - 1; i >= 0; i--) if (LLscnt[i] != 0) {
register char *q = &LLsets[LL_SSIZE * i];
p = &Xset[0];
while (p < &Xset[LL_SSIZE]) *p++ |= *q++;
}
for (i = 0; i < LL_NTERMINALS; i++) {
if (Xset[i >> 3] & (1 << (i & 07))) {
*list++ = LLtok[i];
}
}
*list = 0;
}
#if LL_ANSI_C
static int LLdoskip(int e)
#else
static int LLdoskip(e)
int e;
#endif
{
int LLx;
int list[LL_NTERMINALS+1];
#endif /* LL_USERHOOK */
register int i;
int retval;
int LLi, LLb;
retval = 0;
#ifdef LL_USERHOOK
LLmklist(list);
LLx = LLuserhook(e, list);
if (LLx) retval = 1;
#endif /* LL_USERHOOK */
for (;;) {
if (LLtcnt[LLcsymb] != 0) {
#ifdef LL_USERHOOK
if (!e || !LLx || LLcsymb == LLindex[e])
#endif
return retval;
}
LLi = LLcsymb >> 3;
LLb = 1 << (LLcsymb & 07);
for (i = LL_NSETS - 1; i >= 0; i--) {
if (LLscnt[i] != 0) {
if (LLsets[LL_SSIZE*i+LLi] & LLb) {
#ifdef LL_USERHOOK
if (!e || !LLx || LLcsymb == LLindex[e])
#endif
return retval;
}
}
}
#ifdef LL_USERHOOK
if (LLx) {
LLx = LLuserhook(e, list);
continue;
}
#endif /* LL_USERHOOK */
#if LL_NON_CORR
if ((!nc_done) && (LLsymb > 0)) {
LLmessage(0);
LLnc_recover();
nc_done = 1;
fake_eof = 1;
}
else {
LLmessage(0);
}
#else
LLmessage(0);
#endif
retval = 1;
LLread();
}
/* NOTREACHED */
}
#if LL_ANSI_C
void LLnewlevel(unsigned int *LLsinfo) {
#else
LLnewlevel(LLsinfo) unsigned int *LLsinfo; {
#endif
register int i;
if (LLlevel++) {
LLsinfo[LL_NSETS+LL_NTERMINALS] = (unsigned) LLsymb;
LLsinfo[LL_NSETS+LL_NTERMINALS+1] = (unsigned) LLcsymb;
for (i = LL_NTERMINALS - 1; i >= 0; i--) {
LLsinfo[i] = LLtcnt[i];
LLtcnt[i] = 0;
}
for (i = LL_NSETS - 1; i >= 0; i--) {
LLsinfo[LL_NTERMINALS+i] = LLscnt[i];
LLscnt[i] = 0;
}
}
LLtincr(0);
}
#if LL_ANSI_C
void LLoldlevel(unsigned int *LLsinfo) {
#else
LLoldlevel(LLsinfo) unsigned int *LLsinfo; {
#endif
register int i;
LLtdecr(0);
#ifdef LL_DEBUG
for (i = 0; i < LL_NTERMINALS; i++) LL_assert(LLtcnt[i] == 0);
for (i = 0; i < LL_NSETS; i++) LL_assert(LLscnt[i] == 0);
#endif
if (--LLlevel) {
for (i = LL_NSETS - 1; i >= 0; i--) {
LLscnt[i] = LLsinfo[LL_NTERMINALS+i];
}
for (i = LL_NTERMINALS - 1; i >= 0; i--) {
LLtcnt[i] = LLsinfo[i];
}
LLsymb = (int) LLsinfo[LL_NSETS+LL_NTERMINALS];
LLcsymb = (int) LLsinfo[LL_NSETS+LL_NTERMINALS+1];
}
}

View File

@@ -1,64 +0,0 @@
#!/bin/sh
# $Id$
#
# Script to build a distribution package.
set -e
if [ "$1" = "" ]; then
echo "Please specify a version number!"
exit 1
fi
if [ -d ../LLgen-$1 ]; then
echo "I think you've already generated version $1."
exit 1
fi
mkdir ../LLgen-$1
cp -a --parents \
pm \
c.pm \
pmfile \
doc/LLgen.refs \
doc/LLgen_NCER.n \
doc/LLgen.1 \
doc/LLgen.n \
lib/rec \
lib/incl \
lib/nc_incl \
lib/nc_rec \
src/io.h \
src/extern.h \
src/reach.c \
src/LLgen.c \
src/LLgen.g \
src/compute.c \
src/savegram.c \
src/global.c \
src/gencode.c \
src/main.c \
src/name.c \
src/types.h \
src/sets.c \
src/sets.h \
src/tokens.c \
src/tokens.g \
src/Lpars.c \
src/Lpars.h \
src/cclass.c \
src/cclass.h \
src/alloc.c \
src/check.c \
src/machdep.c \
mkdistr.sh \
bootstrap.sh \
COPYING \
READ_ME \
\
../LLgen-$1
(cd .. && tar cvf LLgen-$1.tar.bz2 --bzip2 LLgen-$1)
echo ""
echo "Done --- but did you remember to update the version number in the README?"

Binary file not shown.

View File

@@ -1,103 +0,0 @@
-- $Id$
--
-- This is the build file used to compile LLgen. It should be run through
-- Prime Mover (copy supplied). See the READ_ME file for more information.
include "c.pm"
-- Where is LLgen going to be installed eventually? (Needs trailing slash.)
PREFIX = PREFIX or "/usr/local/"
-- Where's LLgen's staging area? (Don't change. Needs trailing slash.)
INSTALLPATH = "bin/"
LLgen = cprogram {
CEXTRAFLAGS = '-DLIBDIR=\\"'..PREFIX..'share/LLgen\\" -DNON_CORRECTING',
cfile "src/main.c",
cfile "src/gencode.c",
cfile "src/compute.c",
cfile "src/check.c",
cfile "src/reach.c",
cfile "src/global.c",
cfile "src/name.c",
cfile "src/sets.c",
cfile "src/alloc.c",
cfile "src/machdep.c",
cfile "src/cclass.c",
cfile "src/savegram.c",
-- These use pre-LLgen'd version of the files. If LLgen.g gets updated,
-- they need rebuilding. Use the bootstrap script to do this.
cfile "src/LLgen.c",
cfile "src/Lpars.c",
cfile "src/tokens.c",
outputs = {"%U%/LLgen"},
install = pm.install( INSTALLPATH.."bin/LLgen")
}
library = group {
install = {
pm.install("lib/rec", INSTALLPATH.."share/LLgen/rec"),
pm.install("lib/incl", INSTALLPATH.."share/LLgen/incl"),
pm.install("lib/nc_incl", INSTALLPATH.."share/LLgen/nc_incl"),
pm.install("lib/nc_rec", INSTALLPATH.."share/LLgen/nc_rec"),
}
}
manpage = group {
install = {
pm.install("doc/LLgen.1", INSTALLPATH.."man/man1/LLgen.1"),
}
}
documentation = group {
simple {
outputs = {"%U%-%I%.ps.gz"},
command = "refer -sA+T -p %in[1]% %in[2]% | groff -Tps -e -t -ms "..
"| gzip -c9 > %out[1]%",
file "doc/LLgen.refs",
file "doc/LLgen.n",
install = {
pm.install(INSTALLPATH.."share/doc/LLgen/LLgen.ps.gz")
}
},
simple {
outputs = {"%U%-%I%.ps.gz"},
command = "groff -Tps -e -t -p -ms %in% | gzip -c9 > %out[1]%",
file "doc/LLgen_NCER.n",
install = {
pm.install(INSTALLPATH.."share/doc/LLgen/NCER.ps.gz")
}
},
}
-- Default rule: builds everything into the staging area, but does nothing
-- else.
default = group {
LLgen, -- build LLgen itself
library, -- copy over the library
manpage, -- copy over the man page
documentation, -- build the two white papers
}
-- This rule will build everything, and then install it to its final location.
install = group {
default,
install = {
"mkdir -p %PREFIX%",
"(cd bin && tar cf - .) | (cd %PREFIX% && tar xvf -)"
}
}

View File

@@ -1,665 +0,0 @@
/* Copyright (c) 1991 by the Vrije Universiteit, Amsterdam, the Netherlands.
* For full copyright and restrictions on use see the file COPYING in the top
* level of the LLgen tree.
*/
/*
* L L G E N
*
* An Extended LL(1) Parser Generator
*
* Author : Ceriel J.H. Jacobs
*/
/*
* LLgen.g
* Defines the grammar of LLgen.
* Some routines that build the internal structure are also included
*/
{
# include <stdlib.h>
# include <string.h>
# include "types.h"
# include "io.h"
# include "extern.h"
# include "assert.h"
# include "cclass.h"
# ifndef NORCSID
static string rcsid = "$Id$";
# endif
p_mem alloc(), ralloc();
string store();
p_gram search();
long ftell();
static int acount; /* count #of global actions */
static p_term t_list;
static int t_cnt;
static p_gram alt_table;
static int n_alts;
static int max_alts;
#define ALTINCR 32
static p_gram rule_table;
static int n_rules;
static int max_rules;
#define RULEINCR 32
/* Here are defined : */
STATIC newnorder();
STATIC newtorder();
STATIC mkalt();
STATIC mkterm();
STATIC p_gram copyrule();
/* and of course LLparse() */
STATIC
newnorder(index) {
static int porder;
if (norder != -1) {
nonterms[porder].n_next = index;
}
else norder = index;
porder = index;
nonterms[porder].n_next = -1;
}
STATIC
newtorder(index) {
static int porder;
if (torder != -1) {
tokens[porder].t_next = index;
}
else torder = index;
porder = index;
tokens[porder].t_next = -1;
}
p_init()
{
alt_table = (p_gram )alloc(ALTINCR*sizeof(t_gram));
n_alts = 0;
max_alts = ALTINCR;
rule_table = (p_gram )alloc(RULEINCR*sizeof(t_gram));
n_rules = 0;
max_rules = RULEINCR;
}
}
%start LLparse, spec;
spec : { acount = 0; p_init(); }
[ %persistent def ]*
{ /*
* Put an endmarker in temporary file
*/
putc('\0', fact);
putc('\0', fact);
free((p_mem) rule_table);
free((p_mem) alt_table);
}
;
def { register string p; }
: rule
/*
* A grammar rule
*/
| C_TOKEN listel [ ',' listel ]* ';'
/*
* A token declaration
*/
| C_START C_IDENT
{ p = store(lextoken.t_string); }
',' C_IDENT
/*
* A start symbol declaration
*/
{ /*
* Put the declaration in the list
* of start symbols
*/
register p_gram temp;
register p_start ff;
temp = search(NONTERM,lextoken.t_string,BOTH);
ff = (p_start) alloc(sizeof(t_start));
ff->ff_nont = g_getcont(temp);
ff->ff_name = p;
ff->ff_next = start;
start = ff;
while (ff = ff->ff_next) {
if (! strcmp(p, ff->ff_name)) {
error(linecount, "\"%s\" already used in a %%start", p);
break;
}
}
}
';'
| C_LEXICAL C_IDENT
/*
* Declaration of a name for the lexical analyser.
* May appear only once
*/
{ if (!lexical) {
lexical = store(lextoken.t_string);
}
else error(linecount,"Duplicate %%lexical");
}
';'
| C_PREFIX C_IDENT
/*
* Prefix of external names (default: LL)
*/
{ if (!prefix) {
prefix = store(lextoken.t_string);
if (strlen(prefix) > 6) {
error(linecount,
"%%prefix too long");
prefix[6] = 0;
}
}
else error(linecount,"Duplicate %%prefix");
}
';'
| C_ONERROR C_IDENT
{
#ifdef NON_CORRECTING
if (non_corr) {
warning(linecount, "%%onerror conflicts with -n option");
}
else
#endif
if (! onerror) {
onerror = store(lextoken.t_string);
}
else error(linecount,"Duplicate %%onerror");
}
';'
| C_ACTION { acount++; }
/*
* A global C-declaration
*/
| firsts
/*
* declarations for macros
*/
;
listel : C_IDENT { p_gram temp = search(TERMINAL,lextoken.t_string,ENTERING);
newtorder(g_getcont(temp));
tokens[g_getcont(temp)].t_lineno = linecount;
}
;
rule { register p_nont p;
p_gram rr;
register p_gram temp;
}
: /*
* grammar for a production rule
*/
C_IDENT { temp = search(NONTERM,lextoken.t_string,BOTH);
p = &nonterms[g_getcont(temp)];
if (p->n_rule) {
error(linecount,
"Nonterminal %s already defined", lextoken.t_string);
}
/*
* Remember the order in which the nonterminals
* were defined. Code must be generated in that
* order to keep track with the actions on the
* temporary file
*/
newnorder(p - nonterms);
p->n_count = acount;
acount = 0;
p->n_lineno = linecount;
p->n_off = ftell(fact);
}
[ C_PARAMS { if (lextoken.t_num > 0) {
p->n_flags |= PARAMS;
if (lextoken.t_num > 15) {
error(linecount,"Too many parameters");
}
else setntparams(p,lextoken.t_num);
}
}
]?
[ C_ACTION { p->n_flags |= LOCALS; }
]?
':' { in_production = 1; }
productions(&rr) ';'
{ in_production = 0; }
/*
* Do not use p->n_rule now! The nonterms array
* might have been re-allocated.
*/
{ nonterms[g_getcont(temp)].n_rule = rr;}
;
productions(p_gram *p;)
/*
* One or more alternatives
*/
{ p_gram prod;
int conflres = 0;
int t = 0;
int haddefault = 0;
int altcnt = 0;
int o_lc, n_lc;
} :
{ o_lc = linecount; }
simpleproduction(p,&conflres)
{ if (conflres & DEF) haddefault = 1; }
[
[ '|' { n_lc = linecount; }
simpleproduction(&prod,&t)
{ if (n_alts >= max_alts-2) {
alt_table = (p_gram ) ralloc(
(p_mem) alt_table,
(unsigned)(max_alts+=ALTINCR)*sizeof(t_gram));
}
if (t & DEF) {
if (haddefault) {
error(n_lc,
"More than one %%default in alternation");
}
haddefault = 1;
}
mkalt(*p,conflres,o_lc,&alt_table[n_alts++]);
altcnt++;
o_lc = n_lc;
conflres = t;
t = 0;
*p = prod;
}
]+ { if (conflres & (COND|PREFERING|AVOIDING)) {
error(n_lc,
"Resolver on last alternative not allowed");
}
mkalt(*p,conflres,n_lc,&alt_table[n_alts++]);
altcnt++;
g_settype((&alt_table[n_alts]),EORULE);
*p = copyrule(&alt_table[n_alts-altcnt],altcnt+1);
}
|
{ if (conflres & (COND|PREFERING|AVOIDING)) {
error(o_lc,
"No alternation conflict resolver allowed here");
}
/*
if (conflres & DEF) {
error(o_lc,
"No %%default allowed here");
}
*/
}
]
{ n_alts -= altcnt; }
;
{
STATIC
mkalt(prod,condition,lc,res) p_gram prod; register p_gram res; {
/*
* Create an alternation and initialise it.
*/
register p_link l;
static p_link list;
static int cnt;
if (! cnt) {
cnt = 50;
list = (p_link) alloc(50 * sizeof(t_link));
}
cnt--;
l = list++;
l->l_rule = prod;
l->l_flag = condition;
g_setlink(res,l);
g_settype(res,ALTERNATION);
res->g_lineno = lc;
nalts++;
}
}
simpleproduction(p_gram *p; register int *conflres;)
{ t_gram elem;
int elmcnt = 0;
int cnt, kind;
int termdeleted = 0;
} :
[ C_DEFAULT { *conflres |= DEF; }
]?
[
/*
* Optional conflict reslover
*/
C_IF C_EXPR { *conflres |= COND; }
| C_PREFER { *conflres |= PREFERING; }
| C_AVOID { *conflres |= AVOIDING; }
]?
[ C_ILLEGAL {
#ifdef NON_CORRECTING
if (n_rules >= max_rules-2) {
rule_table = (p_gram) ralloc(
(p_mem) rule_table,
(unsigned)(max_rules+=RULEINCR)*sizeof(t_gram));
}
elmcnt++;
rule_table[n_rules++] =
*search(TERMINAL, "LLILLEGAL", BOTH);
if (*conflres & DEF) {
error(linecount, "%%illegal not allowed in %%default rule");
}
#endif
}
]?
[ %persistent elem(&elem)
{ if (n_rules >= max_rules-2) {
rule_table = (p_gram) ralloc(
(p_mem) rule_table,
(unsigned)(max_rules+=RULEINCR)*sizeof(t_gram));
}
kind = FIXED;
cnt = 0;
}
[ repeats(&kind, &cnt)
{ if (g_gettype(&elem) != TERM) {
rule_table[n_rules] = elem;
g_settype((&rule_table[n_rules+1]),EORULE);
mkterm(copyrule(&rule_table[n_rules],2),
0,
elem.g_lineno,
&elem);
}
}
|
{ if (g_gettype(&elem) == TERM) {
register p_term q = g_getterm(&elem);
if (! (q->t_flags & RESOLVER) &&
g_gettype(q->t_rule) != ALTERNATION &&
g_gettype(q->t_rule) != EORULE) {
while (g_gettype(q->t_rule) != EORULE) {
rule_table[n_rules++] = *q->t_rule++;
elmcnt++;
if (n_rules >= max_rules-2) {
rule_table = (p_gram) ralloc(
(p_mem) rule_table,
(unsigned)(max_rules+=RULEINCR)*sizeof(t_gram));
}
}
elem = *--(q->t_rule);
n_rules--;
elmcnt--;
if (q == t_list - 1) {
t_list--;
nterms--;
t_cnt++;
}
termdeleted = 1;
}
}
}
] { if (!termdeleted && g_gettype(&elem) == TERM) {
register p_term q;
q = g_getterm(&elem);
r_setkind(q,kind);
r_setnum(q,cnt);
if ((q->t_flags & RESOLVER) &&
(kind == PLUS || kind == FIXED)) {
error(linecount,
"%%while not allowed in this term");
}
/*
* A persistent fixed term is the same
* as a non-persistent fixed term.
* Should we complain?
if ((q->t_flags & PERSISTENT) &&
kind == FIXED) {
error(linecount,
"Illegal %%persistent");
}
*/
}
termdeleted = 0;
elmcnt++;
rule_table[n_rules++] = elem;
}
]* { register p_term q;
g_settype((&rule_table[n_rules]),EORULE);
*p = 0;
n_rules -= elmcnt;
if (g_gettype(&rule_table[n_rules]) == TERM &&
elmcnt == 1) {
q = g_getterm(&rule_table[n_rules]);
if (r_getkind(q) == FIXED &&
r_getnum(q) == 0) {
*p = q->t_rule;
}
}
if (!*p) *p = copyrule(&rule_table[n_rules],
elmcnt+1);
}
;
{
STATIC
mkterm(prod,flags,lc,result) p_gram prod; register p_gram result; {
/*
* Create a term, initialise it and return
* a grammar element containing it
*/
register p_term q;
if (! t_cnt) {
t_cnt = 50;
t_list = (p_term) alloc(50 * sizeof(t_term));
}
t_cnt--;
q = t_list++;
q->t_rule = prod;
q->t_contains = 0;
q->t_flags = flags;
g_settype(result,TERM);
g_setterm(result,q);
result->g_lineno = lc;
nterms++;
}
}
elem (register p_gram pres;)
{ register int t = 0;
p_gram p1;
int ln;
p_gram pe;
#ifdef NON_CORRECTING
int erroneous = 0;
#endif
} :
'[' { ln = linecount; }
[ C_WHILE C_EXPR { t |= RESOLVER; }
]?
[ C_PERSISTENT { t |= PERSISTENT; }
]?
productions(&p1)
']' {
mkterm(p1,t,ln,pres);
}
|
[ C_ERRONEOUS {
#ifdef NON_CORRECTING
erroneous = 1;
#endif
}
]?
[
C_IDENT { pe = search(UNKNOWN,lextoken.t_string,BOTH);
*pres = *pe;
#ifdef NON_CORRECTING
if (erroneous) {
if (g_gettype(pres) != TERMINAL){
warning(linecount,
"Erroneous only allowed on terminal");
erroneous = 0;
}
else
pres->g_erroneous = 1;
}
#endif
}
[ C_PARAMS { if (lextoken.t_num > 15) {
error(linecount,"Too many parameters");
} else g_setnpar(pres,lextoken.t_num);
if (g_gettype(pres) == TERMINAL) {
error(linecount,
"Terminal with parameters");
}
}
]?
| C_LITERAL { pe = search(LITERAL,lextoken.t_string,BOTH);
*pres = *pe;
#ifdef NON_CORRECTING
if (erroneous)
pres->g_erroneous = 1;
#endif
}
]
| { g_settype(pres,ACTION);
pres->g_lineno = linecount;
#ifdef NON_CORRECTING
g_setsubparse(pres, (p_start) 0);
#endif
}
[ C_SUBSTART
{
#ifdef NON_CORRECTING
nsubstarts++;
#endif
}
C_IDENT
{
#ifdef NON_CORRECTING
register p_gram temp;
register p_start subp;
temp = search(NONTERM,lextoken.t_string,BOTH);
subp = (p_start) alloc (sizeof(t_start));
subp->ff_nont = g_getcont(temp);
subp->ff_name = (string) 0;
subp->ff_next = (p_start) 0;
g_setsubparse(pres, subp);
#endif
}
[ ',' C_IDENT
{
#ifdef NON_CORRECTING
register p_gram temp;
register p_start ff;
temp = search(NONTERM,lextoken.t_string,BOTH);
ff = g_getsubparse(pres);
while (ff) {
if (ff->ff_nont == g_getcont(temp)) {
warning(linecount, "\"%s\" used twice in %%substart", lextoken.t_string);
break;
}
ff = ff->ff_next;
}
ff = (p_start) alloc(sizeof(t_start));
ff->ff_nont = g_getcont(temp);
ff->ff_name = (string) 0;
ff->ff_next = g_getsubparse(pres);
g_setsubparse(pres, ff);
#endif
}
]* ';'
]?
C_ACTION
;
repeats(int *kind; int *cnt;) { int t1 = 0; } :
[
'?' { *kind = OPT; }
| [ '*' { *kind = STAR; }
| '+' { *kind = PLUS; }
]
number(&t1)?
{ if (t1 == 1) {
t1 = 0;
if (*kind == STAR) *kind = OPT;
if (*kind == PLUS) *kind = FIXED;
}
}
| number(&t1)
] { *cnt = t1; }
;
number(int *t;)
: C_NUMBER
{ *t = lextoken.t_num;
if (*t <= 0 || *t >= 8192) {
error(linecount,"Illegal number");
}
}
;
firsts { register string p; }
: C_FIRST C_IDENT
{ p = store(lextoken.t_string); }
',' C_IDENT ';'
{ /*
* Store this %first in the list belonging
* to this input file
*/
p_gram temp;
register p_first ff;
temp = search(NONTERM,lextoken.t_string,BOTH);
ff = (p_first) alloc(sizeof(t_first));
ff->ff_nont = g_getcont(temp);
ff->ff_name = p;
ff->ff_next = pfile->f_firsts;
pfile->f_firsts = ff;
}
;
{
STATIC p_gram
copyrule(p,length) register p_gram p; {
/*
* Returns a pointer to a grammar rule that was created in
* p. The space pointed to by p can now be reused
*/
register p_gram t;
p_gram rule;
t = (p_gram) alloc((unsigned) length * sizeof(t_gram));
rule = t;
while (length--) {
*t++ = *p++;
}
return rule;
}
}

View File

@@ -1,90 +0,0 @@
/* Copyright (c) 1991 by the Vrije Universiteit, Amsterdam, the Netherlands.
* For full copyright and restrictions on use see the file COPYING in the top
* level of the LLgen tree.
*/
/*
* L L G E N
*
* An Extended LL(1) Parser Generator
*
* Author : Ceriel J.H. Jacobs
*/
/*
* alloc.c
* Interface to malloc() and realloc()
*/
#include <stdlib.h>
# include "types.h"
# include "extern.h"
# ifndef NORCSID
static string rcsid = "$Id$";
# endif
static string e_nomem = "Out of memory";
p_mem
alloc(size) unsigned size; {
/*
Allocate "size" bytes. Panic if it fails
*/
p_mem p;
if ((p = malloc(size)) == 0) fatal(linecount,e_nomem);
return p;
}
p_mem
ralloc(p,size) p_mem p; unsigned size; {
/*
Re-allocate the chunk of memory indicated by "p", to
occupy "size" bytes
*/
if ((p = realloc(p,size)) == 0) fatal(linecount,e_nomem);
return p;
}
p_mem
new_mem(p) register p_info p; {
/*
This routine implements arrays that can grow.
It must be called every time a new element is added to it.
Also, the array has associated with it a "info_alloc" structure,
which contains info on the element size, total allocated size,
a pointer to the array, a pointer to the first free element,
and a pointer to the top.
If the base of the array is remembered elsewhere, it should
be updated each time this routine is called
*/
p_mem rp;
unsigned sz;
if (p->i_max >= p->i_top) { /* No more free elements */
sz = p->i_size;
if (sizeof(char *) > 2) {
/*
Do not worry about size. Just double it.
*/
p->i_size += p->i_size;
if (! p->i_size)
p->i_size += p->i_incr * p->i_esize;
}
else {
/*
Worry about size, so only increment in chunks of i_incr.
*/
p->i_size += p->i_incr * p->i_esize;
}
p->i_ptr = !p->i_ptr ?
alloc(p->i_size) :
ralloc(p->i_ptr, p->i_size);
p->i_max = p->i_ptr + sz;
p->i_top = p->i_ptr + p->i_size;
}
rp = p->i_max;
p->i_max += p->i_esize;
return rp;
}

View File

@@ -1,138 +0,0 @@
/* Copyright (c) 1991 by the Vrije Universiteit, Amsterdam, the Netherlands.
* For full copyright and restrictions on use see the file COPYING in the top
* level of the LLgen tree.
*/
/* $Id$ */
#include "cclass.h"
char c_class[] = {
0, /* 00 */
0, /* 01 */
0, /* 02 */
0, /* 03 */
0, /* 04 */
0, /* 05 */
0, /* 06 */
0, /* 07 */
0, /* 010 */
ISSPA, /* 011 */
ISSPA, /* 012 */
0, /* 013 */
ISSPA, /* 014 */
ISSPA, /* 015 */
0, /* 016 */
0, /* 017 */
0, /* 020 */
0, /* 021 */
0, /* 022 */
0, /* 023 */
0, /* 024 */
0, /* 025 */
0, /* 026 */
0, /* 027 */
0, /* 030 */
0, /* 031 */
0, /* 032 */
0, /* 033 */
0, /* 034 */
0, /* 035 */
0, /* 036 */
0, /* 037 */
ISSPA, /* ' ' */
0, /* '!' */
0, /* '"' */
0, /* '#' */
0, /* '$' */
ISKEY, /* '%' */
0, /* '&' */
ISLIT, /* ''' */
ISACT, /* '(' */
0, /* ')' */
ISTOK, /* '*' */
ISTOK, /* '+' */
ISTOK, /* ',' */
0, /* '-' */
0, /* '.' */
ISCOM, /* '/' */
ISDIG, /* '0' */
ISDIG, /* '1' */
ISDIG, /* '2' */
ISDIG, /* '3' */
ISDIG, /* '4' */
ISDIG, /* '5' */
ISDIG, /* '6' */
ISDIG, /* '7' */
ISDIG, /* '8' */
ISDIG, /* '9' */
ISTOK, /* ':' */
ISTOK, /* ';' */
0, /* '<' */
0, /* '=' */
0, /* '>' */
ISTOK, /* '?' */
0, /* '@' */
ISLET, /* 'A' */
ISLET, /* 'B' */
ISLET, /* 'C' */
ISLET, /* 'D' */
ISLET, /* 'E' */
ISLET, /* 'F' */
ISLET, /* 'G' */
ISLET, /* 'H' */
ISLET, /* 'I' */
ISLET, /* 'J' */
ISLET, /* 'K' */
ISLET, /* 'L' */
ISLET, /* 'M' */
ISLET, /* 'N' */
ISLET, /* 'O' */
ISLET, /* 'P' */
ISLET, /* 'Q' */
ISLET, /* 'R' */
ISLET, /* 'S' */
ISLET, /* 'T' */
ISLET, /* 'U' */
ISLET, /* 'V' */
ISLET, /* 'W' */
ISLET, /* 'X' */
ISLET, /* 'Y' */
ISLET, /* 'Z' */
ISTOK, /* '[' */
0, /* '\' */
ISTOK, /* ']' */
0, /* '^' */
ISLET, /* '_' */
0, /* '`' */
ISLET, /* 'a' */
ISLET, /* 'b' */
ISLET, /* 'c' */
ISLET, /* 'd' */
ISLET, /* 'e' */
ISLET, /* 'f' */
ISLET, /* 'g' */
ISLET, /* 'h' */
ISLET, /* 'i' */
ISLET, /* 'j' */
ISLET, /* 'k' */
ISLET, /* 'l' */
ISLET, /* 'm' */
ISLET, /* 'n' */
ISLET, /* 'o' */
ISLET, /* 'p' */
ISLET, /* 'q' */
ISLET, /* 'r' */
ISLET, /* 's' */
ISLET, /* 't' */
ISLET, /* 'u' */
ISLET, /* 'v' */
ISLET, /* 'w' */
ISLET, /* 'x' */
ISLET, /* 'y' */
ISLET, /* 'z' */
ISACT, /* '{' */
ISTOK, /* '|' */
0, /* '}' */
0, /* '~' */
0 /* 0177 */
};

View File

@@ -1,17 +0,0 @@
/* Copyright (c) 1991 by the Vrije Universiteit, Amsterdam, the Netherlands.
* For full copyright and restrictions on use see the file COPYING in the top
* level of the LLgen tree.
*/
/* $Id$ */
extern char c_class[];
#define ISLET 1
#define ISDIG 2
#define ISSPA 3
#define ISKEY 4
#define ISTOK 5
#define ISCOM 6
#define ISLIT 7
#define ISACT 8

View File

@@ -1,474 +0,0 @@
/* Copyright (c) 1991 by the Vrije Universiteit, Amsterdam, the Netherlands.
* For full copyright and restrictions on use see the file COPYING in the top
* level of the LLgen tree.
*/
/*
* L L G E N
*
* An Extended LL(1) Parser Generator
*
* Author : Ceriel J.H. Jacobs
*/
/*
* check.c
* Several routines to perform checks and printouts
*/
#include <stdlib.h>
#include <string.h>
# include "types.h"
# include "extern.h"
# include "io.h"
# include "sets.h"
# include "assert.h"
# ifndef NORCSID
static string rcsid1 = "$Id$";
# endif
static string c_first = "> firstset ";
static string c_contains = "> containset ";
static string c_follow = "> followset ";
p_set setalloc();
static int level;
/* In this file are defined : */
extern conflchecks();
STATIC prline();
STATIC printset();
STATIC int check();
STATIC moreverbose();
STATIC prrule();
STATIC cfcheck();
STATIC resolve();
STATIC propagate();
STATIC spaces();
conflchecks() {
/*
* Check for conflicts, that is,
* in a repeating term, the FIRST and FOLLOW must be disjunct,
* unless there is a disambiguating condition.
* in an alternation, the sets that determine the direction to take,
* must be disjunct.
*/
register p_nont p;
register int s;
p_file x = files;
f_input = x->f_name;
if (verbose >= 3) {
for (p = nonterms; p < maxnt; p++) p->n_flags |= VERBOSE;
}
if (verbose) {
if ((fout = fopen(f_out,"w")) == NULL) fatal(1,e_noopen,f_out);
}
/*
* Check the rules in the order in which they are declared,
* and input file by input file, to give proper error messages
*/
for (; x < maxfiles; x++) {
f_input = x->f_name;
for (s = x->f_nonterminals; s != -1; s = p->n_next) {
p = &nonterms[s];
if (check(p->n_rule)) p->n_flags |= VERBOSE;
}
}
for (x = files; x < maxfiles; x++) {
f_input = x->f_name;
for (s = x->f_nonterminals; s != -1; s = p->n_next) {
p = &nonterms[s];
if (p->n_flags & RECURSIVE) {
error(p->n_lineno,
"Recursion in default for nonterminal %s",
p->n_name);
}
/*
* If a printout is needed for this rule in
* LL.output, just do it
*/
if (verbose && (p->n_flags & VERBOSE)) {
fprintf(fout,"\n%s :\n",p->n_name);
printset(p->n_first,c_first);
printset(p->n_contains,c_contains);
printset(p->n_follow,c_follow);
fprintf(fout,"> rule%s\n\t",
p->n_flags&EMPTY ? "\t(EMPTY producing)" : "");
level = 8;
prrule(p->n_rule);
level = 0;
prline("\n");
}
/*
* Now, the conflicts may be resolved
*/
resolve(p->n_rule);
}
}
if (verbose) fclose(fout);
}
STATIC
prline(s) char *s; {
fputs(s, fout);
spaces();
}
STATIC
printset(p,s) register p_set p; string s; {
/*
* Print the elements of a set
*/
register int i;
register int j;
register p_token pt;
string name;
int k;
int hulp;
k = strlen(s) + 2 + level;
/*
* k contains relative level of indentation
*/
fprintf(fout,"%s{ ",s);
j = k;
/*
* j will gather the total length of the line
*/
for (i = 0, pt = tokens; i < ntokens; i++,pt++) {
if (IN(p,i)) {
hulp = strlen(pt->t_string)+1;
if (pt->t_tokno < 0400) hulp += 2;
if ((j += hulp) >= 78) {
/*
* Line becoming too long
*/
j = k+hulp;
prline("\n");
fprintf(fout,">%*c",k - level - 1,' ');
}
fprintf(fout, pt->t_tokno<0400 ? "'%s' " : "%s ",pt->t_string);
}
}
if (ntprint) for (i = 0; i < nnonterms; i++) {
/*
* Nonterminals in the set must also be printed
*/
if (NTIN(p,i)) {
name = nonterms[i].n_name;
hulp = strlen(name) + 3;
if ((j += hulp) >= 78) {
j = k + hulp;
prline("\n");
fprintf(fout,">%*c",k - level - 1,' ');
}
fprintf(fout,"<%s> ",name);
}
}
prline("}\n");
}
STATIC int
check(p) register p_gram p; {
/*
* Search for conflicts in a grammar rule.
*/
register p_set temp;
register int retval;
retval = 0;
for (;;) {
switch (g_gettype(p)) {
case EORULE :
return retval;
case NONTERM : {
register p_nont n;
n = &nonterms[g_getcont(p)];
if (g_getnpar(p) != getntparams(n)) {
error(p->g_lineno,
"Call of %s: parameter count mismatch",
n->n_name);
}
break; }
case TERM : {
register p_term q;
q = g_getterm(p);
retval |= check(q->t_rule);
if (r_getkind(q) == FIXED) break;
if (setempty(q->t_first)) {
q->t_flags |= EMPTYFIRST;
retval = 1;
error(p->g_lineno, "No symbols in term");
}
if (empty(q->t_rule)) {
q->t_flags |= EMPTYTERM;
retval = 1;
error(p->g_lineno, "Term with variable repetition count produces empty");
}
temp = setalloc();
setunion(temp,q->t_first);
if (!setintersect(temp,q->t_follow)) {
/*
* q->t_first * q->t_follow != EMPTY
*/
if (!(q->t_flags & RESOLVER)) {
/*
* No conflict resolver
*/
error(p->g_lineno,
"Repetition conflict");
retval = 1;
moreverbose(temp);
}
}
else {
if (q->t_flags & RESOLVER) {
q->t_flags |= NOCONF;
warning(p->g_lineno,
"%%while without conflict");
}
}
free((p_mem) temp);
break; }
case ALTERNATION : {
register p_link l;
l = g_getlink(p);
temp = setalloc();
setunion(temp,l->l_symbs);
if(!setintersect(temp,l->l_others)) {
/*
* temp now contains the conflicting
* symbols
*/
if (!(l->l_flag & (COND|PREFERING|AVOIDING))) {
error(p->g_lineno,
"Alternation conflict");
retval = 1;
moreverbose(temp);
}
} else {
if (l->l_flag & (COND|PREFERING|AVOIDING)) {
l->l_flag |= NOCONF;
warning(p->g_lineno,
"Conflict resolver without conflict");
}
}
free( (p_mem) temp);
if (l->l_flag & PREFERING) propagate(l->l_symbs,p+1);
retval |= check(l->l_rule);
break; }
}
p++;
}
}
STATIC
moreverbose(t) register p_set t; {
/*
* t points to a set containing conflicting symbols and pssibly
* also containing nonterminals.
* Take care that a printout will be prepared for these nonterminals
*/
register int i;
register p_nont p;
if (verbose == 2) for (i = 0, p = nonterms; i < nnonterms; i++, p++) {
if (NTIN(t,i)) p->n_flags |= VERBOSE;
}
}
STATIC
prrule(p) register p_gram p; {
/*
* Create a verbose printout of grammar rule p
*/
register FILE *f;
int present = 0;
int firstalt = 1;
f = fout;
for (;;) {
switch (g_gettype(p)) {
case EORULE :
fputs("\n",f);
return;
case TERM : {
register p_term q;
register int c;
q = g_getterm(p);
if (present) prline("\n");
fputs("[ ",f);
level += 4;
if (q->t_flags & RESOLVER) {
prline("%while (..)\n");
}
if (q->t_flags & PERSISTENT) {
prline("%persistent\n");
}
if (r_getkind(q) != FIXED) {
if (!(q->t_flags & PERSISTENT)) {
prline("> continue repetition on the\n");
}
printset(q->t_first, c_first);
if (q->t_flags & PERSISTENT) {
prline("> continue repetition on the\n");
}
printset(q->t_contains, c_contains);
prline("> terminate repetition on the\n");
printset(q->t_follow,c_follow);
if (q->t_flags & EMPTYFIRST) {
prline(">>> empty first\n");
}
if (q->t_flags & EMPTYTERM) {
prline(">>> term produces empty\n");
}
cfcheck(q->t_first,q->t_follow,
q->t_flags & RESOLVER);
}
prrule(q->t_rule);
level -= 4;
spaces();
c = r_getkind(q);
fputs(c == STAR ? "]*" : c == PLUS ? "]+" :
c == OPT ? "]?" : "]", f);
if (c = r_getnum(q)) {
fprintf(f,"%d",c);
}
prline("\n");
break; }
case ACTION :
fputs("{..} ",f);
break;
case ALTERNATION : {
register p_link l;
l = g_getlink(p);
if (firstalt) {
firstalt = 0;
}
else prline("|\n");
printset(l->l_symbs,"> alternative on ");
cfcheck(l->l_symbs,
l->l_others,
(int)(l->l_flag&(COND|PREFERING|AVOIDING)));
fputs(" ",f);
level += 4;
if (l->l_flag & DEF) {
prline("%default\n");
}
if (l->l_flag & AVOIDING) {
prline("%avoid\n");
}
if (l->l_flag & PREFERING) {
prline("%prefer\n");
}
if (l->l_flag & COND) {
prline("%if ( ... )\n");
}
prrule(l->l_rule);
level -= 4;
if (g_gettype(p+1) == EORULE) {
return;
}
spaces();
p++; continue; }
case LITERAL :
case TERMINAL : {
register p_token pt = &tokens[g_getcont(p)];
fprintf(f,pt->t_tokno<0400 ?
"'%s' " : "%s ", pt->t_string);
break; }
case NONTERM :
fprintf(f,"%s ",nonterms[g_getcont(p)].n_name);
break;
}
p++;
present = 1;
}
}
STATIC
cfcheck(s1,s2,flag) p_set s1,s2; {
/*
* Check if s1 and s2 have elements in common.
* If so, flag must be non-zero, indicating that there is a
* conflict resolver, otherwise, flag must be zero, indicating
* that there is not.
*/
register p_set temp;
temp = setalloc();
setunion(temp,s1);
if (!setintersect(temp,s2)) {
if (! flag) {
printset(temp,">>> conflict on ");
prline("\n");
}
} else {
if (flag) {
prline(">>> %if/%while, no conflict\n");
}
}
free((p_mem) temp);
}
STATIC
resolve(p) register p_gram p; {
/*
* resolve conflicts, as specified by the user
*/
for (;;) {
switch (g_gettype(p)) {
case EORULE :
return;
case TERM :
resolve(g_getterm(p)->t_rule);
break;
case ALTERNATION : {
register p_link l;
l = g_getlink(p);
if (l->l_flag & AVOIDING) {
/*
* On conflicting symbols, this rule
* is never chosen
*/
setminus(l->l_symbs,l->l_others);
}
if (setempty(l->l_symbs)) {
/*
* This may be caused by the statement above
*/
error(p->g_lineno,"Alternative never chosen");
}
resolve(l->l_rule);
break; }
}
p++;
}
}
STATIC
propagate(set,p) p_set set; register p_gram p; {
/*
* Propagate the fact that on the elements of set the grammar rule
* p will not be chosen.
*/
while (g_gettype(p) != EORULE) {
setminus(g_getlink(p)->l_symbs,set);
p++;
}
}
STATIC
spaces() {
if (level > 0) fprintf(fout,"%*c",level,' ');
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,94 +0,0 @@
/* Copyright (c) 1991 by the Vrije Universiteit, Amsterdam, the Netherlands.
* For full copyright and restrictions on use see the file COPYING in the top
* level of the LLgen tree.
*/
/*
* L L G E N
*
* An Extended LL(1) Parser Generator
*
* Author : Ceriel J.H. Jacobs
*/
/*
* $Id$
* Miscellanious constants and
* some variables that are visible in more than one file
*/
# define LTEXTSZ 256 /* Size of longest token */
/*
* options for the identifier search routine
*/
# define ENTERING 1
# define BOTH 2
/*
* Now for some declarations
*/
extern char ltext[]; /* input buffer */
extern int nnonterms; /* number of nonterminals */
extern int ntokens; /* number of terminals */
extern int nterms; /* number of terms */
extern int nalts; /* number of alternatives */
extern p_start start; /* will contain startsymbols */
#ifdef NON_CORRECTING
extern int nsubstarts; /* number of subparserstarts */
extern p_set start_firsts; /* Will contain the union of first sets of
startsymbols when -n -s option is on */
#endif
extern int linecount; /* line number */
extern int assval; /* to create difference between literals
* and other terminals
*/
extern p_nont nonterms; /* the nonterminal array */
extern p_nont maxnt; /* is filled up until here */
extern p_token tokens; /* the token array */
extern p_token maxt; /* is filled up until here */
extern int norder, torder;
/* order of nonterminals in the grammar,
* important because actions are copied to
* a temporary file in the order in which they
* were read
*/
extern string e_noopen; /* Error message string used often */
extern int verbose; /* Level of verbosity */
extern int wflag; /* warnings? */
extern string lexical; /* name of lexical analyser */
extern string prefix; /* prefix of externals */
extern string onerror; /* name of user error handler */
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 p_file maxfiles;
extern string LLgenid; /* LLgen identification string */
extern t_token lextoken; /* the current token */
extern int nerrors;
extern string rec_file, incl_file;
#ifdef NON_CORRECTING
extern string nc_rec_file, nc_incl_file;
#endif
extern int low_percentage, high_percentage;
extern int min_cases_for_jmptable;
extern int jmptable_option;
extern int ansi_c;
#ifdef NON_CORRECTING
extern int non_corr;
extern int subpars_sim;
extern p_gram illegal_gram;
#endif
extern int strip_grammar;
extern int in_production;

File diff suppressed because it is too large Load Diff

View File

@@ -1,89 +0,0 @@
/* Copyright (c) 1991 by the Vrije Universiteit, Amsterdam, the Netherlands.
* For full copyright and restrictions on use see the file COPYING in the top
* level of the LLgen tree.
*/
/*
* 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 "extern.h"
# include "io.h"
# ifndef NORCSID
static string rcsid4 = "$Id$";
# endif
char ltext[LTEXTSZ];
p_nont nonterms;
p_nont maxnt;
int nnonterms;
p_token tokens;
p_token maxt;
int ntokens;
int nterms, nalts;
int norder, torder;
#ifdef NON_CORRECTING
int nsubstarts;
p_set start_firsts;
#endif
p_start start;
int linecount;
int assval;
FILE *fout;
FILE *fpars;
FILE *finput;
FILE *fact;
char f_pars[] = PARSERFILE;
char f_temp[] = ACTFILE;
#ifdef NON_CORRECTING
char f_nc[20];
#endif
char f_out[20];
string f_input;
char f_include[20];
char f_rec[20];
string e_noopen = "Cannot open %s";
int verbose;
int wflag;
string lexical;
string prefix;
string onerror;
int ntneeded;
int ntprint;
# ifndef NDEBUG
int debug;
#endif /* not NDEBUG */
p_file files;
p_file maxfiles;
p_file pfile;
string LLgenid = "/* LLgen generated code from source %s */\n";
t_token lextoken;
int nerrors;
string rec_file, incl_file;
#ifdef NON_CORRECTING
string nc_rec_file, nc_incl_file;
#endif
int low_percentage = 10, high_percentage = 30;
int min_cases_for_jmptable = 8;
int jmptable_option;
int ansi_c = 0;
#ifdef NON_CORRECTING
int non_corr = 0;
int subpars_sim = 0;
p_gram illegal_gram;
#endif
int strip_grammar = 0;
int in_production; /* set when the parser is reading a production
rule.
*/

View File

@@ -1,43 +0,0 @@
/* Copyright (c) 1991 by the Vrije Universiteit, Amsterdam, the Netherlands.
* For full copyright and restrictions on use see the file COPYING in the top
* level of the LLgen tree.
*/
/*
* L L G E N
*
* An Extended LL(1) Parser Generator
*
* Author : Ceriel J.H. Jacobs
*/
/*
* $Id$
* Some important file names and variables
*/
# include <stdio.h>
/* FILES */
# define OUTFILE "%s.output" /* -v option */
# define PARSERFILE "xxxXXXXXX" /* This is what we want */
# define ACTFILE "tempXXXXXX" /* temporary file to save actions */
# define HFILE "%spars.h" /* file for "#define's " */
# define RFILE "%spars.c" /* Error recovery */
#ifdef NON_CORRECTING
# define NCFILE "%sncor.c" /* Non-corrcting error recovery */
#endif
extern FILE *finput;
extern FILE *fpars;
extern FILE *fact;
extern FILE *fout;
extern char f_pars[];
extern char f_temp[];
extern char f_out[];
extern string f_input;
extern char f_include[];
extern char f_rec[];
#ifdef NON_CORRECTING
extern char f_nc[];
#endif

View File

@@ -1,72 +0,0 @@
/* Copyright (c) 1991 by the Vrije Universiteit, Amsterdam, the Netherlands.
* For full copyright and restrictions on use see the file COPYING in the top
* level of the LLgen tree.
*/
/*
* L L G E N
*
* An Extended LL(1) Parser Generator
*
* Author : Ceriel J.H. Jacobs
*/
/*
* machdep.c
* Machine dependant things
*/
#include <stdlib.h>
#include <string.h>
# include "types.h"
# ifndef NORCSID
static string rcsid5 = "$Id$";
# endif
/* In this file the following routines are defined: */
extern UNLINK();
extern RENAME();
extern string libpath();
UNLINK(x) string x; {
/* Must remove the file "x" */
#ifdef USE_SYS
sys_remove(x); /* systemcall to remove file */
#else
unlink(x);
#endif
}
RENAME(x,y) string x,y; {
/* Must move the file "x" to the file "y" */
#ifdef USE_SYS
if(! sys_rename(x,y)) fatal(1,"Cannot rename to %s",y);
#else
unlink(y);
if (link(x,y) != 0) fatal(1,"Cannot rename to %s",y);
unlink(x);
#endif
}
string
libpath(s) string s; {
/* Must deliver a full pathname to the library file "s" */
register string p;
register length;
p_mem alloc();
string strcpy(), strcat();
char* libdir = getenv("LLGEN_LIB_DIR");
if (!libdir)
libdir = LIBDIR;
length = strlen(libdir) + strlen(s) + 2;
p = (string) alloc((unsigned) length);
strcpy(p,libdir);
strcat(p,"/");
strcat(p,s);
return p;
}

View File

@@ -1,378 +0,0 @@
/* Copyright (c) 1991 by the Vrije Universiteit, Amsterdam, the Netherlands.
* For full copyright and restrictions on use see the file COPYING in the top
* level of the LLgen tree.
*/
/*
* 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 <stdlib.h>
#include <string.h>
# include "types.h"
# include "io.h"
# include "extern.h"
# include "sets.h"
# include "assert.h"
# ifndef NORCSID
static string rcsid6 = "$Id$";
# endif
/* In this file the following routines are defined: */
extern int main();
STATIC readgrammar();
STATIC doparse();
extern error();
extern fatal();
extern comfatal();
extern copyfile();
extern install();
extern char *mktemp();
extern char *sbrk();
main(argc,argv) register string argv[]; {
register string arg;
string libpath();
char *beg_sbrk = 0;
/* Initialize */
assval = 0400;
/* read options */
while (argc >= 2 && (arg = argv[1], *arg == '-')) {
while (*++arg) {
switch(*arg) {
case 'j':
case 'J':
jmptable_option = 1;
if (*++arg)
min_cases_for_jmptable = atoi(arg);
break;
case 'w':
case 'W':
wflag = 1;
continue;
case 'v':
case 'V':
verbose++;
continue;
case 'l':
case 'L':
low_percentage = atoi(++arg);
break;
case 'h':
case 'H':
high_percentage = atoi(++arg);
break;
# ifndef NDEBUG
case 'd':
case 'D':
debug++;
continue;
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;
#endif /* not NDEBUG */
case 'x':
case 'X':
ntneeded = 1;
ntprint = 1;
continue;
case 'a':
case 'A':
ansi_c = 1;
continue;
#ifdef NON_CORRECTING
case 'n':
case 'N':
non_corr = 1;
continue;
case 's':
case 'S':
subpars_sim = 1;
continue;
#endif
case 'g':
case 'G':
strip_grammar = 1;
continue;
default:
fprintf(stderr,"illegal option : %c\n",*arg);
exit(1);
}
break;
}
argv++;
argc--;
}
if (verbose) beg_sbrk = sbrk(0);
#ifdef NON_CORRECTING
if ((subpars_sim) && (!non_corr)) {
fprintf(stderr,"option -s illegal without -n, turned off\n");
subpars_sim = 0;
}
#endif
/*
* Now check wether the sets should include nonterminals
*/
if (verbose == 2) ntneeded = 1;
/*
* Initialise
*/
# ifndef NDEBUG
if (!rec_file) {
# endif
rec_file = libpath("rec");
# ifndef NDEBUG
}
if (!incl_file) {
# endif
incl_file = libpath("incl");
# ifndef NDEBUG
}
# endif
#ifdef NON_CORRECTING
if (non_corr) {
nc_incl_file = libpath("nc_incl");
nc_rec_file = libpath ("nc_rec");
}
#endif
mktemp(f_temp);
mktemp(f_pars);
if ((fact = fopen(f_temp,"w")) == NULL) {
fputs("Cannot create temporary\n",stderr);
exit(1);
}
name_init();
readgrammar(argc,argv);
sprintf(f_out, OUTFILE, prefix ? prefix : "LL");
/* for the following two filenames only one L is used; historical
reasons ...
*/
sprintf(f_include, HFILE, prefix ? prefix : "L");
sprintf(f_rec, RFILE, prefix ? prefix : "L");
#ifdef NON_CORRECTING
if (non_corr)
sprintf(f_nc, NCFILE, prefix ? prefix : "L");
#endif
setinit(ntneeded);
maxnt = &nonterms[nnonterms];
maxt = &tokens[ntokens];
/*
* Now, the grammar is read. Do some computations
*/
co_reach(); /* Check for undefined and unreachable */
if (nerrors) comfatal();
do_compute();
conflchecks();
if (nerrors) comfatal();
fclose(fact);
if (argc-- == 1) {
fputs("No code generation for input from standard input\n",
stderr);
}
else gencode(argc);
UNLINK(f_temp);
UNLINK(f_pars);
if (verbose) {
fprintf(stderr, "number of nonterminals: %d\n", nnonterms);
fprintf(stderr, "number of tokens: %d\n", ntokens);
fprintf(stderr, "number of term structures: %d\n", nterms);
fprintf(stderr, "number of alternation structures: %d\n", nalts);
fprintf(stderr, "total memory used: %ld\n", (long)(sbrk(0) - beg_sbrk));
}
exit(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;
f_input = "standard input";
doparse(p++);
} else {
while (argc--) {
if ((finput = fopen(f_input=argv[1],"r")) == NULL) {
fatal(0,e_noopen,f_input);
}
doparse(p++);
argv++;
fclose(finput);
}
}
maxfiles = p;
if (! lexical) lexical = "yylex";
/*
* There must be a start symbol!
*/
if (! nerrors && start == 0) {
fatal(linecount,"Missing %%start");
}
if (nerrors) comfatal();
}
STATIC
doparse(p) register p_file p; {
linecount = 0;
p->f_name = f_input;
p->f_firsts = 0;
pfile = p;
torder = -1;
norder = -1;
LLparse();
p->f_nonterminals = norder;
p->f_terminals = torder;
}
/* VARARGS1 */
error(lineno,s,t,u) string s,t,u; {
/*
* Just an error message
*/
++nerrors;
if (!lineno) lineno = 1;
fprintf(stderr,"\"%s\", line %d: ",f_input, lineno);
fprintf(stderr,s,t,u);
fputs("\n",stderr);
}
/* VARARGS1 */
warning(lineno,s,t,u) string s,t,u; {
/*
* Just a warning
*/
if (wflag) return;
if (!lineno) lineno = 1;
fprintf(stderr,"\"%s\", line %d: (Warning) ",f_input, lineno);
fprintf(stderr,s,t,u);
fputs("\n",stderr);
}
/* 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(file) string file; {
/*
* Copies a file indicated by the parameter to filedescriptor fpars.
*/
register int c;
register FILE *f;
if ((f = fopen(file,"r")) == NULL) {
fatal(0,"Cannot open library file %s, call an expert",file);
}
while ((c = getc(f)) != EOF) putc(c,fpars);
fclose(f);
}
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 int c1, c2;
register FILE *f1, *f2;
int cnt;
/*
* First open temporary, generated for source
*/
if ((f1 = fopen(f_pars,"r")) == NULL) {
fatal(0,e_noopen,f_pars);
}
/*
* Now open target for reading
*/
if ((f2 = fopen(target,"r")) == NULL) {
fclose(f1);
RENAME(f_pars, target);
return;
}
/*
* Compute length of LLgen identification string. The target must
* start with that!
*/
cnt = strlen(LLgenid) + strlen(source) - 2;
/*
* Now compare the target with the temporary
*/
do {
c1 = getc(f1);
c2 = getc(f2);
if (cnt >= 0) cnt--;
} while (c1 == c2 && c1 != EOF);
fclose(f1);
fclose(f2);
/*
* Here, if c1 != c2 the target must be recreated
*/
if (c1 != c2) {
if (cnt >= 0) {
fatal(0,"%s : not a file generated by LLgen",target);
}
RENAME(f_pars,target);
}
}

View File

@@ -1,251 +0,0 @@
/* Copyright (c) 1991 by the Vrije Universiteit, Amsterdam, the Netherlands.
* For full copyright and restrictions on use see the file COPYING in the top
* level of the LLgen tree.
*/
/*
* L L G E N
*
* An Extended LL(1) Parser Generator
*
* Author : Ceriel J.H. Jacobs
*/
/*
* name.c
* Defines the symboltable search routine, a name store routine and an
* initialising routine.
*/
# include "types.h"
# include "extern.h"
# include "assert.h"
# include "io.h"
# ifndef NORCSID
static string rcsid7 = "$Id$";
# endif
# define HASHSIZE 128
# define NMSIZ 2048 /* Room for names allocated NMSIZ bytes at a time */
static char *name, *maxname;
static p_entry h_root[HASHSIZE]; /* hash table */
static string e_literal = "Illegal literal";
static p_entry entries, maxentries;
static t_info token_info, nont_info;
/* Defined in this file are: */
extern string store();
extern name_init();
STATIC int hash();
STATIC p_entry newentry();
extern p_gram search();
p_mem alloc();
p_mem new_mem();
name_init() {
token_info.i_esize = sizeof (t_token);
token_info.i_incr = 50;
nont_info.i_esize = sizeof (t_nont);
nont_info.i_incr = 50;
search(TERMINAL,"EOFILE",ENTERING);
#ifdef NON_CORRECTING
illegal_gram = search(TERMINAL,"LLILLEGAL",ENTERING);
#endif
}
STATIC p_entry
newentry(str, next) string str; p_entry next; {
register p_entry p;
if ((p = entries) == maxentries) {
p = (p_entry) alloc(50 * sizeof(t_entry));
maxentries = p + 50;
}
entries = p + 1;
p->h_name = str;
p->h_next = next;
p->h_type.g_lineno = linecount;
#ifdef NON_CORRECTING
p->h_type.g_erroneous = 0;
#endif
return p;
}
string
store(s) string s; {
/*
* Store a string s in the name table
*/
register string s1, t ,u;
u = name;
t = s;
s1 = u;
do {
if (u >= maxname) {
u = alloc(NMSIZ);
maxname = u + NMSIZ;
t = s;
s1 = u;
}
*u++ = *t;
} while (*t++);
name = u;
return s1;
}
STATIC int
hash(str) string str; {
/*
* Compute the hash for string str
*/
register int i;
register string l;
l = str;
i = 0;
while (*l != '\0') i += *l++ & 0377;
i += l - str;
return i % HASHSIZE;
}
p_gram
search(type,str,option) register string str; {
/*
* Search for object str.
* It has type UNKNOWN, LITERAL, TERMINAL or NONTERM.
* option can be ENTERING or BOTH (also looking).
*/
register int val = 0;
register p_entry p;
register int i;
int type1;
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)) {
type1 = g_gettype(&(p->h_type));
if (type1 != type) {
if (type1 == LITERAL || type == LITERAL) {
continue;
}
if (type == TERMINAL) {
error(linecount,
"%s: is already a nonterminal",
str);
continue;
}
else if (type == NONTERM) {
error(linecount,
"%s : is already a token",
str);
continue;
}
}
if (option==ENTERING) {
error(linecount,
"%s : is already defined",str);
}
p->h_type.g_lineno = linecount;
return &(p->h_type);
}
}
p = newentry(store(str), h_root[i]);
h_root[i] = p;
if (type == TERMINAL || type == LITERAL) {
register p_token pt;
pt = (p_token) new_mem(&token_info);
tokens = (p_token) token_info.i_ptr;
pt->t_string = p->h_name;
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);
}
pt->t_tokno = val;
g_settype(&(p->h_type), LITERAL);
} else {
/*
* Here, type = TERMINAL
*/
pt->t_tokno = assval++;
g_settype(&(p->h_type), TERMINAL);
}
g_setcont(&(p->h_type), ntokens);
ntokens++;
return &(p->h_type);
}
/*
* type == NONTERM || type == UNKNOWN
* UNKNOWN and not yet declared means : NONTERM
*/
{
register p_nont q;
q = (p_nont) new_mem(&nont_info);
nonterms = (p_nont) nont_info.i_ptr;
q->n_name = p->h_name;
q->n_rule = 0;
q->n_lineno = linecount;
q->n_string = f_input;
q->n_follow = 0;
q->n_flags = 0;
q->n_contains = 0;
g_settype(&(p->h_type), NONTERM);
g_setcont(&(p->h_type), nnonterms);
g_setnpar(&(p->h_type), 0);
nnonterms++;
return &(p->h_type);
}
}

View File

@@ -1,135 +0,0 @@
/* Copyright (c) 1991 by the Vrije Universiteit, Amsterdam, the Netherlands.
* For full copyright and restrictions on use see the file COPYING in the top
* level of the LLgen tree.
*/
/*
* 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 "types.h"
# include "extern.h"
# include "io.h"
# include "assert.h"
# ifndef NORCSID
static string rcsid8 = "$Id$";
# endif
/* In this file the following routines are defined: */
extern co_reach();
STATIC reachable();
STATIC reachwalk();
co_reach() {
/*
* Check for undefined or unreachable nonterminals.
*/
register p_nont p;
register p_token t;
register p_start st;
register p_file x;
register int s;
/* Check for undefined nonterminals */
for (p = nonterms; p < maxnt; p++) {
if (! p->n_rule) { /* undefined */
f_input = p->n_string;
error(p->n_lineno,"Nonterminal %s not defined",
p->n_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(&nonterms[st->ff_nont]);
}
/*
* Now check for unreachable nonterminals
*/
for (x = files; x < maxfiles; x++) {
f_input = x->f_name;
for (s = x->f_nonterminals; s != -1; s = p->n_next) {
p = &nonterms[s];
if (! (p->n_flags & REACHABLE)) {
warning(p->n_lineno,"nonterminal %s unreachable",
p->n_name);
}
}
for (s = x->f_terminals; s != -1; s = t->t_next) {
t = &tokens[s];
if (! (t->t_flags & REACHABLE)) {
warning(t->t_lineno,"terminal %s not used",
t->t_string);
}
}
}
}
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
*/
if (p->n_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(g_getlink(p)->l_rule);
break;
case TERM :
reachwalk(g_getterm(p)->t_rule);
break;
case NONTERM : {
register p_nont n = &nonterms[g_getcont(p)];
reachable(n);
if (n->n_rule && g_gettype(n->n_rule) == EORULE &&
! g_getnpar(p) && (getntparams(n) == 0)) {
register p_gram np = p;
do {
*np = *(np + 1);
np++;
} while (g_gettype(np) != EORULE);
continue;
}
break;
}
case TERMINAL:
tokens[g_getcont(p)].t_flags |= REACHABLE;
break;
case EORULE :
return;
}
p++;
}
}

View File

@@ -1,385 +0,0 @@
/* Copyright (c) 1991 by the Vrije Universiteit, Amsterdam, the Netherlands.
* All rights reserved.
*/
#ifdef NON_CORRECTING
/*
* L L G E N
*
* An Extended LL(1) Parser Generator
*
* Author : Ceriel J.H. Jacobs
*/
/*
* savegram.c
* Save the input grammar for non-correcting error recovery
*
* Grammar rules are `flattened' by introducing anonymous nonterminals.
* [B]? becomes X; X: B | {empty}
* [B]+ becomes X: B Y; Y: X | {empty}
* [B]* becomes X; X: B X | {empty}
* [B | C] becomes X; X: B | C
* [B | C]* becomes X; X: B X | C X | {empty} etc.
*/
# include "types.h"
# include "extern.h"
# include "io.h"
# include "assert.h"
# include "sets.h"
#define LLALT 9999
static int nt_highest;
extern int nbytes;
extern p_mem alloc();
extern p_set start_firsts;
extern p_set setalloc();
extern p_gram search();
STATIC save_rule();
STATIC save_set();
/* t_list will contain terms to be `flattened' */
static struct t_list {
p_term term;
int t_nt_num;
} *t_list;
/* Subparse list will contain symbols in %substart */
static struct subparse_list {
p_gram sub_action;
int sub_nt_num;
} *sub_list;
/* Index in t_list */
static int t_list_index;
/* Index in subparse_list */
static int sub_list_index;
/* File to save grammar to */
static FILE *fgram;
/* Nonterminal number to simulate parsers that get called in actions
used when LLgen called with -n -s options */
int act_nt;
save_grammar(f) FILE *f; {
/*
* Save the grammar
*/
register p_nont p;
register p_start st;
register int nt_nr;
fgram = f;
/* Compute highest nonterminal nr. */
nt_highest = nnonterms + assval - 1;
/* Generate some constants in the grammar file */
/* Allocate terms list */
t_list = (struct t_list *) alloc((unsigned) nterms * sizeof(struct t_list));
t_list_index = 0;
sub_list = (struct subparse_list *) alloc(nsubstarts * sizeof(struct subparse_list));
fputs("static ", fgram);
fputs((prefix ? prefix : "LL"), fgram);
fputs("grammar[] = {\n", fgram);
/* Check if -n -s option is on */
if (subpars_sim) {
/* Allocate action simulation nt */
act_nt = ++nt_highest;
/* write simualtion rule */
fprintf(fgram, "/* Simulation rule */\n");
fprintf(fgram, "%d,\n", act_nt);
/* Put a firstset and a fake followset */
/* Followset optimization is not implemented for
-s because it would be hard, and does not
bring enough improvement to jutify the effort
*/
save_set(start_firsts);
save_set(start_firsts);
/* Simulation rule procudes empty */
fprintf(fgram, "%d,\n", 1);
for (st = start; st; st = st->ff_next)
{
fprintf(fgram, "%d, %d, %d, \n", st->ff_nont + assval,
act_nt, LLALT);
}
fprintf(fgram, "%d, \n", 0);
}
/* Now process all rules */
for (p = nonterms, nt_nr = assval; p < maxnt; p++, nt_nr++) {
fprintf(fgram, "/* nr. %d %s */\n", nt_nr, p->n_name);
fprintf(fgram, "%d, ",nt_nr);
if (! p->n_rule) { /* undefined */
f_input = p->n_string;
error(p->n_lineno,"Nonterminal %s not defined",
p->n_name);
}
/* Save the first_set and follow set */
save_set(p->n_nc_first);
save_set(p->n_nc_follow);
if (p->n_flags & EMPTY)
fprintf(fgram, "%d,\n", 1);
else
fprintf(fgram, "%d,\n", 0);
save_rule(p->n_rule, 0);
fprintf(fgram, "%d,\n", 0);
}
/* Resolve terms, they are on t_list */
fprintf(fgram, "/* Fresh nonterminals */\n");
{ int i;
for (i = 0; i < t_list_index; i++)
{
/* Terms of the form [] without + ? * or number produce
a NIL pointer in the term-list */
if ((t_list + i)->term == (struct term *) 0) {
continue;
}
fprintf(fgram, "%d, ", (t_list + i)->t_nt_num);
/* Save the first and follow sets */
save_set((t_list + i)->term->t_nc_first);
save_set((t_list + i)->term->t_nc_follow);
/* NOTE: A VARIABLE REPETITION COUNT TERMS RULE IS NOT
ALLOWED TO PRODUCE EMPTY IN LLGEN
*/
switch(r_getkind((t_list + i)->term)) {
case FIXED:
/* Already done by repeating new nonterminal */
/* FIXED term-rule may produce empty */
if (empty((t_list +i)->term->t_rule))
fprintf(fgram, "%d,\n", 1);
else
fprintf(fgram, "%d,\n", 0);
save_rule((t_list + i)->term->t_rule, 0);
fprintf(fgram, "%d,\n", 0);
break;
case STAR:
/* Save the rule, appending the new lhs for this rule */
/* Star rules always produce empty */
fprintf(fgram, "1,\n");
save_rule((t_list + i)->term->t_rule,
(t_list + i)->t_nt_num);
fprintf(fgram, "%d,\n%d,\n", LLALT, 0);
/* ALT EMPTY*/
break;
case PLUS:
/* Save the rule appending a fresh nonterminal */
fprintf(fgram, "%d,\n", 0);
save_rule((t_list + i)->term->t_rule, ++nt_highest);
fprintf(fgram, "%d,\n", 0); /* EOR */
fprintf(fgram, "%d, ", nt_highest);
/* First set of the extra nonterm is same as
for the term */
/* Except that the new nonterm also produces empty ! */
save_set((t_list + i)->term->t_nc_first);
save_set((t_list + i)->term->t_nc_follow);
fprintf(fgram, "1,\n");
fprintf(fgram, "%d, ", (t_list+i)->t_nt_num);
fprintf(fgram, "%d,\n%d,\n", LLALT, 0); /* ALT EMPTY */
break;
case OPT:
fprintf(fgram, "1,\n");
save_rule((t_list + i)->term->t_rule, 0);
fprintf(fgram, "%d,\n%d,\n", LLALT, 0); /* ALT EMPTY */
break;
}
}
}
/* Resolve %substarts */
if (!subpars_sim) {
int i,s,check;
p_start ff, gg;
p_set temp_set;
for (i = 0; i < sub_list_index; i++) {
fprintf(fgram, "%d, ", (sub_list + i)->sub_nt_num);
/* Compute the first set */
temp_set = setalloc();
for (ff = g_getsubparse((sub_list + i)->sub_action);
ff; ff = ff->ff_next){
s = setunion(temp_set,
(&nonterms[ff->ff_nont])->n_first);
check = 0;
for (gg =start; gg; gg = gg->ff_next)
if (ff->ff_nont == gg->ff_nont)
check = 1;
if (check == 0)
warning((sub_list + i)->sub_action->g_lineno,
"\"%s\" is not a startsymbol",
(&nonterms[ff->ff_nont])->n_name);
}
save_set(temp_set);
save_set(temp_set);
free(temp_set);
/* Produces empty */
fprintf(fgram, "1,\n");
ff = g_getsubparse((sub_list + i)->sub_action);
for (; ff; ff = ff->ff_next)
fprintf(fgram, "%d, %d, %d, \n", ff->ff_nont + assval,
(sub_list + i)->sub_nt_num,
LLALT);
fprintf(fgram, "%d, \n", 0);
}
}
fprintf(fgram, "%d\n};\n", 0);
fprintf(fgram, "#define LLNNONTERMINALS %d\n", nt_highest - assval + 1);
}
STATIC
save_rule(p, tail) register p_gram p; int tail; {
/*
Walk through rule p, saving it. The non-terminal tail is
appended to the rule. It needs to be appended in this function
to process alt-rules correctly. Tail == 0 means don't append.
*/
int in_alt;
int illegal_num;
/* Processing an alt needs some special care. When processing the
first alternative, we don't want to write the alt-code;
When appending something to the alt, it needs to be appended to
every alternative and not at the end of the rule.
*/
/* Look up the ILLEGAL token number */
illegal_num = tokens[g_getcont(illegal_gram)].t_tokno;
in_alt = 0;
for (;;) {
switch(g_gettype(p)) {
case ALTERNATION :
if (in_alt)
fprintf(fgram, "%d,\n", LLALT);
else
in_alt = 1;
save_rule(g_getlink(p)->l_rule, tail);
break;
case TERM :
/* Make entry in term list */
(t_list + t_list_index)->term = g_getterm(p);
/* Test for [] without specifier */
if (g_getterm(p) == (struct term *) 0) {
t_list_index++;
break;
}
(t_list + t_list_index++)->t_nt_num = ++nt_highest;
fprintf(fgram, "%d, ", nt_highest);
/* Check if repetition, if so handle here */
if (r_getkind(g_getterm(p)) == FIXED)
{
int k;
for (k = 1; k < r_getnum(g_getterm(p)); k++)
fprintf(fgram, "%d, ", nt_highest);
}
break;
case NONTERM :
fprintf(fgram, "%d, ", g_getcont(p) + assval);
break;
case TERMINAL:
if (g_getcont(p) == g_getcont(illegal_gram)) {
/* %illegal. Ignore. */
break;
}
if (p->g_erroneous)
fprintf(fgram, "%d, ", illegal_num);
else
fprintf(fgram, "%d, ",
tokens[g_getcont(p)].t_tokno);
break;
case LITERAL:
if (p->g_erroneous)
fprintf(fgram, "%d, ", illegal_num);
else
fprintf(fgram, "%d, ",
tokens[g_getcont(p)].t_tokno);
break;
case ACTION:
if (subpars_sim) {
fprintf(fgram, "%d, ", act_nt);
}
else if (g_getsubparse(p)) {
/* Allocate nonterminal that will simulate
subparser
*/
(sub_list + sub_list_index)->sub_nt_num =
++nt_highest;
(sub_list + sub_list_index++)->sub_action = p;
fprintf(fgram, "%d, ", nt_highest);
}
break;
case EORULE :
if ((! in_alt) && tail )
/* If this rule is not an alt, append tail now.
If it is an alt, the recursive call of this function
has appended tail to each alternative
*/
fprintf(fgram, "%d, ", tail);
return;
}
p++;
}
}
STATIC
save_set(p) p_set p; {
register int k;
register unsigned i;
int j;
j = nbytes;
for (;;) {
i = (unsigned) *p++;
for (k = 0; k < sizeof(int); k++) {
fprintf(fgram,"0%o,",(int)(i & 0377));
i >>= 8;
if (--j == 0) {
fputs("\n",fgram);
return;
}
}
}
/* NOTREACHED */
}
#endif

View File

@@ -1,218 +0,0 @@
/* Copyright (c) 1991 by the Vrije Universiteit, Amsterdam, the Netherlands.
* For full copyright and restrictions on use see the file COPYING in the top
* level of the LLgen tree.
*/
/*
* L L G E N
*
* An Extended LL(1) Parser Generator
*
* Author : Ceriel J.H. Jacobs
*/
/*
* sets.c
* Set manipulation and allocation routines.
*/
# include "types.h"
# include "extern.h"
# include "sets.h"
# include "assert.h"
# ifndef NORCSID
static string rcsid9 = "$Id$";
# endif
/* In this file the following routines are defined: */
extern setinit();
extern p_set setalloc();
extern p_set get_set();
extern int setunion();
extern int setintersect();
extern setminus();
extern int setempty();
extern int findindex();
extern int setcount();
int nbytes;
static int setsize;
int tsetsize;
p_set *setptr, *maxptr;
static t_info set_info;
p_mem alloc();
setinit(nt_needed) {
/*
* Initialises some variables needed for setcomputations
*/
register int bitset;
nbytes = NBYTES(ntokens);
bitset = ALIGN(nbytes);
tsetsize = NINTS(bitset);
if (nt_needed) {
/* nonterminals must be included in the sets */
bitset += NBYTES(nnonterms);
}
setsize = NINTS(bitset);
set_info.i_esize = sizeof(p_set);
set_info.i_incr = 20;
}
p_set
get_set() {
/*
* Allocate a set that cannot be freed
*/
register p_set p, q;
static p_set sets, maxsets;
if ((p = sets) >= maxsets) {
q = p = (p_set) alloc((unsigned) (50*setsize*sizeof(*sets)));
maxsets = p + 50 * setsize;
do {
*q++ = 0;
} while (q < maxsets);
}
sets = p + setsize;;
return p;
}
p_set
setalloc() {
/*
* Allocate a set which can later be freed.
*/
register p_set p;
register int size = setsize;
p = (p_set) alloc((unsigned) (size * sizeof(*p))) + size;
do {
*--p = 0;
} while (--size);
return p;
}
int
setunion(a,b) register p_set a,b; {
/*
* a = a union b.
* Return 1 if the set a changed
*/
register int i;
register int j;
register int nsub = 0;
i = setsize;
do {
*a = (j = *a) | *b++;
if (*a++ != j) {
nsub = 1;
}
} while (--i);
return nsub;
}
int
setintersect(a,b) register p_set a,b; {
/*
* a = a intersect b.
* return 1 if the result is empty
*/
register int i;
register int nempty;
nempty = 1;
i = setsize;
do {
if (*a++ &= *b++) nempty = 0;
} while (--i);
return nempty;
}
setminus(a,b) register p_set a,b; {
/*
* a = a setminus b
*/
register int i;
i = setsize;
do {
*a++ &= ~(*b++);
} while (--i);
}
int
setempty(p) register p_set p; {
/*
* Return 1 if the set p is empty
*/
register int i;
i = tsetsize;
do {
if (*p++) return 0;
} while (--i);
return 1;
}
int
findindex(set) p_set set; {
/*
* The set "set" will serve as a recovery set.
* Search for it in the table. If not present, enter it.
* Here is room for improvement. At the moment, the list of
* sets is examined with linear search.
*/
register p_set *t;
p_mem new_mem();
register p_set a;
register p_set b;
register int i;
int saved;
/*
* First search for the set in the table
*/
for (t = setptr; t < maxptr; t++) {
a = *t;
b = set;
i = tsetsize;
do {
if (*a++ != *b++) break;
} while (--i);
if (i) continue;
/*
* Here, the sets are equal.
*/
return nbytes * (t - setptr);
}
/*
* Now check if the set consists of only one element.
* It would be a waste to use a set for that
*/
if (setcount(set, &saved) == 1) return -(saved + 1);
/*
* If it does, return its number as a negative number.
*/
maxptr = (p_set *) new_mem(&set_info);
setptr = (p_set *) set_info.i_ptr;
*maxptr = setalloc();
setunion(*maxptr, set);
return nbytes * (maxptr++ - setptr);
}
int
setcount(set, saved) register p_set set; int *saved; {
register int i, j;
for (j = 0, i = 0; i < ntokens; i++) {
if (IN(set,i)) {
j++;
*saved = i;
}
}
return j;
}

View File

@@ -1,33 +0,0 @@
/* Copyright (c) 1991 by the Vrije Universiteit, Amsterdam, the Netherlands.
* For full copyright and restrictions on use see the file COPYING in the top
* level of the LLgen tree.
*/
/*
* L L G E N
*
* An Extended LL(1) Parser Generator
*
* Author : Ceriel J.H. Jacobs
*/
/*
* $Id$
* 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)/BITS+tsetsize]&(1<<((i)%BITS)))
# define PUTIN(a,i) ((a)[(i)/BITS] |=(1<<((i) % BITS)))
# define NTPUTIN(a,i) ((a)[(i)/BITS+tsetsize]|=(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 tsetsize;
extern p_set *setptr, *maxptr;
extern int nbytes;

View File

@@ -1,604 +0,0 @@
/* Copyright (c) 1991 by the Vrije Universiteit, Amsterdam, the Netherlands.
* For full copyright and restrictions on use see the file COPYING in the top
* level of the LLgen tree.
*/
/*
* 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 LLmessage are also included here.
*/
{
# include "types.h"
# include "io.h"
# include "extern.h"
# include "assert.h"
# include "cclass.h"
# ifndef NORCSID
static string rcsidc = "$Id$";
# endif
/* Here are defined : */
extern int scanner();
extern LLmessage();
extern int input();
extern unput();
extern skipcomment();
# ifdef LINE_DIRECTIVE
STATIC linedirective();
# endif
STATIC string cpy();
STATIC string vallookup();
STATIC copyact();
static int nparams;
}
/* Classes */
%token C_IDENT ; /* lextoken.t_string contains the identifier read */
%token C_NUMBER ; /* lextoken.t_num contains the number read */
%token C_LITERAL ; /* lextoken.t_string contains the literal read */
%token C_EXPR ; /* A C expression (%if or %while) */
%token C_PARAMS ; /* formal or actual parameters */
%token C_ACTION ; /* a C action */
/* Keywords */
%token C_TOKEN ;
%token C_START ;
%token C_IF ;
%token C_WHILE ;
%token C_PERSISTENT ;
%token C_FIRST ;
%token C_LEXICAL ;
%token C_PREFIX ;
%token C_ONERROR ;
%token C_AVOID ;
%token C_PREFER ;
%token C_DEFAULT ;
%token C_SUBSTART ;
%token C_ERRONEOUS ;
%token C_ILLEGAL ;
%lexical scanner ;
{
/*
* Structure for a keyword
*/
typedef struct keyword {
string w_word;
int w_value;
} t_keyw, *p_keyw;
/*
* The list of keywords, the most often used keywords come first.
* Linear search is used, as there are not many keywords
*/
static t_keyw 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 },
{ "onerror", C_ONERROR },
{ "prefix", C_PREFIX },
#ifdef NON_CORRECTING
{ "substart", C_SUBSTART },
{ "erroneous", C_ERRONEOUS },
{ "illegal", C_ILLEGAL },
#endif
{ 0, 0 }
};
static t_token savedtok; /* to save lextoken in case of an insertion */
# ifdef LINE_DIRECTIVE
static int nostartline; /* = 0 if at the start of a line */
# endif
STATIC
copyact(ch1,ch2,flag,level) char ch1,ch2; {
/*
* Copy an action to file f. Opening bracket is ch1, closing bracket
* is ch2.
* If flag & 1, copy opening and closing parameters too.
* If flag & 2, don't allow ','.
*/
static int text_seen = 0;
register FILE *f;
register ch; /* Current char */
register match; /* used to read strings */
int saved = linecount;
/* save linecount */
int sav_strip = strip_grammar;
f = fact;
if (ch1 == '{' || flag != 1) strip_grammar = 0;
if (!level) {
text_seen = 0;
nparams = 0; /* count comma's */
putc('\0',f);
fprintf(f,"# line %d \"%s\"\n", linecount,f_input);
}
if (level || (flag & 1)) putc(ch1,f);
for (;;) {
ch = input();
if (ch == ch2) {
if (!level) {
if (text_seen) nparams++;
}
if (level || (flag & 1)) putc(ch,f);
if (strip_grammar != sav_strip) {
if (ch1 == '{' || flag != 1) putchar(ch);
}
strip_grammar = sav_strip;
return;
}
switch(ch) {
case ')':
case '}':
case ']':
error(linecount,"Parentheses mismatch");
break;
case '(':
text_seen = 1;
copyact('(',')',flag,level+1);
continue;
case '{':
text_seen = 1;
copyact('{','}',flag,level+1);
continue;
case '[':
text_seen = 1;
copyact('[',']',flag,level+1);
continue;
case '/':
ch = input();
unput(ch);
if (ch == '*') {
putc('/', f);
skipcomment(1);
continue;
}
ch = '/';
text_seen = 1;
break;
case ';':
case ',':
if (! level && text_seen) {
text_seen = 0;
nparams++;
if (ch == ',' && (flag & 2)) {
warning(linecount, "Parameters may not be separated with a ','");
ch = ';';
}
}
break;
case '\'':
case '"' :
/*
* watch out for brackets in strings, they do not
* count !
*/
text_seen = 1;
match = ch;
putc(ch,f);
while((ch = input())) {
if (ch == match) break;
if (ch == '\\') {
putc(ch,f);
ch = input();
}
if (ch == '\n') {
error(linecount,"Newline in string");
unput(match);
}
putc(ch,f);
}
if (ch == match) break;
/* Fall through */
case EOF :
if (!level) error(saved,"Action does not terminate");
strip_grammar = sav_strip;
return;
default:
if (c_class[ch] != ISSPA) text_seen = 1;
}
putc(ch,f);
}
}
scanner() {
/*
* Lexical analyser, what else
*/
register int ch; /* Current char */
register char *p = ltext;
int reserved = 0; /* reserved word? */
char *max = &ltext[LTEXTSZ - 1];
static int nextexpr;
int expect_expr = nextexpr;
long off;
nextexpr = 0;
if (savedtok.t_tokno) {
/* A token has been inserted.
* Now deliver the last lextoken again
*/
lextoken = savedtok;
savedtok.t_tokno = 0;
return lextoken.t_tokno;
}
for (;;) {
ch = input();
if (ch == EOF) return ch;
# ifdef LINE_DIRECTIVE
if (ch == '#' && !nostartline) {
linedirective();
continue;
}
# endif
switch(c_class[ch]) {
case ISACT :
if (ch == '{') {
copyact('{', '}', in_production, 0);
return C_ACTION;
}
assert(ch == '(');
if (expect_expr) {
copyact('(', ')', 1, 0);
return C_EXPR;
}
off = ftell(fact);
copyact('(', ')', in_production != 0 ? 0 : 2, 0);
if (nparams == 0) fseek(fact, off, 0);
lextoken.t_num = nparams;
return C_PARAMS;
case ISLIT :
for (;;) {
ch = input();
if (ch == '\n' || ch == EOF) {
error(linecount,"Missing '");
break;
}
if (ch == '\'') break;
if (ch == '\\') {
*p++ = ch;
ch = input();
}
*p++ = ch;
if (p > max) p--;
}
*p = '\0';
lextoken.t_string = ltext;
return C_LITERAL;
case ISCOM :
skipcomment(0);
/* Fall through */
case ISSPA :
continue;
case ISDIG : {
register i = 0;
do {
i = 10 * i + (ch - '0');
ch= input();
} while (c_class[ch] == ISDIG);
lextoken.t_num = i;
unput(ch);
return C_NUMBER; }
default:
return ch;
case ISKEY :
reserved = 1;
ch = input();
/* Fall through */
case ISLET :
do {
if (reserved && ch >= 'A' && ch <= 'Z') {
ch += 'a' - 'A';
}
*p++ = ch;
if (p > max) p--;
ch = input();
} while (c_class[ch] == ISDIG || c_class[ch] == ISLET);
unput(ch);
*p = '\0';
if (reserved) { /*
* Now search for the keyword
*/
register p_keyw w;
w = resword;
while (w->w_word) {
if (! strcmp(ltext,w->w_word)) {
/*
* Return token number.
*/
if (w->w_value == C_IF ||
w->w_value == C_WHILE) {
nextexpr = 1;
}
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;
if (c = backupc) {
/* Last char was "unput()". Deliver it again
*/
backupc = 0;
return c;
}
if ((c = getc(finput)) == EOF) {
nonline = 0;
return c;
}
# ifdef LINE_DIRECTIVE
nostartline = 1;
# endif
if (!nonline) {
linecount++;
# ifdef LINE_DIRECTIVE
nostartline = 0;
# endif
nonline = 1;
}
if (c == '\n') nonline = 0;
if (strip_grammar) putchar(c);
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 keep it.
*/
register int ch;
int saved; /* line count on which comment starts */
saved = linecount;
if (input() != '*') error(linecount,"Illegal comment");
if (flag) putc('*', fact);
do {
ch = input();
if (flag) putc(ch, fact);
while (ch == '*') {
ch = input();
if (flag) putc(ch, fact);
if (ch == '/') return;
}
} while (ch != EOF);
error(saved,"Comment does not terminate");
}
# ifdef LINE_DIRECTIVE
STATIC
linedirective() {
/*
* Read a line directive
*/
register int ch;
register int 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' && c_class[ch] != ISDIG);
if (ch == '\n') {
error(linecount,s_error);
return;
}
i = 0;
do {
i = i*10 + (ch - '0');
ch = input();
} while (c_class[ch] == ISDIG);
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;
}
# endif
STATIC string
vallookup(s) {
/*
* Look up the keyword that has token number s
*/
register p_keyw p = resword;
while (p->w_value) {
if (p->w_value == s) return p->w_word;
p++;
}
return 0;
}
STATIC string
cpy(s,p,inserted) register string p; {
/*
* Create a piece of error message for token s and put it at p.
* inserted = 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 (!inserted) t = lextoken.t_string;
else t = "identifier";
break;
case C_NUMBER :
t = "number";
break;
case C_LITERAL :
if (!inserted) {
*p++ = '\'';
t = lextoken.t_string;
break;
}
t = "literal";
break;
case C_ACTION:
t = "C action";
break;
case C_PARAMS:
t = "C parameter section";
break;
case C_EXPR:
t = "C expression";
break;
case EOFILE :
t = "end-of-file";
break;
}
if (!t && (t = vallookup(s))) {
*p++ = '%';
}
if (t) { /*
* We have a string for the token. Copy it
*/
while (*t) *p++ = *t++;
if (s == C_LITERAL && !inserted) {
*p++ = '\'';
}
return p;
}
/*
* The token is a literal
*/
*p++ = '\'';
if (s >= 040 && s <= 0176) *p++ = s;
else {
*p++ = '\\';
switch(s) {
case '\b' : *p++ = 'b'; break;
case '\f' : *p++ = 'f'; break;
case '\n' : *p++ = 'n'; break;
case '\r' : *p++ = 'r'; break;
case '\t' : *p++ = 't'; break;
default : *p++='0'+((s&0377)>>6); *p++='0'+((s>>3)&07);
*p++='0'+(s&07);
}
}
*p++ = '\'';
return p;
}
string strcpy();
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) {
strcpy(buf, "end-of-file expected");
}
else if (d == 0) {
#ifdef LLNONCORR
t = " unexpected";
#else
t = " deleted";
#endif
s = cpy(LLsymb,s,0);
do *s++ = *t; while (*t++);
} else {
s = cpy(d,s,1);
t = " inserted in front of ";
do *s++ = *t++; while (*t);
s = cpy(LLsymb,s,0);
*s = '\0';
}
if (d > 0) { /*
* Save the current token and make up some
* attributes for the inserted token
*/
savedtok = lextoken;
savedtok.t_tokno = LLsymb;
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;
}
#ifdef LLNONCORR
else
#endif
error(linecount, "%s", buf);
/* Don't change this line to
* error(linecount, buf).
* The string in "buf" might contain '%' ...
*/
#ifdef LLNONCORR
in_production = 1;
/* To prevent warnings from copyact */
#endif
}
}

View File

@@ -1,272 +0,0 @@
/* Copyright (c) 1991 by the Vrije Universiteit, Amsterdam, the Netherlands.
* For full copyright and restrictions on use see the file COPYING in the top
* level of the LLgen tree.
*/
/*
* L L G E N
*
* An Extended LL(1) Parser Generator
*
* Author : Ceriel J.H. Jacobs
*/
/*
* $Id$
* Type and structure definitions
*/
typedef int *p_set; /* pointer to bitset */
typedef char *p_mem; /* pointer to some core */
typedef char *string;
/*
* structure for a token
*/
typedef struct token {
int t_tokno; /* Lexical token number */
union {
string t_s; /* Attribute is either a string or */
int t_v; /* an integer */
} t_x;
# define t_string t_x.t_s
# define t_num t_x.t_v
int t_flags;
int t_next;
int t_lineno;
} t_token, *p_token;
/*
* structure for the grammar elements
*/
typedef struct gram {
int x; /* for lay-out see comment below */
int g_lineno; /* element found on this line number */
#ifdef NON_CORRECTING
int g_erroneous; /* 1 if element declared erroneous */
#endif
union {
int g_index;
struct term * g_term;
struct link * g_link;
#ifdef NON_CORRECTING
/* If this is an action with a %substart g_subparse
points to the list of startsymbols of the subparser */
struct ff_firsts *g_subparse;
#endif
} g_i;
} t_gram,*p_gram;
/*
* Layout of the field x:
*
* 15 ....... 7 6 ........ 3 2 .... 0
* -----------------------------------
* | unused | | nparams | | type |
* -----------------------------------
*/
# define EORULE 00 /* End of (sub)rule */
# define ACTION 01 /* Imbedded action */
# define NONTERM 02 /* A nonterminal */
# define TERMINAL 03 /* A terminal */
# define TERM 04 /* Something between square brackets */
# define ALTERNATION 05 /* Alternation (|) */
# define LITERAL 06 /* Also a terminal */
/*
* Access macros for the x-field of a grammar element
*/
# define g_gettype(p) ((p)->x&07)
# define g_getcont(p) ((p)->g_i.g_index)
# define g_getterm(p) ((p)->g_i.g_term)
# define g_getlink(p) ((p)->g_i.g_link)
# define g_getnpar(p) (((p)->x>>3)&017)
# define g_settype(p,s) { assert(((unsigned)(s))<=07);(p)->x=((p)->x&~07)|(s);}
# define g_setcont(p,s) ((p)->g_i.g_index=(s))
# define g_setterm(p,s) ((p)->g_i.g_term = (s))
# define g_setlink(p,s) ((p)->g_i.g_link = (s))
# define g_setnpar(p,s) { assert(((unsigned)(s))<=017);(p)->x=((p)->x&~0170)|((s)<<3);}
#ifdef NON_CORRECTING
# define g_getsubparse(p) ((p)->g_i.g_subparse)
# define g_setsubparse(p,s) ((p)->g_i.g_subparse = (s))
#endif
/*
* Some constants to communicate with the symbol table search routine
*/
# define UNKNOWN 00 /* Not equal to NONTERM, TERMINAL or LITERAL */
/*
* Some constants for safety
*/
# define SAFE 0 /* Indicates that a scan is done, and that the
* token is correct
*/
# define SAFESCANDONE 1 /* Indicates that a scan is done, and that the
* token will not be skipped
*/
# define SCANDONE 2 /* Indicates that a scan is done */
# define NOSCANDONE 3 /* Indicates that no scan is done */
# define NOSAFETY 4 /* Safety not yet computed */
/*
* nonterminal structure
*/
typedef struct {
int n_flags; /* low order four bits are reserved
* the parameter count
*/
# define getntparams(p) ((p)->n_flags&017)
# define setntparams(p,i) {assert(((unsigned)(i))<=017);(p)->n_flags&=~017;(p)->n_flags|=(i);}
# define GENSTATIC 01000 /* set if routine can be made static */
# define RECURSIVE 02000 /* Set if the default rule is recursive */
# define PARAMS 04000 /* tells if a nonterminal has parameters */
# define EMPTY 010000 /* tells if a nonterminal produces empty */
# define LOCALS 020000 /* local declarations ? */
# define REACHABLE 040000 /* can this nonterminal be reached ? */
# define VERBOSE 0100000 /* Set if in LL.output file */
char n_insafety;
char n_outsafety;
# define getntsafe(p) ((p)->n_insafety)
# define setntsafe(p,i) {assert(((unsigned)(i))<=NOSAFETY);(p)->n_insafety=(i);}
# define getntout(p) ((p)->n_outsafety)
# define setntout(p,i) {assert(((unsigned)(i))<=NOSAFETY);(p)->n_outsafety=(i);}
int n_count; /* pieces of code before this rule */
int n_lineno; /* declared on line ... */
p_gram n_rule; /* pointer to right hand side of rule */
union {
p_set n_f; /* ptr to "first" set */
string n_s; /* If this nonterminal is not declared,
* This field indicates the filename in
* which it occurred
*/
} n_x;
# define n_first n_x.n_f
# define n_string n_x.n_s
#ifdef NON_CORRECTING
p_set n_nc_first; /* Pointer to non-corr first set */
p_set n_nc_follow; /* Pointer to non-corr follow set */
#endif
p_set n_follow; /* pointer to the "follow" set */
p_set n_contains; /* pointer to symbols that can be produced */
string n_name; /* name of nonterminal */
int n_next; /* index of next nonterminal */
long n_off; /* index of parameters in action file */
} t_nont, *p_nont;
/*
* hash table structure
*/
typedef struct h_entry {
string h_name; /* pointer to name */
t_gram h_type; /* Type and index */
struct h_entry *h_next; /* next in hash chain */
} t_entry, *p_entry;
/*
* link structure to link alternations
*/
typedef struct link {
unsigned int l_flag;
# define COND 01 /* Set if this alternative has a %if */
# define DEF 02 /* This alternative is default */
# define PREFERING 010 /* %prefer */
# define AVOIDING 020 /* %avoid */
# define NOCONF 01000 /* Set if there is a resolver without
* conflict
*/
p_gram l_rule; /* pointer to this rule */
p_set l_symbs; /* set, when to take this rule */
#ifdef NON_CORRECTING
p_set l_nc_symbs;
#endif
p_set l_others; /* set, when to take another rule */
} t_link, *p_link;
/*
* Structure for a repitition specification
*/
typedef int t_reps,*p_reps;
# define FIXED 00 /* a fixed number */
# define STAR 01 /* 0 or more times */
# define PLUS 02 /* 1 or more times */
# define OPT 03 /* 0 or 1 times */
/*
* Access macros for repitition in term
*/
# define r_getkind(q) ((q)->t_repeats&03)
# define r_getnum(q) (((q)->t_repeats>>2)&037777)
# define r_setkind(q,s) { assert(((unsigned)(s))<=03);(q)->t_repeats=((q)->t_repeats&0177774)|(s);}
# define r_setnum(q,s) { assert(((unsigned)(s))<=037777);(q)->t_repeats=((q)->t_repeats&03)|((s)<<2);}
/*
* header structure for a term
*/
typedef struct term {
t_reps t_repeats;
int t_flags; /* Low order three bits for safety */
# define gettout(q) ((q)->t_flags&07)
# define settout(q,i) {assert(((unsigned)(i))<=NOSAFETY);(q)->t_flags&=~07;(q)->t_flags|=i;}
# define PERSISTENT 010 /* Set if this term has %persistent */
# define RESOLVER 020 /* Set if this term has %while */
# define EMPTYFIRST 0100 /* Error, empty first */
# define EMPTYTERM 0200 /* Error, term can produce empty */
/* # define NOCONF 01000 see link structure */
p_gram t_rule; /* pointer to this term */
p_set t_follow; /* set of followers */
p_set t_first; /* set of firsts */
#ifdef NON_CORRECTING
p_set t_nc_first; /* set of non corr firsts */
p_set t_nc_follow; /* set of non corr followers */
#endif
p_set t_contains; /* contains set */
} t_term, *p_term;
/*
* structure for firstmacros list
*/
typedef struct ff_firsts {
string ff_name; /* Name of the macro */
int ff_nont; /* for this nonterminal */
struct ff_firsts *ff_next;
} t_first, *p_first;
/*
* structure for start symbol list
*/
typedef t_first t_start;
typedef p_first p_start;
/*
* structure for file names and info
*/
typedef struct f_file {
string f_name; /* File name */
p_first f_firsts; /* ptr to list of firstmacros that must be
* generated in the target file for this
* grammar file
*/
int f_nonterminals; /* list of nonterminals in this file */
int f_terminals; /* list of terminals in this file */
p_set f_used; /* set of nonterminals used in this file */
} t_file, *p_file;
typedef struct info_alloc {
/*
* Structure used for dynamically growing arrays
*/
unsigned i_size; /* Size of the array */
unsigned i_esize; /* Size of an element */
unsigned i_incr; /* When filled, add room for i_incr elements */
p_mem i_ptr; /* ptr to base of array */
p_mem i_max; /* ptr to first free */
p_mem i_top; /* ptr to top of array */
} t_info, *p_info;
# ifdef NDEBUG
# define STATIC static
# else /* not NDEBUG */
# define STATIC extern
# endif /* not NDEBUG */

690
util/ack/pc/em_pc.c Normal file
View File

@@ -0,0 +1,690 @@
/*
* (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
*
*/
/*
* put all the pieces of the pascal part of the EM project together
* original author: Johan Stevenson, Vrije Universiteit, Amsterdam
* heavily modified by: Ed Keizer, Vrije Universiteit, Amsterdam
*/
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/dir.h>
#include <em_path.h>
#include <pc_size.h>
#include <local.h>
#define MAX_FLAG 40 /* The Max. no of '{' flags allowed */
#define void int
char def_pc_path[200] ;
char def_err_path[200] ;
char *pc_path = def_pc_path ;
char *err_path = def_err_path ;
int toterr;
int parent;
char *eeflag;
char *vvflag = "-V";
int no_pemflag = 0 ;
char *pemflag[MAX_FLAG];
char *eflag;
char *wflag;
int sizes[sz_last+1] = {
2, /* sz_addr */
8, /* sz_real */
0, /* sz_head */
512, /* sz_buff */
4096, /* sz_mset */
2, /* sz_iset */
};
#define CALLSIZE 60
char *callvector[CALLSIZE];
char **av;
int ac;
int fileargs; /* number of recognized, processed args */
int flagargs;
char *progname;
char *source;
#define CHARSIZE 2500
#define CHARMARG 50
char charbuf[CHARSIZE];
char *charp = charbuf;
char *tmp_dir = TMP_DIR;
char *unique = "pcXXXXXX";
char sigs[] = {
SIGHUP,
SIGINT,
SIGTERM,
0
};
/*
* forward function declarations
*/
void finish();
void pem();
int list();
char *flag();
char *tempfile();
char **initvector();
char *basename();
/*
* used library routines and data
*/
extern char *sys_errlist[];
extern int errno;
int atoi();
void exit();
void sleep();
void execv();
char *sbrk();
int chdir();
int fork();
int wait();
int getpid();
int open();
int close();
int read();
main(argc,argv) char **argv; {
register char *p;
char *files[3] ;
for (p = sigs; *p; p++)
if (signal(*p,finish) == SIG_IGN)
signal(*p,SIG_IGN);
ac = argc;
av = argv;
progname = *av++;
init();
while ( --ac>0 ) {
p = *av++;
if (*p == '-') {
flagargs++;
p = flag(p);
} else {
if ( fileargs>=3 ) fatal("Too many file arguments") ;
files[fileargs++]= p;
}
}
if ( fileargs!=3 ) fatal("Not enough arguments") ;
source=files[2] ;
pem(files[0],files[1]) ;
finish();
}
char *flag(f) char *f; {
register char *p;
p = f+1;
switch (*p++) {
case 'e':
eflag = f;
break;
case 'E':
eeflag = f;
break;
case 'w':
wflag = f;
break;
case 'V':
vvflag = f;
return(0);
case '{':
if ( no_pemflag>=MAX_FLAG ) {
ermess("too many flags, ignored %s",f) ;
} else {
pemflag[no_pemflag++] = p;
}
return(0);
case 'R':
pc_path= p ;
return 0 ;
case 'r' :
err_path= p ;
return 0 ;
default:
return(f);
}
if (*p)
fatal("bad flag %s",f);
return(0);
}
initsizes(f) FILE *f; {
register c, i;
register char *p;
p = vvflag + 2;
while (c = *p++) {
i = atoi(p);
while (*p >= '0' && *p <= '9')
p++;
switch (c) {
case 'p': sz_addr = i; continue;
case 'f': sz_real = i; continue;
case 'h': sz_head = i; continue;
case 'b': sz_buff = i; continue;
case 'm': sz_mset = i; continue;
case 'j': sz_iset = i; continue;
case 'w':
case 'i': if (i == 2) continue; break;
case 'l': if (i == 4) continue; break;
}
fatal("bad V-flag %s",vvflag);
}
if (sz_head == 0)
sz_head = 6*sz_word + 2*sz_addr;
for (i = 0; i <= sz_last; i++)
fprintf(f, "%d\n",sizes[i]);
}
/* ------------------ calling sequences -------------------- */
pem(p,q) char *p,*q; {
register char **v,*d;
int i;
FILE *erfil;
v = initvector(pc_path);
d = tempfile('d');
if ((erfil = fopen(d,"w")) == NULL)
syserr(d);
initsizes(erfil);
fprintf(erfil,"%s\n",basename(source));
for ( i=0 ; i<no_pemflag ; i++ ) fprintf(erfil,"%s\n",pemflag[i]);
fclose(erfil);
*v++ = q;
*v++ = d;
call(v,p,(char *)0);
if (toterr == 0)
if (list(p,d) < 0)
toterr++;
donewith(d);
}
/* ------------------- miscellaneous routines --------------- */
char *basename(p) char *p; {
register char *q;
q = p;
while (*q)
if (*q++ == '/')
p = q;
return(p);
}
char *tempfile(suf) {
register char *p,*q;
register i;
p = charp; q = tmp_dir;
while (*p = *q++)
p++;
*p++ = '/';
q = unique;
while (*p = *q++)
p++;
i = fileargs;
do
*p++ = i % 10 + '0';
while (i /= 10);
*p++ = '.'; *p++ = suf; *p++ = '\0';
q = charp; charp = p;
return(q);
}
call(v,in,out) char **v,*in,*out; {
register pid;
int status;
while ((parent = fork()) < 0)
sleep(1);
if (parent == 0) {
if (in) {
close(0);
if (open(in,0) != 0)
syserr(in);
}
if (out) {
close(1);
if (creat(out,0666) != 1)
syserr(out);
}
*v = 0;
execv(callvector[0],callvector+1);
syserr(callvector[0]);
}
while ((pid = wait(&status)) != parent) {
if (pid == -1)
fatal("process %d disappeared",parent);
fatal("unknown child %d died",pid);
}
if ((status & 0177) > 3) {
/*
if ((status & 0200) && tflag==0)
unlink("core");
*/
fatal("signal %d in %s. Ask an expert for help",
status&0177,callvector[0]);
}
if (status & 0177400)
toterr++;
}
char **initvector(path) char *path; {
register char *p,**v;
v = callvector;
p = path;
*v++ = p;
*v++ = basename(p);
return(v);
}
finish() {
register char *p,*q;
register fd;
struct direct dir;
signal(SIGINT,SIG_IGN);
if (parent != 0) {
chdir(tmp_dir);
fd = open(".",0);
while (read(fd,(char *) &dir,sizeof dir) == sizeof dir) {
if (dir.d_ino == 0)
continue;
p = unique;
q = dir.d_name;
while (*p++ == *q++)
if (*p == '\0') {
unlink(dir.d_name);
break;
}
}
close(fd);
}
exit(toterr ? -1 : 0);
}
donewith(p) char *p; {
if (p >= charbuf && p < &charbuf[CHARSIZE])
unlink(p);
}
init() {
register char *p,*s ;
register i,fd;
if ((fd = open(tmp_dir,0)) < 0)
tmp_dir = ".";
close(fd);
p= def_pc_path ;
s= EM_DIR ; while ( *p++ = *s++ ) ; *p='/' ;
s= PEM_PATH ; while ( *p++ = *s++ ) ;
p= def_err_path ;
s= EM_DIR ; while ( *p++ = *s++ ) ; *p='/' ;
s= ERR_PATH ; while ( *p++ = *s++ ) ;
p = unique+2;
parent = i = getpid();
do
*p++ = i % 10 + '0';
while (i /= 10);
*p++ = '.'; *p = '\0';
}
/* ------------------- pascal listing ----------------------- */
#define MAXERNO 300
#define MAXERRLIST 10
#define IDMAX 8
struct errec {
int erno;
char mess[IDMAX+1];
int mesi;
int chno;
int lino;
};
struct errec curr;
struct errec next;
int *index = 0;
int maxerno;
int errerr;
int errfat;
int listlino;
int listorig;
int listrela;
char *listfnam;
FILE *inpfil;
FILE *mesfil;
FILE *errfil;
int errorline();
int geterrec();
int nexterror();
int list(p,q) char *p,*q; {
if ((errfil = fopen(q,"r")) == NULL)
syserr(q);
if (geterrec() == 0)
if (eeflag==0) {
fclose(errfil);
return(0);
}
if (index == 0) {
index = (int *) sbrk(MAXERNO * sizeof index[0]);
fillindex();
}
if ((inpfil = fopen(p,"r")) == NULL)
syserr(p);
errerr = 0;
errfat = 0;
listlino = 0;
listorig = 0;
listrela = 0;
listfnam = source;
if (eeflag)
listfull();
else if (eflag)
listpartial();
else
listshort();
fclose(errfil);
fclose(inpfil);
fflush(stdout);
return(errfat ? -1 : 1);
}
listshort() {
while (nexterror()) {
while (listlino < curr.lino)
nextline(0);
printf("%s, line %d: ",listfnam,listrela);
string(&curr);
}
}
listfull() {
if (nexterror())
do {
do {
nextline(1);
} while (listlino < curr.lino);
} while (errorline());
while (nextline(1))
;
}
listpartial() {
if (nexterror())
do {
do {
nextline(listlino >= curr.lino-2);
} while (listlino < curr.lino);
} while (errorline());
}
int nextline(printing) {
register ch;
listlino++;
ch = getc(inpfil);
if (ch == '#') {
if (lineline(printing) == 0)
fatal("bad line directive");
return(1);
}
listrela++;
if (listfnam == source)
listorig++;
if (ch != EOF) {
if (printing)
printf("%5d\t",listorig);
do {
if (printing)
putchar(ch);
if (ch == '\n')
return(1);
} while ((ch = getc(inpfil)) != EOF);
}
return(0);
}
lineline(printing) {
register ch;
register char *p,*q;
static char line[100];
p = line;
while ((ch = getc(inpfil)) != '\n') {
if (ch == EOF || p == &line[100-1])
return(0);
*p++ = ch;
}
*p = '\0'; p = line;
if (printing)
printf("\t#%s\n",p);
if ((listrela = atoi(p)-1) < 0)
return(0);
while ((ch = *p++) != '"')
if (ch == '\0')
return(0);
q = p;
while (ch = *p++) {
if (ch == '"') {
*--p = '\0';
if ( source ) {
listfnam = strcmp(q,source)==0 ? source : q;
return(1);
}
source=q ; listfnam=q ;
return 1 ;
}
if (ch == '/')
q = p;
}
return(0);
}
int errorline() {
register c;
register struct errec *p,*q;
struct errec lerr[MAXERRLIST];
int goon;
printf("*** ***");
p = lerr;
c = 0;
do {
if (c < curr.chno) {
printf("%*c",curr.chno-c,'^');
c = curr.chno;
}
if (p < &lerr[MAXERRLIST])
*p++ = curr;
goon = nexterror();
} while (goon && curr.lino==listlino);
putchar('\n');
for (q = lerr; q < p; q++)
string(q);
putchar('\n');
return(goon);
}
int geterrec() {
register ch;
register char *p;
ch = getc(errfil);
next.erno = 0;
next.mesi = -1;
next.mess[0] = '\0';
if (ch == EOF)
return(0);
if (ch >= '0' && ch <= '9') {
ch = getnum(ch,&next.mesi);
} else if (ch == '\'') {
p = next.mess;
while ((ch = getc(errfil)) != ' ' && ch != EOF)
if (p < &next.mess[IDMAX])
*p++ = ch;
*p = '\0';
}
ch = getnum(ch, &next.erno);
ch = getnum(ch, &next.lino);
ch = getnum(ch, &next.chno);
if (ch != '\n')
fatal("bad error line");
return(1);
}
int getnum(ch, ip) register ch; register *ip; {
register neg;
*ip = 0;
while (ch == ' ')
ch = getc(errfil);
if (neg = ch=='-')
ch = getc(errfil);
while (ch >= '0' && ch <= '9') {
*ip = *ip * 10 - '0' + ch;
ch = getc(errfil);
}
if (neg)
*ip = -(*ip);
return(ch);
}
int nexterror() {
do { /* skip warnings if wflag */
curr = next;
if (curr.erno == 0)
return(0);
for (;;) {
if (geterrec() == 0)
break;
if (next.lino != curr.lino || next.chno != curr.chno)
break;
if (curr.erno < 0 && next.erno > 0)
/* promote warnings if they cause fatals */
curr.erno = -curr.erno;
if (next.mess[0] != '\0' || next.mesi != -1)
/* give all parameterized errors */
break;
if (curr.mess[0] != '\0' || curr.mesi != -1)
/* and at least a non-parameterized one */
break;
}
} while (curr.erno < 0 && wflag != 0);
return(1);
}
fillindex() {
register *ip,n,c;
if ((mesfil = fopen(err_path,"r")) == NULL)
syserr(err_path);
ip = index;
*ip++ = 0;
n = 0;
while ((c = getc(mesfil)) != EOF) {
n++;
if (c == '\n') {
*ip++ = n;
if (ip > &index[MAXERNO])
fatal("too many errors on %s",err_path);
}
}
maxerno = ip - index;
}
string(ep) register struct errec *ep; {
register i,n;
errerr++;
if ((i = ep->erno) < 0) {
i = -i;
printf("Warning: ");
} else
errfat++;
if (i == 0 || i >= maxerno)
fatal("bad error number %d",i);
n = index[i] - index[i-1];
fseek(mesfil,(long)index[i-1],0);
while (--n >= 0) {
i = getc(mesfil);
if (i == '%' && --n>=0) {
i = getc(mesfil);
if (i == 'i')
printf("%d", ep->mesi);
else if (i == 's')
printf("%s", ep->mess);
else
putchar(i);
} else
putchar(i);
}
}
/* ------------------- error routines -------------------------- */
/* VARARGS1 */
void ermess(s,a1,a2,a3,a4) char *s; {
fprintf(stderr,"%s: ",progname);
fprintf(stderr,s,a1,a2,a3,a4);
fprintf(stderr,"\n");
}
syserr(s) char *s; {
fatal("%s: %s",s,sys_errlist[errno]);
}
/* VARARGS1 */
void fatal(s,a1,a2,a3,a4) char *s; {
ermess(s,a1,a2,a3,a4);
toterr++;
finish();
}