Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd651d83be | ||
|
|
312f3d1835 |
@@ -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.
|
||||
@@ -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$ */
|
||||
@@ -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."
|
||||
144
util/LLgen/c.pm
144
util/LLgen/c.pm
@@ -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"},
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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 */
|
||||
@@ -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
@@ -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];
|
||||
}
|
||||
}
|
||||
@@ -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?"
|
||||
BIN
util/LLgen/pm
BIN
util/LLgen/pm
Binary file not shown.
@@ -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 -)"
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 */
|
||||
};
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
*/
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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 = <ext[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
|
||||
}
|
||||
}
|
||||
@@ -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 */
|
||||
339
util/cmisc/tabgen.c
Normal file
339
util/cmisc/tabgen.c
Normal file
@@ -0,0 +1,339 @@
|
||||
/*
|
||||
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
||||
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
||||
*/
|
||||
/*
|
||||
chtabgen - character table generator
|
||||
|
||||
Author: Erik Baalbergen (..tjalk!erikb)
|
||||
Many mods by Ceriel Jacobs
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef NORCSID
|
||||
static char *RcsId = "$Id$";
|
||||
#endif
|
||||
|
||||
#define MAXBUF 256
|
||||
#define MAXTAB 10000
|
||||
#define COMCOM '-'
|
||||
#define FILECOM '%'
|
||||
|
||||
int InputForm = 'c'; /* default input format (and, currently, only one) */
|
||||
char OutputForm[MAXBUF] = "%s,\n";
|
||||
/* format for spitting out a string */
|
||||
char *Table[MAXTAB];
|
||||
char *ProgCall; /* callname of this program */
|
||||
int TabSize = 128; /* default size of generated table */
|
||||
char *InitialValue; /* initial value of all table entries */
|
||||
|
||||
extern char *malloc(), *strcpy();
|
||||
|
||||
main(argc, argv)
|
||||
char *argv[];
|
||||
{
|
||||
|
||||
ProgCall = *argv++;
|
||||
argc--;
|
||||
while (argc-- > 0) {
|
||||
if (**argv == COMCOM) {
|
||||
option(*argv++);
|
||||
}
|
||||
else {
|
||||
if (! process(*argv++, InputForm)) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
char *
|
||||
Salloc(s)
|
||||
char *s;
|
||||
{
|
||||
char *ns = malloc((unsigned)strlen(s) + 1);
|
||||
|
||||
if (ns) {
|
||||
strcpy(ns, s);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "%s: out of memory\n", ProgCall);
|
||||
exit(1);
|
||||
}
|
||||
return ns;
|
||||
}
|
||||
|
||||
option(str)
|
||||
char *str;
|
||||
{
|
||||
/* note that *str indicates the source of the option:
|
||||
either COMCOM (from command line) or FILECOM (from a file).
|
||||
*/
|
||||
switch (*++str) {
|
||||
|
||||
case ' ': /* command */
|
||||
case '\t':
|
||||
case '\0':
|
||||
break;
|
||||
case 'I': /* for future extension */
|
||||
InputForm = *++str;
|
||||
break;
|
||||
case 'f': /* input from file ... */
|
||||
if (*++str == '\0') {
|
||||
fprintf(stderr, "%s: -f: name expected\n", ProgCall);
|
||||
exit(1);
|
||||
}
|
||||
DoFile(str);
|
||||
break;
|
||||
case 'F': /* new output format string */
|
||||
sprintf(OutputForm, "%s\n", ++str);
|
||||
break;
|
||||
case 'T': /* insert text literally */
|
||||
printf("%s\n", ++str);
|
||||
break;
|
||||
case 'p': /* print table */
|
||||
PrintTable();
|
||||
break;
|
||||
case 'C': /* clear table */
|
||||
InitTable((char *)0);
|
||||
break;
|
||||
case 'i': /* initialize table with given value */
|
||||
if (*++str == '\0') {
|
||||
InitTable((char *)0);
|
||||
}
|
||||
else InitTable(str);
|
||||
break;
|
||||
case 'S':
|
||||
{
|
||||
int i = atoi(++str);
|
||||
|
||||
if (i <= 0 || i > MAXTAB) {
|
||||
fprintf(stderr, "%s: size would exceed maximum\n",
|
||||
ProgCall);
|
||||
}
|
||||
else {
|
||||
TabSize = i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fprintf(stderr, "%s: bad option -%s\n", ProgCall, str);
|
||||
}
|
||||
}
|
||||
|
||||
InitTable(ival)
|
||||
char *ival;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < TabSize; i++) {
|
||||
Table[i] = 0;
|
||||
}
|
||||
InitialValue = 0;
|
||||
if (ival) {
|
||||
InitialValue = Salloc(ival);
|
||||
}
|
||||
}
|
||||
|
||||
PrintTable()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < TabSize; i++) {
|
||||
if (Table[i]) {
|
||||
printf(OutputForm, Table[i]);
|
||||
}
|
||||
else if (InitialValue) {
|
||||
printf(OutputForm, InitialValue);
|
||||
}
|
||||
else {
|
||||
printf(OutputForm, "0");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
process(str, format)
|
||||
char *str;
|
||||
{
|
||||
char *cstr = str;
|
||||
char *Name = cstr; /* overwrite original string! */
|
||||
|
||||
/* strip of the entry name
|
||||
*/
|
||||
while (*str && *str != ':') {
|
||||
if (*str == '\\') {
|
||||
++str;
|
||||
}
|
||||
*cstr++ = *str++;
|
||||
}
|
||||
|
||||
if (*str != ':') {
|
||||
fprintf(stderr, "%s: bad specification: \"%s\", ignored\n",
|
||||
ProgCall, Name);
|
||||
return 0;
|
||||
}
|
||||
*cstr = '\0';
|
||||
str++;
|
||||
|
||||
switch (format) {
|
||||
|
||||
case 'c':
|
||||
return c_proc(str, Name);
|
||||
default:
|
||||
fprintf(stderr, "%s: bad input format\n", ProgCall);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
c_proc(str, Name)
|
||||
char *str;
|
||||
char *Name;
|
||||
{
|
||||
int ch, ch2;
|
||||
int quoted();
|
||||
char *name = Salloc(Name);
|
||||
|
||||
while (*str) {
|
||||
if (*str == '\\') {
|
||||
ch = quoted(&str);
|
||||
}
|
||||
else {
|
||||
ch = *str++ & 0377;
|
||||
}
|
||||
if (*str == '-') {
|
||||
if (*++str == '\\') {
|
||||
ch2 = quoted(&str);
|
||||
}
|
||||
else {
|
||||
if (ch2 = (*str++ & 0377));
|
||||
else str--;
|
||||
}
|
||||
if (ch > ch2) {
|
||||
fprintf(stderr, "%s: bad range\n", ProgCall);
|
||||
return 0;
|
||||
}
|
||||
while (ch <= ch2) {
|
||||
if (! setval(ch, name)) return 0;
|
||||
ch++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (! setval(ch, name)) return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
setval(ch, nm)
|
||||
char *nm;
|
||||
{
|
||||
char **p = &Table[ch];
|
||||
|
||||
if (ch < 0 || ch >= TabSize) {
|
||||
fprintf(stderr, "Illegal index: %d\n", ch);
|
||||
return 0;
|
||||
}
|
||||
if (*(p = &Table[ch])) {
|
||||
fprintf(stderr, "Warning: redefinition of index %d\n", ch);
|
||||
}
|
||||
*p = nm;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
quoted(pstr)
|
||||
char **pstr;
|
||||
{
|
||||
int ch;
|
||||
int i;
|
||||
char *str = *pstr;
|
||||
|
||||
if ((*++str >= '0') && (*str <= '9')) {
|
||||
ch = 0;
|
||||
for (i = 0; i < 3; i++) {
|
||||
ch = 8 * ch + (*str - '0');
|
||||
if (*++str < '0' || *str > '9')
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (*str++) {
|
||||
case 'n':
|
||||
ch = '\n';
|
||||
break;
|
||||
case 't':
|
||||
ch = '\t';
|
||||
break;
|
||||
case 'b':
|
||||
ch = '\b';
|
||||
break;
|
||||
case 'r':
|
||||
ch = '\r';
|
||||
break;
|
||||
case 'f':
|
||||
ch = '\f';
|
||||
break;
|
||||
case 'v':
|
||||
ch = 013;
|
||||
break;
|
||||
default :
|
||||
ch = *(str - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
*pstr = str;
|
||||
return ch & 0377;
|
||||
}
|
||||
|
||||
char *
|
||||
getline(s, n, fp)
|
||||
char *s;
|
||||
FILE *fp;
|
||||
{
|
||||
int c = getc(fp);
|
||||
char *str = s;
|
||||
|
||||
while (n--) {
|
||||
if (c == EOF) {
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
if (c == '\n') {
|
||||
*str++ = '\0';
|
||||
return s;
|
||||
}
|
||||
*str++ = c;
|
||||
c = getc(fp);
|
||||
}
|
||||
s[n - 1] = '\0';
|
||||
return s;
|
||||
}
|
||||
|
||||
#define BUFSIZE 1024
|
||||
|
||||
DoFile(name)
|
||||
char *name;
|
||||
{
|
||||
char text[BUFSIZE];
|
||||
FILE *fp;
|
||||
|
||||
if ((fp = fopen(name, "r")) == NULL) {
|
||||
fprintf(stderr, "%s: cannot read file %s\n", ProgCall, name);
|
||||
exit(1);
|
||||
}
|
||||
while (getline(text, BUFSIZE, fp) != NULL) {
|
||||
if (text[0] == FILECOM) {
|
||||
option(text);
|
||||
}
|
||||
else {
|
||||
if (! process(text, InputForm)) {
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user