164 Commits

Author SHA1 Message Date
cvs2hg
5cb054f106 fixup commit for tag 'llgen-1-0' 2006-02-04 00:57:05 +00:00
dtrg
e864bf235e Split LLgen off to be self-contained, and not necessarily part of the ACK. Replaced its build system with one based on pm. Rewrote the README. Updated the license text to match the overriding license common to all the ACK. 2006-02-04 00:57:04 +00:00
dtrg
953a565a10 Moved LLgen documentation from the main ACK documentation directory into LLgen's own documentation directory. 2006-02-04 00:43:32 +00:00
dtrg
dd57d79b1b Modernised usage of system header files. 2006-02-04 00:37:19 +00:00
dtrg
71a92846dd Modernised usage of system header files. 2006-02-03 22:23:37 +00:00
dtrg
c39e85da63 Modernised usage of system header files. Changed the patch buffer (which allowed the library path to be modified with a hex editor) to an environment variable instead. 2006-02-03 22:23:11 +00:00
dtrg
4c0b3bb40f Modernised usage of system header files. 2006-01-24 22:29:19 +00:00
dtrg
4fdd9b83fc Converted to use termios, not sgtty. (pbetti@e-tech.net) 2005-08-10 22:48:40 +00:00
cjhjacobs
26889d3762 Fix: did not deal with quotes in macro definitions properly 2005-06-30 16:54:15 +00:00
dtrg
e0846f63be Removed duplicate and inconsistent function declarations. 2005-06-25 15:52:19 +00:00
dtrg
35bd1df1aa Now includes stdlib.h to avoid implicit call declarations. 2005-06-25 15:50:40 +00:00
dtrg
4ed4d8423f Added some prototyping to stop a compile error with gcc 4. 2005-06-25 13:49:06 +00:00
cvs2hg
cf1a80ecb6 fixup commit for tag 'release-5-6' 2005-06-24 23:20:42 +00:00
dtrg
e8b47b4745 Added some new readmes at the top level. 2005-06-24 23:20:41 +00:00
dtrg
5c8a5ed523 Added LLgen_NCER.n to the distribution because the makefile seems to want it. 2005-06-24 23:19:55 +00:00
dtrg
754267f0bd Added new mkdist tool. 2005-06-24 23:19:24 +00:00
dtrg
adb3cc5523 Created new tool to generate distributions. 2005-06-24 22:13:57 +00:00
dtrg
dd400ca720 Removed a call to _cleanup(), which appears to be a Minixism (and should be unnecessary). 2005-06-24 22:12:02 +00:00
dtrg
f2046954e6 Cleaned up the struct sgtty workaround and made it more generic. 2005-06-24 22:11:27 +00:00
dtrg
779fe568fc Removed an assumption that 'stdin' is a constant, which it's not on Linux. (You can't use it as an initialiser when declaring a global variable.) 2005-06-24 22:10:24 +00:00
dtrg
9bc8c07deb Replaced references to /usr/tmp with references to /tmp. 2005-06-24 22:08:47 +00:00
dtrg
70ef6fe52e Applied interim patches to make the interpreter compile on Linux. (Linux doesn't support struct sgtty; all this code should probably be rewritten to use termios instead, if I've understood it correctly.) 2005-06-24 21:42:11 +00:00
dtrg
9bd955e4f6 Removed Versions, since that file doesn't actually exist. 2005-06-24 21:14:44 +00:00
ceriel
a56d81ea51 new copyright notice in repository 2005-05-26 06:47:43 +00:00
ceriel
b1632b8060 Fix 2003-01-08 09:39:52 +00:00
ceriel
8f69a0ca44 Fix 2002-09-11 13:32:57 +00:00
ceriel
e8fdf4fcda fix 2002-09-11 13:19:23 +00:00
ceriel
1e32788ad1 Added missing files to .distr 2002-09-11 13:17:00 +00:00
ceriel
053ba2d164 ... 2002-09-10 13:40:14 +00:00
ceriel
daa34d0fe6 minor mods 2002-09-10 13:30:06 +00:00
ceriel
ee2c7069e4 Prevent double fclose 2002-08-26 14:27:15 +00:00
ceriel
4556d261d8 ??? 2002-04-04 12:33:15 +00:00
ceriel
df46c5e165 Fix for union initializers 2001-07-03 10:10:56 +00:00
ceriel
910316cfde Fix: parameter name same as function name not dealt with properly 2001-07-03 08:55:16 +00:00
ceriel
55dbc99000 Updated copyright 1999-04-23 14:15:43 +00:00
ceriel
6ca98e7102 Adapted copyright notice 1999-03-18 15:34:27 +00:00
ceriel
f0a7a313fc Fix: did not always produce error message 1998-11-10 14:26:06 +00:00
ceriel
384c4bc698 Fixed bug with 4-byte sets on 2-byte machines 1998-09-03 12:51:38 +00:00
ceriel
91cb060d10 Replaced a couple of UnGetChar calls with ChPushBack calls. The
UnGetChar call is wrong after skipspaces().
1998-02-09 09:49:00 +00:00
ceriel
d6e0e461f7 Corrected Makefile 1997-09-04 15:49:46 +00:00
ceriel
1840829928 Added LLgen_NCER.n 1997-07-10 07:58:30 +00:00
ceriel
298f8c8b0f fixed typo 1997-07-10 07:58:19 +00:00
ceriel
495dce5d6c Added LLgen_NCER.n 1997-07-10 07:55:35 +00:00
ceriel
8a2a3fd74b Only list readable directories 1997-07-01 12:05:54 +00:00
ceriel
4ec7d8bf7f Bug fix: copied wrong size to destination in structure returns 1997-07-01 08:33:13 +00:00
ceriel
f8fd2aa273 Removed superfluous ; 1997-06-16 13:07:37 +00:00
ceriel
e38b178317 Many modifications, mostly in comment 1997-05-15 12:03:05 +00:00
ceriel
cebde164bb Prevent warning about unused labels 1997-04-02 10:42:06 +00:00
ceriel
6db931eee6 Link em_data.a as well (needed when producing readable EM 1997-04-01 13:58:58 +00:00
ceriel
2c66222509 Fixed bug: flt_div should not touch e1 1997-03-13 18:38:24 +00:00
ceriel
2382ef1a27 Additions for non-correcting error recovery 1997-02-21 17:22:42 +00:00
ceriel
99ac23b4b4 Additions for non-correcting error recovery 1997-02-21 17:11:04 +00:00
ceriel
8ea5d257c4 improved error reporting, added -DNON_CORRECTING 1997-02-21 15:44:44 +00:00
ceriel
664d3fc8d3 some minor fixes 1997-02-21 15:44:10 +00:00
ceriel
13fea7102b Updated 1997-02-21 12:23:04 +00:00
ceriel
c2607fdf0f Added non-correcting error recovery stuff 1997-02-21 11:27:57 +00:00
ceriel
a44875cf00 bug fix: code referred to token attribute of wrong token! 1997-02-17 15:14:55 +00:00
ceriel
ae0cde301d Bug fix: conversion is OK if arg = 0.0 1997-01-27 14:06:51 +00:00
ceriel
9f61a33c9f troff flag -Tlpr is now changed to -Tlp 1996-12-04 14:03:12 +00:00
ceriel
3b3ec3a2af Fixed typo in catchsig.s 1996-11-26 15:05:10 +00:00
ceriel
63e0b36b41 renamed _len to _length: conflict with name in minix lib 1996-11-26 15:02:36 +00:00
ceriel
56033dc0c1 Added -n flag 1996-11-21 10:14:26 +00:00
ceriel
ea09125e30 fixed a bug: STD/LDD was generated on odd-numbered reg 1996-11-19 13:28:41 +00:00
ceriel
a44bbb3977 Fixed a couple of minor bugs 1996-11-19 13:27:56 +00:00
ceriel
322c1c1b4c Some fixes 1996-11-19 09:12:36 +00:00
ceriel
d0587ef3ab Stupid confusion with fdtox and fxtod 1996-11-18 16:49:54 +00:00
ceriel
150db958da Fixed typo 1996-10-22 14:34:16 +00:00
ceriel
efacd02ffd Added LONGCARD as a local extension 1996-08-14 07:42:40 +00:00
ceriel
1592c3638c Moved TryToString call into ChkAssCompat 1996-06-06 07:47:00 +00:00
ceriel
7f7f5f187f Fix: compatibility check in RETURN statement 1996-06-06 07:37:02 +00:00
ceriel
740f1d5f75 fix in cmpxchg instruction; i486 book is wrong 1996-04-25 08:38:05 +00:00
ceriel
6ec3dd7ebd fix in flushbuf: make sure it does not return EOF when it actually succeeds 1996-04-24 13:06:00 +00:00
ceriel
73b54a2326 fixed bug with %[] in doscan.c 1996-04-01 09:08:59 +00:00
ceriel
3895a59e03 Fix to fix in idf.c 1996-02-19 12:19:47 +00:00
ceriel
67cb729554 Fixed bug: crashed when parameter has same name as function 1995-12-20 09:58:56 +00:00
ceriel
d0288b673b Some improvements 1995-12-19 09:30:48 +00:00
ceriel
7442852cad Removed unclear test 1995-12-18 11:02:18 +00:00
ceriel
4baa1312a8 removed 1995-12-06 14:15:11 +00:00
ceriel
cdb362b628 removed 1995-12-06 14:04:51 +00:00
ceriel
e5894e0f5a removed 1995-12-06 13:28:04 +00:00
ceriel
6576498776 removed MakeVersion 1995-12-06 13:26:54 +00:00
ceriel
d224889b8d removed Makefile 1995-12-06 13:26:03 +00:00
ceriel
a6ea80436b removed Makefile, added README 1995-12-06 13:25:23 +00:00
ceriel
0ea8200a57 added file 1995-12-06 13:23:09 +00:00
ceriel
4a5e3f42d3 removed 1995-12-06 13:21:54 +00:00
ceriel
2358a2f5e2 Added pascal compiler report 1995-12-06 13:17:50 +00:00
ceriel
6e2fe89c61 removed 1995-12-06 13:08:44 +00:00
ceriel
583130b79b deleted 1995-12-06 13:04:25 +00:00
ceriel
550095a5d0 Removed Version.c 1995-12-06 09:52:54 +00:00
ceriel
f7157ca24c Copied versions of dv[iu].s from ../../m68k2/libem. 1995-12-05 15:38:55 +00:00
ceriel
ddc1751296 A couple of minor changes 1995-12-05 13:51:43 +00:00
ceriel
0a643bb9d0 Improved the pow() function to give more exact results 1995-12-05 12:29:36 +00:00
ceriel
812b6f2158 Fixed obscure bug in setvbuf 1995-12-04 17:11:54 +00:00
ceriel
6d39052c12 Corrected nested function info 1995-12-04 16:42:11 +00:00
ceriel
d4abf57904 Fixed warnings, recognize -gdb 1995-12-04 15:29:42 +00:00
ceriel
a9df108116 Made to work; how did this get into the repository??? 1995-12-04 15:20:46 +00:00
ceriel
39011a99c5 Pass -gdb on to M2 compiler 1995-12-04 15:01:07 +00:00
ceriel
c97f79454d Fixed a bug with local character arrays initialized with a string 1995-11-15 09:42:25 +00:00
ceriel
2985469116 Fix: wrong offsets for locals when < -32768, installation error for 'show' 1995-11-08 11:09:14 +00:00
ceriel
c1738933d7 Fix: wrong offsets for locals when < -32768 1995-11-08 11:08:09 +00:00
ceriel
4565576021 Fixed bug with labels 1995-11-07 10:37:59 +00:00
ceriel
0bf45ac757 Get() parameter is optional 1995-11-01 16:54:17 +00:00
ceriel
a8b1f8e347 Header file was included twice 1995-11-01 15:59:33 +00:00
ceriel
29e457c381 Fix by Charles Lindsey 1995-09-25 08:09:55 +00:00
ceriel
71da2cdda9 Fixed some bugs with the setxx instructions 1995-09-12 12:09:08 +00:00
ceriel
8b3437dd24 Fix: setxx instructions should only accept byte registers 1995-09-12 12:08:42 +00:00
ceriel
b766e2beab Added libassert for when DEBUG is defined 1995-08-18 07:28:47 +00:00
ceriel
71913a9d1d A68 rules from Charles Lindsey 1995-08-18 07:27:57 +00:00
ceriel
3ad37ef26b lib --> lib.bin for a68 1995-08-18 07:26:46 +00:00
ceriel
b9a67e72ca use stdarg when compiling with ANSI C compiler 1995-08-18 07:26:18 +00:00
ceriel
1aa9149ff9 Changed for sparc_solarisdescr 1995-08-18 07:24:18 +00:00
ceriel
4c73887050 use stdarg when compiling with ANSI C compiler 1995-08-17 16:51:09 +00:00
ceriel
7b207deeb7 use stdarg when compiling with ANSI C compiler 1995-08-17 16:43:36 +00:00
ceriel
53eb117563 use stdarg when compiling with ANSI C compiler 1995-08-17 16:34:29 +00:00
ceriel
0dc2d5a625 use stdarg when compiling with ANSI C compiler 1995-08-17 16:14:45 +00:00
ceriel
b7396a7cd4 use stdarg when compiling with ANSI C compiler 1995-08-17 15:20:35 +00:00
ceriel
0509996f7f use stdarg when compiling with ANSI C compiler 1995-08-17 15:01:56 +00:00
ceriel
c3855160fb use stdarg when compiling with ANSI C compiler 1995-08-17 14:36:05 +00:00
ceriel
acdb874527 use stdarg when compiling with ANSI C compiler, and some other minor changes 1995-08-17 13:33:55 +00:00
ceriel
a96a9107c8 'ed -' is no longer supported on some systems. replaced by 'ed -s' 1995-08-17 12:22:33 +00:00
ceriel
e41c75c1bc Some minor changes 1995-08-17 10:03:43 +00:00
ceriel
32bcf11ab9 Re-ordered for incompatible Linux shell 1995-08-15 14:59:28 +00:00
ceriel
f8cbcf1b4f Don't use SIGEMT; it is not portable 1995-08-15 09:10:39 +00:00
ceriel
65cd309c08 'ed -' is no longer supported by some systems. Use 'ed -s' 1995-08-15 08:43:10 +00:00
ceriel
f8d6337862 'ed -' is no longer supported by some systems. Use 'ed -s' 1995-08-14 15:09:59 +00:00
ceriel
f34bf4b487 removed dependency on /usr/include/varargs.h 1995-08-14 15:08:46 +00:00
ceriel
7c086b1710 create modules/h too, for varargs.h 1995-08-14 15:07:53 +00:00
ceriel
c587ca287e 'ed -' is no longer supported by some systems. Use 'ed -s' 1995-08-14 08:08:56 +00:00
ceriel
525eb1f1a4 Fixed typo 1995-07-31 09:17:14 +00:00
ceriel
7b6d8fbe56 Added copyright notice 1995-07-31 09:10:42 +00:00
ceriel
bf6f4f8a6e Minor mod to Makefile 1995-07-27 07:14:54 +00:00
ceriel
5a6d5d877f declare errno in cerror.s 1995-07-26 08:55:56 +00:00
ceriel
2624e5d05c Use _end instead of $_end. $_end does not always indicate the right
position. This should be fixed as well, but how?
1995-07-26 08:52:03 +00:00
ceriel
ef30bb3398 Fix by Charles Lindsey: still used reg vars, despite ms_gto 1995-07-26 08:44:35 +00:00
ceriel
41d0c898e5 Fixed typo 1995-07-26 08:43:02 +00:00
ceriel
1bcd59df35 Some changes suggested by Charles Lindsey 1995-07-26 08:42:56 +00:00
ceriel
c9153e6b9b Set B_busy 1995-07-25 16:49:15 +00:00
ceriel
4978d19bff Several fixes from Charles Lindsey 1995-07-25 16:43:42 +00:00
ceriel
34b3d1fb52 Fix: produced jgt instead of jg 1995-07-25 13:21:53 +00:00
ceriel
5e03b1bebb Fixes: some conditionals were evaluated wrong due to the overflow bit 1995-07-21 12:05:26 +00:00
ceriel
3883860106 Added Posix names 1995-06-28 09:46:39 +00:00
ceriel
c833d93d2d Some fixes 1995-06-12 14:28:36 +00:00
ceriel
a0bd098f98 Fix: got into infinite loop 1995-05-02 12:23:28 +00:00
ceriel
15d2949b88 Fix: opaque types my only be defined in the CORRESPONDING implementation 1995-04-26 13:54:56 +00:00
ceriel
5edfb9eccf Fix: had a semicolon too much (KJB) 1995-04-18 13:56:20 +00:00
ceriel
fdc0e2efdb minor improvement 1995-03-29 11:57:27 +00:00
ceriel
34f7036b87 Reordered patterns 1995-03-28 11:22:34 +00:00
ceriel
06b0d3775f Added some patterns 1995-03-28 10:01:02 +00:00
ceriel
f069cba449 Made arith_sign more portable 1995-03-28 09:10:31 +00:00
ceriel
86cb2d66d7 Fixed: % and / were interchanged 1995-03-27 11:46:47 +00:00
ceriel
d801356f1e Fixed typo 1995-03-27 11:22:57 +00:00
ceriel
bcb4a75630 free WorkingDir only if including cpp 1995-03-24 13:56:20 +00:00
ceriel
e4fd4fce8e Fix: C_pt_ps and C_pt_op prototypes only valid when READABLE_EM is defined 1995-03-24 10:27:28 +00:00
ceriel
b71c0ca9a3 Added Amake.srclist 1995-03-21 09:39:29 +00:00
ceriel
32c692d93b Use TARGETHOME for manual page 1995-03-17 14:11:47 +00:00
ceriel
87d67255d9 Added filter for TARGETHOME, needed for man pages that include an include-file 1995-03-17 14:11:06 +00:00
ceriel
404d86d544 Added -F option to indicate name of floating point hook 1995-03-17 12:37:06 +00:00
ceriel
911b0a43d8 Fix: never replace LAR/SAR by AAR LOI/STI if descriptor is not in ROM 1995-03-17 12:32:47 +00:00
ceriel
d5505f2f02 Also create sparc_solarisdescr 1995-03-17 11:00:29 +00:00
ceriel
d1435f4fc6 Added an option to strip the grammar from its actions 1995-02-24 12:10:44 +00:00
ceriel
65353b1417 Fix: description of setxx should write arg 1995-02-24 11:53:43 +00:00
ceriel
0ae5288ab7 Fix for membership test with constant LHS 1994-12-20 16:00:57 +00:00
ceriel
68cebfb733 do not allow ',' as separator in parameter declarations; this results in bad C-code 1994-12-20 12:47:48 +00:00
ceriel
2b0a61d143 Added more precise info about parameters 1994-12-20 12:40:21 +00:00
35 changed files with 13272 additions and 339 deletions

32
util/LLgen/COPYING Normal file
View File

@@ -0,0 +1,32 @@
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.

84
util/LLgen/READ_ME Normal file
View File

@@ -0,0 +1,84 @@
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$ */

16
util/LLgen/bootstrap.sh Executable file
View File

@@ -0,0 +1,16 @@
#!/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 Normal file
View File

@@ -0,0 +1,144 @@
-- 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"},
}

139
util/LLgen/doc/LLgen.1 Normal file
View File

@@ -0,0 +1,139 @@
.\" $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.

1077
util/LLgen/doc/LLgen.n Normal file

File diff suppressed because it is too large Load Diff

54
util/LLgen/doc/LLgen.refs Normal file
View File

@@ -0,0 +1,54 @@
%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

2712
util/LLgen/doc/LLgen_NCER.n Normal file

File diff suppressed because it is too large Load Diff

68
util/LLgen/lib/incl Normal file
View File

@@ -0,0 +1,68 @@
/* $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 */

70
util/LLgen/lib/nc_incl Normal file
View File

@@ -0,0 +1,70 @@
#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)))

1790
util/LLgen/lib/nc_rec Normal file

File diff suppressed because it is too large Load Diff

442
util/LLgen/lib/rec Normal file
View File

@@ -0,0 +1,442 @@
/*
* 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];
}
}

64
util/LLgen/mkdistr.sh Executable file
View File

@@ -0,0 +1,64 @@
#!/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 Executable file

Binary file not shown.

103
util/LLgen/pmfile Normal file
View File

@@ -0,0 +1,103 @@
-- $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 -)"
}
}

665
util/LLgen/src/LLgen.g Normal file
View File

@@ -0,0 +1,665 @@
/* 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;
}
}

90
util/LLgen/src/alloc.c Normal file
View File

@@ -0,0 +1,90 @@
/* 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;
}

138
util/LLgen/src/cclass.c Normal file
View File

@@ -0,0 +1,138 @@
/* 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 */
};

17
util/LLgen/src/cclass.h Normal file
View File

@@ -0,0 +1,17 @@
/* 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

474
util/LLgen/src/check.c Normal file
View File

@@ -0,0 +1,474 @@
/* 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,' ');
}

1159
util/LLgen/src/compute.c Normal file

File diff suppressed because it is too large Load Diff

94
util/LLgen/src/extern.h Normal file
View File

@@ -0,0 +1,94 @@
/* 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;

1360
util/LLgen/src/gencode.c Normal file

File diff suppressed because it is too large Load Diff

89
util/LLgen/src/global.c Normal file
View File

@@ -0,0 +1,89 @@
/* 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.
*/

43
util/LLgen/src/io.h Normal file
View File

@@ -0,0 +1,43 @@
/* 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

72
util/LLgen/src/machdep.c Normal file
View File

@@ -0,0 +1,72 @@
/* 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;
}

378
util/LLgen/src/main.c Normal file
View File

@@ -0,0 +1,378 @@
/* 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);
}
}

251
util/LLgen/src/name.c Normal file
View File

@@ -0,0 +1,251 @@
/* 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);
}
}

135
util/LLgen/src/reach.c Normal file
View File

@@ -0,0 +1,135 @@
/* 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++;
}
}

385
util/LLgen/src/savegram.c Normal file
View File

@@ -0,0 +1,385 @@
/* 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

218
util/LLgen/src/sets.c Normal file
View File

@@ -0,0 +1,218 @@
/* 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;
}

33
util/LLgen/src/sets.h Normal file
View File

@@ -0,0 +1,33 @@
/* 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;

604
util/LLgen/src/tokens.g Normal file
View File

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

272
util/LLgen/src/types.h Normal file
View File

@@ -0,0 +1,272 @@
/* 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 */

View File

@@ -1,339 +0,0 @@
/*
* (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);
}
}
}
}