diff options
| author | Paweł Redman <pawel.redman@gmail.com> | 2017-03-22 17:56:34 +0100 | 
|---|---|---|
| committer | Paweł Redman <pawel.redman@gmail.com> | 2017-03-22 17:56:34 +0100 | 
| commit | 6a777afc079c2a8d3af3ecd2145fe8dd50567a39 (patch) | |
| tree | 520f4489cebf8564ef6cb27064ceea45cbc005b3 /src/tools/lcc | |
Diffstat (limited to 'src/tools/lcc')
152 files changed, 21949 insertions, 0 deletions
diff --git a/src/tools/lcc/COPYRIGHT b/src/tools/lcc/COPYRIGHT new file mode 100644 index 0000000..961a48f --- /dev/null +++ b/src/tools/lcc/COPYRIGHT @@ -0,0 +1,61 @@ +The authors of this software are Christopher W. Fraser and +David R. Hanson. + +Copyright (c) 1991,1992,1993,1994,1995,1996,1997,1998 by AT&T, +Christopher W. Fraser, and David R. Hanson. All Rights Reserved. + +Permission to use, copy, modify, and distribute this software for any +purpose, subject to the provisions described below, without fee is +hereby granted, provided that this entire notice is included in all +copies of any software that is or includes a copy or modification of +this software and in all copies of the supporting documentation for +such software. + +THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED +WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY +REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY +OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + + +lcc is not public-domain software, shareware, and it is not protected +by a `copyleft' agreement, like the code from the Free Software +Foundation. + +lcc is available free for your personal research and instructional use +under the `fair use' provisions of the copyright law. You may, however, +redistribute lcc in whole or in part provided you acknowledge its +source and include this CPYRIGHT file. You may, for example, include +the distribution in a CDROM of free software, provided you charge only +for the media, or mirror the distribution files at your site. + +You may not sell lcc or any product derived from it in which it is a +significant part of the value of the product. Using the lcc front end +to build a C syntax checker is an example of this kind of product. + +You may use parts of lcc in products as long as you charge for only +those components that are entirely your own and you acknowledge the use +of lcc clearly in all product documentation and distribution media. You +must state clearly that your product uses or is based on parts of lcc +and that lcc is available free of charge. You must also request that +bug reports on your product be reported to you. Using the lcc front +end to build a C compiler for the Motorola 88000 chip and charging for +and distributing only the 88000 code generator is an example of this +kind of product. + +Using parts of lcc in other products is more problematic. For example, +using parts of lcc in a C++ compiler could save substantial time and +effort and therefore contribute significantly to the profitability of +the product. This kind of use, or any use where others stand to make a +profit from what is primarily our work, requires a license agreement +with Addison-Wesley.  Per-copy and unlimited use licenses are +available; for more information, contact + +	J. Carter Shanklin +	Addison Wesley Longman, Inc.  +	2725 Sand Hill Rd. +	Menlo Park, CA 94025 +	650/854-0300 x2478 FAX: 650/614-2930 jcs@awl.com +----- +Chris Fraser / cwfraser@microsoft.com +David Hanson / drh@microsoft.com +$Revision: 145 $ $Date: 2001-10-17 16:53:10 -0500 (Wed, 17 Oct 2001) $ diff --git a/src/tools/lcc/LOG b/src/tools/lcc/LOG new file mode 100644 index 0000000..dd23f62 --- /dev/null +++ b/src/tools/lcc/LOG @@ -0,0 +1,91 @@ +From lcc 4.0 to 4.1: + +Changes: + +See doc/4.html for changes in the code-generation interface. + +Warns about constants that are too large, eg, short x = 70000; + +Warns about expressions that have no effect. + +Unsigned shorts are now used for wide-character constants, and +wchar_t is a typedef for unsigned short. + +More assertions in gen.c to confirm that the register allocator is +configured correctly; ie, that the various masks, wildcards, +clobbers, and targets are internally consistent. Full checking +appears impractical, but there's still more than than there was +before. + +On the SPARC, lcc now emits .type and .size directives +unconditionally. + +On the x86, constants are now emitted into the text segment. + +If the environment variable "LCCDIR" is defined, it gives the directory +that contains the preprocessor, the compiler proper, and the +lcc-specific libraries. + +Under Windows, lcc searches the directories named in the environment +variable "include" for header files. + +Errors fixed: + +Erroneously complained about unknown sizes for some const fields, eg, +typedef struct foo ref; struct foo { const ref *q; int a; }; +f(ref *p, int i) { return p->q[i].a; } + +-A -A erroneously complained about static main's that didn't conform +to the ANSI-mandated "int main(void)" or "int main(int, char **)". + +Silently generated incorrect code for a structure copy with a +post-incremented target, eg, +struct { int x; } data = {1}, copy[2], *q = copy; +main() { *q++ = data; } + +Generated incorrect values in some expressions with constant pointers. + +Silently truncated string literals longer than 4095 characters. + +Failed to emit debugging information for uninitialized globals. + +Failed to diagnose missing sizes in some multi-dimensioned array +declarators, eg, extern int x[][10]; int x[5][]; + +Silently emitted incorrect sizes and initalizations for some +incomplete multi-dimensioned arrays involving pointers and whose size +is determined by the number of initializers. + +Set only the x.name field for some back-end symbols (eg, wildcards), +and the uninitialized name field crashed some debugging output. + +uses() failed to check the register *set* as well as the register +mask.  There's no known bug demo, but a wildcard set might be +contrived that would need the test. + +Crashed with -b on some conditional expressions involving calls, eg, +int p; void g(void) { p ? f() : 1; } + +On the MIPS, sometimes generated an incorrect frame size and thus a +crash when floating-point registers were saved. + +On the SPARC, erroneously reused a register variable as a temporary +when the variable is compiler-generated. + +On the SPARC with -b, emitted incorrect code for returning structs. + +On the x86, conversion from float to int rounded instead of truncated +with the default floating-point mode. + +On the x86, eliminate rtargets for kids after the first (see p. 419). + +On the x86, substitute reg for freg, in order to use the common reg +rules. Needed only for debugging output, since we're not using any +float regs as regs at this time. + +On the x86, "double f(); main(){f();}" wasn't popping the FP register stack. + +On the x86, ECX was saved by the callee, when it should have been +saved by the caller. + +$Id: LOG 145 2001-10-17 21:53:10Z timo $ diff --git a/src/tools/lcc/Makefile b/src/tools/lcc/Makefile new file mode 100644 index 0000000..8dd5fb2 --- /dev/null +++ b/src/tools/lcc/Makefile @@ -0,0 +1,163 @@ +TEMPDIR=/tmp +A=.a +O=.o + +ifeq ($(PLATFORM),mingw32) +  E=.exe +else +  E= +endif + +CC=gcc +LCC_CFLAGS=-O2 -Wall -fno-strict-aliasing -MMD +LDFLAGS= +LD=gcc +AR=ar +ARFLAGS=cru +RANLIB=ranlib +DIFF=diff +RM=rm -f +RMDIR=rmdir +BUILDDIR=build-$(PLATFORM)-$(ARCH) +BD=$(BUILDDIR)/ + +ifeq ($(USE_CCACHE),1) +  CC := ccache $(CC) +endif + +# Need MACOS_X defined or this won't build. +ifeq ($(PLATFORM),darwin) +  LCC_CFLAGS += -DMACOS_X +endif + +ifeq ($(PLATFORM),sunos) +  INSTALL=ginstall +else +  INSTALL=install +endif + +all: q3rcc lburg q3cpp q3lcc + +q3rcc: makedirs $(BD)q3rcc$(E) +lburg: makedirs $(BD)lburg$(E) +q3cpp: makedirs $(BD)q3cpp$(E) +q3lcc: makedirs $(BD)q3lcc$(E) + +makedirs: +	@if [ ! -d $(BD) ];then mkdir $(BD);fi +	@if [ ! -d $(BD)/etc ];then mkdir $(BD)/etc;fi +	@if [ ! -d $(BD)/rcc ];then mkdir $(BD)/rcc;fi +	@if [ ! -d $(BD)/cpp ];then mkdir $(BD)/cpp;fi +	@if [ ! -d $(BD)/lburg ];then mkdir $(BD)/lburg;fi + +# ===== RCC ===== +RCCOBJS= \ +	$(BD)rcc/alloc$(O) \ +	$(BD)rcc/bind$(O) \ +	$(BD)rcc/bytecode$(O) \ +	$(BD)rcc/dag$(O) \ +	$(BD)rcc/dagcheck$(O) \ +	$(BD)rcc/decl$(O) \ +	$(BD)rcc/enode$(O) \ +	$(BD)rcc/error$(O) \ +	$(BD)rcc/event$(O) \ +	$(BD)rcc/expr$(O) \ +	$(BD)rcc/gen$(O) \ +	$(BD)rcc/init$(O) \ +	$(BD)rcc/inits$(O) \ +	$(BD)rcc/input$(O) \ +	$(BD)rcc/lex$(O) \ +	$(BD)rcc/list$(O) \ +	$(BD)rcc/main$(O) \ +	$(BD)rcc/null$(O) \ +	$(BD)rcc/output$(O) \ +	$(BD)rcc/prof$(O) \ +	$(BD)rcc/profio$(O) \ +	$(BD)rcc/simp$(O) \ +	$(BD)rcc/stmt$(O) \ +	$(BD)rcc/string$(O) \ +	$(BD)rcc/sym$(O) \ +	$(BD)rcc/symbolic$(O) \ +	$(BD)rcc/trace$(O) \ +	$(BD)rcc/tree$(O) \ +	$(BD)rcc/types$(O) + +$(BD)q3rcc$(E): $(RCCOBJS) +	$(LD) $(LDFLAGS) -o $@ $(RCCOBJS) + +$(BD)rcc/%$(O): src/%.c +	$(CC) $(LCC_CFLAGS) -c -Isrc -o $@ $< + +$(BD)rcc/dagcheck$(O): $(BD)rcc/dagcheck.c +	$(CC) $(LCC_CFLAGS) -Wno-unused -c -Isrc -o $@ $< + +$(BD)rcc/dagcheck.c: $(BD)lburg/lburg$(E) src/dagcheck.md +	$(BD)lburg/lburg$(E) src/dagcheck.md $@ + + +# ===== LBURG ===== +LBURGOBJS= \ +	$(BD)lburg/lburg$(O) \ +	$(BD)lburg/gram$(O) + +$(BD)lburg/lburg$(E): $(LBURGOBJS) +	$(LD) $(LDFLAGS) -o $@ $(LBURGOBJS) + +$(BD)lburg/%$(O): lburg/%.c +	$(CC) $(LCC_CFLAGS) -c -Ilburg -o $@ $< + + +# ===== CPP ===== +CPPOBJS= \ +	$(BD)cpp/cpp$(O) \ +	$(BD)cpp/lex$(O) \ +	$(BD)cpp/nlist$(O) \ +	$(BD)cpp/tokens$(O) \ +	$(BD)cpp/macro$(O) \ +	$(BD)cpp/eval$(O) \ +	$(BD)cpp/include$(O) \ +	$(BD)cpp/hideset$(O) \ +	$(BD)cpp/getopt$(O) \ +	$(BD)cpp/unix$(O) + +$(BD)q3cpp$(E): $(CPPOBJS) +	$(LD) $(LDFLAGS) -o $@ $(CPPOBJS) + +$(BD)cpp/%$(O): cpp/%.c +	$(CC) $(LCC_CFLAGS) -c -Icpp -o $@ $< + + +# ===== LCC ===== +LCCOBJS= \ +	$(BD)etc/lcc$(O) \ +	$(BD)etc/bytecode$(O) + +$(BD)q3lcc$(E): $(LCCOBJS) +	$(LD) $(LDFLAGS) -o $@ $(LCCOBJS) + +$(BD)etc/%$(O): etc/%.c +	$(CC) $(LCC_CFLAGS) -DTEMPDIR=\"$(TEMPDIR)\" -DSYSTEM=\"\" -c -Isrc -o $@ $< + + +install: q3lcc q3cpp q3rcc +	$(INSTALL) -s -m 0755 $(BD)q3lcc$(E) ../ +	$(INSTALL) -s -m 0755 $(BD)q3cpp$(E) ../ +	$(INSTALL) -s -m 0755 $(BD)q3rcc$(E) ../ + +uninstall: +	-$(RM) ../q3lcc$(E) +	-$(RM) ../q3cpp$(E) +	-$(RM) ../q3rcc$(E) + +clean: +	if [ -d $(BD) ];then (find $(BD) -name '*.d' -exec rm {} \;)fi +	$(RM) $(RCCOBJS) $(LBURGOBJS) $(CPPOBJS) $(LCCOBJS) +	$(RM) $(BD)rcc/dagcheck.c $(BD)lburg/lburg$(E) +	$(RM) $(BD)q3lcc$(E) $(BD)q3cpp$(E) $(BD)q3rcc$(E) +	$(RM) -r $(BD) + +D_FILES=$(shell find . -name '*.d') + +ifneq ($(strip $(D_FILES)),) +  include $(D_FILES) +endif diff --git a/src/tools/lcc/README b/src/tools/lcc/README new file mode 100644 index 0000000..4ba4d3f --- /dev/null +++ b/src/tools/lcc/README @@ -0,0 +1,21 @@ +This hierarchy is the distribution for lcc version 4.1. + +lcc version 3.x is described in the book "A Retargetable C Compiler: +Design and Implementation" (Addison-Wesley, 1995, ISBN 0-8053-1670-1). +There are significant differences between 3.x and 4.x, most notably in +the intermediate code. doc/4.html summarizes the differences. + +VERSION 4.1 IS INCOMPATIBLE WITH EARLIER VERSIONS OF LCC. DO NOT +UNLOAD THIS DISTRIBUTION ON TOP OF A 3.X DISTRIBUTION. + +LOG describes the changes since the last release. + +CPYRIGHT describes the conditions under you can use, copy, modify, and +distribute lcc or works derived from lcc. + +doc/install.html is an HTML file that gives a complete description of +the distribution and installation instructions. + +Chris Fraser / cwfraser@microsoft.com +David Hanson / drh@microsoft.com +$Revision: 145 $ $Date: 2001-10-17 16:53:10 -0500 (Wed, 17 Oct 2001) $ diff --git a/src/tools/lcc/README.id b/src/tools/lcc/README.id new file mode 100644 index 0000000..6611a37 --- /dev/null +++ b/src/tools/lcc/README.id @@ -0,0 +1,3 @@ +2001-10-31  Timothee Besset <ttimo@idsoftware.com> +updated from the $/source/lcc code +modified for portability and use with >= 1.31 mod source release diff --git a/src/tools/lcc/build-mingw32-x86/cpp/cpp.d b/src/tools/lcc/build-mingw32-x86/cpp/cpp.d new file mode 100644 index 0000000..1e6df09 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/cpp/cpp.d @@ -0,0 +1 @@ +build-mingw32-x86/cpp/cpp.o: cpp/cpp.c cpp/cpp.h
 diff --git a/src/tools/lcc/build-mingw32-x86/cpp/cpp.o b/src/tools/lcc/build-mingw32-x86/cpp/cpp.o Binary files differnew file mode 100644 index 0000000..796a68f --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/cpp/cpp.o diff --git a/src/tools/lcc/build-mingw32-x86/cpp/eval.d b/src/tools/lcc/build-mingw32-x86/cpp/eval.d new file mode 100644 index 0000000..91cecf9 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/cpp/eval.d @@ -0,0 +1 @@ +build-mingw32-x86/cpp/eval.o: cpp/eval.c cpp/cpp.h
 diff --git a/src/tools/lcc/build-mingw32-x86/cpp/eval.o b/src/tools/lcc/build-mingw32-x86/cpp/eval.o Binary files differnew file mode 100644 index 0000000..d2c2f5d --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/cpp/eval.o diff --git a/src/tools/lcc/build-mingw32-x86/cpp/getopt.d b/src/tools/lcc/build-mingw32-x86/cpp/getopt.d new file mode 100644 index 0000000..588c535 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/cpp/getopt.d @@ -0,0 +1 @@ +build-mingw32-x86/cpp/getopt.o: cpp/getopt.c
 diff --git a/src/tools/lcc/build-mingw32-x86/cpp/getopt.o b/src/tools/lcc/build-mingw32-x86/cpp/getopt.o Binary files differnew file mode 100644 index 0000000..fa3077b --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/cpp/getopt.o diff --git a/src/tools/lcc/build-mingw32-x86/cpp/hideset.d b/src/tools/lcc/build-mingw32-x86/cpp/hideset.d new file mode 100644 index 0000000..45a524d --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/cpp/hideset.d @@ -0,0 +1 @@ +build-mingw32-x86/cpp/hideset.o: cpp/hideset.c cpp/cpp.h
 diff --git a/src/tools/lcc/build-mingw32-x86/cpp/hideset.o b/src/tools/lcc/build-mingw32-x86/cpp/hideset.o Binary files differnew file mode 100644 index 0000000..b50d276 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/cpp/hideset.o diff --git a/src/tools/lcc/build-mingw32-x86/cpp/include.d b/src/tools/lcc/build-mingw32-x86/cpp/include.d new file mode 100644 index 0000000..9142604 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/cpp/include.d @@ -0,0 +1 @@ +build-mingw32-x86/cpp/include.o: cpp/include.c cpp/cpp.h
 diff --git a/src/tools/lcc/build-mingw32-x86/cpp/include.o b/src/tools/lcc/build-mingw32-x86/cpp/include.o Binary files differnew file mode 100644 index 0000000..5e854ed --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/cpp/include.o diff --git a/src/tools/lcc/build-mingw32-x86/cpp/lex.d b/src/tools/lcc/build-mingw32-x86/cpp/lex.d new file mode 100644 index 0000000..9d79717 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/cpp/lex.d @@ -0,0 +1 @@ +build-mingw32-x86/cpp/lex.o: cpp/lex.c cpp/cpp.h
 diff --git a/src/tools/lcc/build-mingw32-x86/cpp/lex.o b/src/tools/lcc/build-mingw32-x86/cpp/lex.o Binary files differnew file mode 100644 index 0000000..55a6d8b --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/cpp/lex.o diff --git a/src/tools/lcc/build-mingw32-x86/cpp/macro.d b/src/tools/lcc/build-mingw32-x86/cpp/macro.d new file mode 100644 index 0000000..50072bd --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/cpp/macro.d @@ -0,0 +1 @@ +build-mingw32-x86/cpp/macro.o: cpp/macro.c cpp/cpp.h
 diff --git a/src/tools/lcc/build-mingw32-x86/cpp/macro.o b/src/tools/lcc/build-mingw32-x86/cpp/macro.o Binary files differnew file mode 100644 index 0000000..7c40fe1 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/cpp/macro.o diff --git a/src/tools/lcc/build-mingw32-x86/cpp/nlist.d b/src/tools/lcc/build-mingw32-x86/cpp/nlist.d new file mode 100644 index 0000000..523bd99 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/cpp/nlist.d @@ -0,0 +1 @@ +build-mingw32-x86/cpp/nlist.o: cpp/nlist.c cpp/cpp.h
 diff --git a/src/tools/lcc/build-mingw32-x86/cpp/nlist.o b/src/tools/lcc/build-mingw32-x86/cpp/nlist.o Binary files differnew file mode 100644 index 0000000..6758ec7 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/cpp/nlist.o diff --git a/src/tools/lcc/build-mingw32-x86/cpp/tokens.d b/src/tools/lcc/build-mingw32-x86/cpp/tokens.d new file mode 100644 index 0000000..b79115e --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/cpp/tokens.d @@ -0,0 +1 @@ +build-mingw32-x86/cpp/tokens.o: cpp/tokens.c cpp/cpp.h
 diff --git a/src/tools/lcc/build-mingw32-x86/cpp/tokens.o b/src/tools/lcc/build-mingw32-x86/cpp/tokens.o Binary files differnew file mode 100644 index 0000000..f6025d9 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/cpp/tokens.o diff --git a/src/tools/lcc/build-mingw32-x86/cpp/unix.d b/src/tools/lcc/build-mingw32-x86/cpp/unix.d new file mode 100644 index 0000000..2497d6c --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/cpp/unix.d @@ -0,0 +1 @@ +build-mingw32-x86/cpp/unix.o: cpp/unix.c cpp/cpp.h
 diff --git a/src/tools/lcc/build-mingw32-x86/cpp/unix.o b/src/tools/lcc/build-mingw32-x86/cpp/unix.o Binary files differnew file mode 100644 index 0000000..0d9967a --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/cpp/unix.o diff --git a/src/tools/lcc/build-mingw32-x86/etc/bytecode.d b/src/tools/lcc/build-mingw32-x86/etc/bytecode.d new file mode 100644 index 0000000..6ec5010 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/etc/bytecode.d @@ -0,0 +1,2 @@ +build-mingw32-x86/etc/bytecode.o: etc/bytecode.c \
 +  etc/../../../qcommon/q_platform.h
 diff --git a/src/tools/lcc/build-mingw32-x86/etc/bytecode.o b/src/tools/lcc/build-mingw32-x86/etc/bytecode.o Binary files differnew file mode 100644 index 0000000..0bc871e --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/etc/bytecode.o diff --git a/src/tools/lcc/build-mingw32-x86/etc/lcc.d b/src/tools/lcc/build-mingw32-x86/etc/lcc.d new file mode 100644 index 0000000..db5601e --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/etc/lcc.d @@ -0,0 +1 @@ +build-mingw32-x86/etc/lcc.o: etc/lcc.c
 diff --git a/src/tools/lcc/build-mingw32-x86/etc/lcc.o b/src/tools/lcc/build-mingw32-x86/etc/lcc.o Binary files differnew file mode 100644 index 0000000..a71eb3a --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/etc/lcc.o diff --git a/src/tools/lcc/build-mingw32-x86/lburg/gram.d b/src/tools/lcc/build-mingw32-x86/lburg/gram.d new file mode 100644 index 0000000..7fb0f94 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/lburg/gram.d @@ -0,0 +1 @@ +build-mingw32-x86/lburg/gram.o: lburg/gram.c lburg/lburg.h
 diff --git a/src/tools/lcc/build-mingw32-x86/lburg/gram.o b/src/tools/lcc/build-mingw32-x86/lburg/gram.o Binary files differnew file mode 100644 index 0000000..989471f --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/lburg/gram.o diff --git a/src/tools/lcc/build-mingw32-x86/lburg/lburg.d b/src/tools/lcc/build-mingw32-x86/lburg/lburg.d new file mode 100644 index 0000000..6d1a42c --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/lburg/lburg.d @@ -0,0 +1 @@ +build-mingw32-x86/lburg/lburg.o: lburg/lburg.c lburg/lburg.h
 diff --git a/src/tools/lcc/build-mingw32-x86/lburg/lburg.exe b/src/tools/lcc/build-mingw32-x86/lburg/lburg.exe Binary files differnew file mode 100644 index 0000000..b6206fc --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/lburg/lburg.exe diff --git a/src/tools/lcc/build-mingw32-x86/lburg/lburg.o b/src/tools/lcc/build-mingw32-x86/lburg/lburg.o Binary files differnew file mode 100644 index 0000000..b8bb453 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/lburg/lburg.o diff --git a/src/tools/lcc/build-mingw32-x86/q3cpp.exe b/src/tools/lcc/build-mingw32-x86/q3cpp.exe Binary files differnew file mode 100644 index 0000000..db9901e --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/q3cpp.exe diff --git a/src/tools/lcc/build-mingw32-x86/q3lcc.exe b/src/tools/lcc/build-mingw32-x86/q3lcc.exe Binary files differnew file mode 100644 index 0000000..f775a8a --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/q3lcc.exe diff --git a/src/tools/lcc/build-mingw32-x86/q3rcc.exe b/src/tools/lcc/build-mingw32-x86/q3rcc.exe Binary files differnew file mode 100644 index 0000000..a377f00 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/q3rcc.exe diff --git a/src/tools/lcc/build-mingw32-x86/rcc/alloc.d b/src/tools/lcc/build-mingw32-x86/rcc/alloc.d new file mode 100644 index 0000000..295181a --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/alloc.d @@ -0,0 +1,2 @@ +build-mingw32-x86/rcc/alloc.o: src/alloc.c src/c.h src/config.h \
 +  src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/alloc.o b/src/tools/lcc/build-mingw32-x86/rcc/alloc.o Binary files differnew file mode 100644 index 0000000..5af0f2b --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/alloc.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/bind.d b/src/tools/lcc/build-mingw32-x86/rcc/bind.d new file mode 100644 index 0000000..8af7505 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/bind.d @@ -0,0 +1 @@ +build-mingw32-x86/rcc/bind.o: src/bind.c src/c.h src/config.h src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/bind.o b/src/tools/lcc/build-mingw32-x86/rcc/bind.o Binary files differnew file mode 100644 index 0000000..5522529 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/bind.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/bytecode.d b/src/tools/lcc/build-mingw32-x86/rcc/bytecode.d new file mode 100644 index 0000000..a71ac78 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/bytecode.d @@ -0,0 +1,2 @@ +build-mingw32-x86/rcc/bytecode.o: src/bytecode.c src/c.h src/config.h \
 +  src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/bytecode.o b/src/tools/lcc/build-mingw32-x86/rcc/bytecode.o Binary files differnew file mode 100644 index 0000000..a25dfc2 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/bytecode.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/dag.d b/src/tools/lcc/build-mingw32-x86/rcc/dag.d new file mode 100644 index 0000000..5f6ef0d --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/dag.d @@ -0,0 +1 @@ +build-mingw32-x86/rcc/dag.o: src/dag.c src/c.h src/config.h src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/dag.o b/src/tools/lcc/build-mingw32-x86/rcc/dag.o Binary files differnew file mode 100644 index 0000000..482dfdd --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/dag.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/dagcheck.c b/src/tools/lcc/build-mingw32-x86/rcc/dagcheck.c new file mode 100644 index 0000000..e723dac --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/dagcheck.c @@ -0,0 +1,2086 @@ +#include "c.h"
 +typedef Node NODEPTR_TYPE;
 +#define OP_LABEL(p)     (specific((p)->op))
 +#define LEFT_CHILD(p)   ((p)->kids[0])
 +#define RIGHT_CHILD(p)  ((p)->kids[1])
 +#define STATE_LABEL(p)  ((p)->x.state)
 +#define PANIC	   error
 +/*
 +generated at Fri Mar 06 20:43:04 2009
 +by lburg.c - faked rcsid
 +*/
 +static void _kids(NODEPTR_TYPE, int, NODEPTR_TYPE[]);
 +static void _label(NODEPTR_TYPE);
 +static int _rule(void*, int);
 +
 +#define _stmt_NT 1
 +#define _P_NT 2
 +#define _V_NT 3
 +#define _bogus_NT 4
 +#define _I_NT 5
 +#define _U_NT 6
 +#define _F_NT 7
 +#define _B_NT 8
 +
 +static char *_ntname[] = {
 +	0,
 +	"stmt",
 +	"P",
 +	"V",
 +	"bogus",
 +	"I",
 +	"U",
 +	"F",
 +	"B",
 +	0
 +};
 +
 +struct _state {
 +	short cost[9];
 +	struct {
 +		unsigned int _stmt:4;
 +		unsigned int _P:4;
 +		unsigned int _V:6;
 +		unsigned int _bogus:3;
 +		unsigned int _I:5;
 +		unsigned int _U:5;
 +		unsigned int _F:4;
 +		unsigned int _B:2;
 +	} rule;
 +};
 +
 +static short _nts_0[] = { _P_NT, 0 };
 +static short _nts_1[] = { _V_NT, 0 };
 +static short _nts_2[] = { _I_NT, 0 };
 +static short _nts_3[] = { _U_NT, 0 };
 +static short _nts_4[] = { _F_NT, 0 };
 +static short _nts_5[] = { _B_NT, 0 };
 +static short _nts_6[] = { _bogus_NT, 0 };
 +static short _nts_7[] = { 0 };
 +static short _nts_8[] = { _P_NT, _B_NT, 0 };
 +static short _nts_9[] = { _P_NT, _F_NT, 0 };
 +static short _nts_10[] = { _P_NT, _I_NT, 0 };
 +static short _nts_11[] = { _P_NT, _U_NT, 0 };
 +static short _nts_12[] = { _P_NT, _P_NT, 0 };
 +static short _nts_13[] = { _F_NT, _F_NT, 0 };
 +static short _nts_14[] = { _I_NT, _I_NT, 0 };
 +static short _nts_15[] = { _I_NT, _P_NT, 0 };
 +static short _nts_16[] = { _U_NT, _P_NT, 0 };
 +static short _nts_17[] = { _U_NT, _U_NT, 0 };
 +static short _nts_18[] = { _U_NT, _I_NT, 0 };
 +
 +static short *_nts[] = {
 +	0,	/* 0 */
 +	_nts_0,	/* 1 */
 +	_nts_0,	/* 2 */
 +	_nts_0,	/* 3 */
 +	_nts_0,	/* 4 */
 +	_nts_0,	/* 5 */
 +	_nts_0,	/* 6 */
 +	_nts_0,	/* 7 */
 +	_nts_0,	/* 8 */
 +	_nts_0,	/* 9 */
 +	_nts_1,	/* 10 */
 +	_nts_2,	/* 11 */
 +	_nts_3,	/* 12 */
 +	_nts_0,	/* 13 */
 +	_nts_4,	/* 14 */
 +	_nts_5,	/* 15 */
 +	_nts_1,	/* 16 */
 +	_nts_6,	/* 17 */
 +	_nts_6,	/* 18 */
 +	_nts_6,	/* 19 */
 +	_nts_6,	/* 20 */
 +	_nts_6,	/* 21 */
 +	_nts_6,	/* 22 */
 +	_nts_7,	/* 23 */
 +	_nts_7,	/* 24 */
 +	_nts_7,	/* 25 */
 +	_nts_7,	/* 26 */
 +	_nts_5,	/* 27 */
 +	_nts_4,	/* 28 */
 +	_nts_2,	/* 29 */
 +	_nts_3,	/* 30 */
 +	_nts_0,	/* 31 */
 +	_nts_8,	/* 32 */
 +	_nts_9,	/* 33 */
 +	_nts_10,	/* 34 */
 +	_nts_11,	/* 35 */
 +	_nts_12,	/* 36 */
 +	_nts_0,	/* 37 */
 +	_nts_0,	/* 38 */
 +	_nts_0,	/* 39 */
 +	_nts_0,	/* 40 */
 +	_nts_0,	/* 41 */
 +	_nts_2,	/* 42 */
 +	_nts_3,	/* 43 */
 +	_nts_4,	/* 44 */
 +	_nts_2,	/* 45 */
 +	_nts_3,	/* 46 */
 +	_nts_0,	/* 47 */
 +	_nts_2,	/* 48 */
 +	_nts_4,	/* 49 */
 +	_nts_3,	/* 50 */
 +	_nts_0,	/* 51 */
 +	_nts_4,	/* 52 */
 +	_nts_2,	/* 53 */
 +	_nts_12,	/* 54 */
 +	_nts_0,	/* 55 */
 +	_nts_0,	/* 56 */
 +	_nts_0,	/* 57 */
 +	_nts_0,	/* 58 */
 +	_nts_0,	/* 59 */
 +	_nts_4,	/* 60 */
 +	_nts_2,	/* 61 */
 +	_nts_3,	/* 62 */
 +	_nts_0,	/* 63 */
 +	_nts_7,	/* 64 */
 +	_nts_7,	/* 65 */
 +	_nts_7,	/* 66 */
 +	_nts_7,	/* 67 */
 +	_nts_13,	/* 68 */
 +	_nts_14,	/* 69 */
 +	_nts_10,	/* 70 */
 +	_nts_15,	/* 71 */
 +	_nts_16,	/* 72 */
 +	_nts_11,	/* 73 */
 +	_nts_17,	/* 74 */
 +	_nts_13,	/* 75 */
 +	_nts_14,	/* 76 */
 +	_nts_10,	/* 77 */
 +	_nts_11,	/* 78 */
 +	_nts_17,	/* 79 */
 +	_nts_14,	/* 80 */
 +	_nts_18,	/* 81 */
 +	_nts_14,	/* 82 */
 +	_nts_17,	/* 83 */
 +	_nts_14,	/* 84 */
 +	_nts_18,	/* 85 */
 +	_nts_17,	/* 86 */
 +	_nts_14,	/* 87 */
 +	_nts_3,	/* 88 */
 +	_nts_2,	/* 89 */
 +	_nts_14,	/* 90 */
 +	_nts_17,	/* 91 */
 +	_nts_17,	/* 92 */
 +	_nts_14,	/* 93 */
 +	_nts_13,	/* 94 */
 +	_nts_14,	/* 95 */
 +	_nts_17,	/* 96 */
 +	_nts_13,	/* 97 */
 +	_nts_14,	/* 98 */
 +	_nts_17,	/* 99 */
 +	_nts_13,	/* 100 */
 +	_nts_14,	/* 101 */
 +	_nts_17,	/* 102 */
 +	_nts_13,	/* 103 */
 +	_nts_14,	/* 104 */
 +	_nts_17,	/* 105 */
 +	_nts_13,	/* 106 */
 +	_nts_14,	/* 107 */
 +	_nts_17,	/* 108 */
 +	_nts_13,	/* 109 */
 +	_nts_14,	/* 110 */
 +	_nts_17,	/* 111 */
 +	_nts_13,	/* 112 */
 +	_nts_14,	/* 113 */
 +	_nts_17,	/* 114 */
 +	_nts_13,	/* 115 */
 +	_nts_14,	/* 116 */
 +	_nts_17,	/* 117 */
 +	_nts_0,	/* 118 */
 +	_nts_7,	/* 119 */
 +};
 +
 +static char *_templates[] = {
 +/* 0 */	0,
 +/* 1 */	"",	/* stmt: INDIRB(P) */
 +/* 2 */	"",	/* stmt: INDIRF(P) */
 +/* 3 */	"",	/* stmt: INDIRI(P) */
 +/* 4 */	"",	/* stmt: INDIRU(P) */
 +/* 5 */	"",	/* stmt: INDIRP(P) */
 +/* 6 */	"",	/* stmt: CALLF(P) */
 +/* 7 */	"",	/* stmt: CALLI(P) */
 +/* 8 */	"",	/* stmt: CALLU(P) */
 +/* 9 */	"",	/* stmt: CALLP(P) */
 +/* 10 */	"",	/* stmt: V */
 +/* 11 */	"",	/* bogus: I */
 +/* 12 */	"",	/* bogus: U */
 +/* 13 */	"",	/* bogus: P */
 +/* 14 */	"",	/* bogus: F */
 +/* 15 */	"",	/* bogus: B */
 +/* 16 */	"",	/* bogus: V */
 +/* 17 */	"",	/* I: bogus */
 +/* 18 */	"",	/* U: bogus */
 +/* 19 */	"",	/* P: bogus */
 +/* 20 */	"",	/* F: bogus */
 +/* 21 */	"",	/* B: bogus */
 +/* 22 */	"",	/* V: bogus */
 +/* 23 */	"",	/* F: CNSTF */
 +/* 24 */	"",	/* I: CNSTI */
 +/* 25 */	"",	/* P: CNSTP */
 +/* 26 */	"",	/* U: CNSTU */
 +/* 27 */	"",	/* V: ARGB(B) */
 +/* 28 */	"",	/* V: ARGF(F) */
 +/* 29 */	"",	/* V: ARGI(I) */
 +/* 30 */	"",	/* V: ARGU(U) */
 +/* 31 */	"",	/* V: ARGP(P) */
 +/* 32 */	"",	/* V: ASGNB(P,B) */
 +/* 33 */	"",	/* V: ASGNF(P,F) */
 +/* 34 */	"",	/* V: ASGNI(P,I) */
 +/* 35 */	"",	/* V: ASGNU(P,U) */
 +/* 36 */	"",	/* V: ASGNP(P,P) */
 +/* 37 */	"",	/* B: INDIRB(P) */
 +/* 38 */	"",	/* F: INDIRF(P) */
 +/* 39 */	"",	/* I: INDIRI(P) */
 +/* 40 */	"",	/* U: INDIRU(P) */
 +/* 41 */	"",	/* P: INDIRP(P) */
 +/* 42 */	"",	/* I: CVII(I) */
 +/* 43 */	"",	/* I: CVUI(U) */
 +/* 44 */	"",	/* I: CVFI(F) */
 +/* 45 */	"",	/* U: CVIU(I) */
 +/* 46 */	"",	/* U: CVUU(U) */
 +/* 47 */	"",	/* U: CVPU(P) */
 +/* 48 */	"",	/* F: CVIF(I) */
 +/* 49 */	"",	/* F: CVFF(F) */
 +/* 50 */	"",	/* P: CVUP(U) */
 +/* 51 */	"",	/* P: CVPP(P) */
 +/* 52 */	"",	/* F: NEGF(F) */
 +/* 53 */	"",	/* I: NEGI(I) */
 +/* 54 */	"",	/* V: CALLB(P,P) */
 +/* 55 */	"",	/* F: CALLF(P) */
 +/* 56 */	"",	/* I: CALLI(P) */
 +/* 57 */	"",	/* U: CALLU(P) */
 +/* 58 */	"",	/* P: CALLP(P) */
 +/* 59 */	"",	/* V: CALLV(P) */
 +/* 60 */	"",	/* V: RETF(F) */
 +/* 61 */	"",	/* V: RETI(I) */
 +/* 62 */	"",	/* V: RETU(U) */
 +/* 63 */	"",	/* V: RETP(P) */
 +/* 64 */	"",	/* V: RETV */
 +/* 65 */	"",	/* P: ADDRGP */
 +/* 66 */	"",	/* P: ADDRFP */
 +/* 67 */	"",	/* P: ADDRLP */
 +/* 68 */	"",	/* F: ADDF(F,F) */
 +/* 69 */	"",	/* I: ADDI(I,I) */
 +/* 70 */	"",	/* P: ADDP(P,I) */
 +/* 71 */	"",	/* P: ADDP(I,P) */
 +/* 72 */	"",	/* P: ADDP(U,P) */
 +/* 73 */	"",	/* P: ADDP(P,U) */
 +/* 74 */	"",	/* U: ADDU(U,U) */
 +/* 75 */	"",	/* F: SUBF(F,F) */
 +/* 76 */	"",	/* I: SUBI(I,I) */
 +/* 77 */	"",	/* P: SUBP(P,I) */
 +/* 78 */	"",	/* P: SUBP(P,U) */
 +/* 79 */	"",	/* U: SUBU(U,U) */
 +/* 80 */	"",	/* I: LSHI(I,I) */
 +/* 81 */	"",	/* U: LSHU(U,I) */
 +/* 82 */	"",	/* I: MODI(I,I) */
 +/* 83 */	"",	/* U: MODU(U,U) */
 +/* 84 */	"",	/* I: RSHI(I,I) */
 +/* 85 */	"",	/* U: RSHU(U,I) */
 +/* 86 */	"",	/* U: BANDU(U,U) */
 +/* 87 */	"",	/* I: BANDI(I,I) */
 +/* 88 */	"",	/* U: BCOMU(U) */
 +/* 89 */	"",	/* I: BCOMI(I) */
 +/* 90 */	"",	/* I: BORI(I,I) */
 +/* 91 */	"",	/* U: BORU(U,U) */
 +/* 92 */	"",	/* U: BXORU(U,U) */
 +/* 93 */	"",	/* I: BXORI(I,I) */
 +/* 94 */	"",	/* F: DIVF(F,F) */
 +/* 95 */	"",	/* I: DIVI(I,I) */
 +/* 96 */	"",	/* U: DIVU(U,U) */
 +/* 97 */	"",	/* F: MULF(F,F) */
 +/* 98 */	"",	/* I: MULI(I,I) */
 +/* 99 */	"",	/* U: MULU(U,U) */
 +/* 100 */	"",	/* V: EQF(F,F) */
 +/* 101 */	"",	/* V: EQI(I,I) */
 +/* 102 */	"",	/* V: EQU(U,U) */
 +/* 103 */	"",	/* V: GEF(F,F) */
 +/* 104 */	"",	/* V: GEI(I,I) */
 +/* 105 */	"",	/* V: GEU(U,U) */
 +/* 106 */	"",	/* V: GTF(F,F) */
 +/* 107 */	"",	/* V: GTI(I,I) */
 +/* 108 */	"",	/* V: GTU(U,U) */
 +/* 109 */	"",	/* V: LEF(F,F) */
 +/* 110 */	"",	/* V: LEI(I,I) */
 +/* 111 */	"",	/* V: LEU(U,U) */
 +/* 112 */	"",	/* V: LTF(F,F) */
 +/* 113 */	"",	/* V: LTI(I,I) */
 +/* 114 */	"",	/* V: LTU(U,U) */
 +/* 115 */	"",	/* V: NEF(F,F) */
 +/* 116 */	"",	/* V: NEI(I,I) */
 +/* 117 */	"",	/* V: NEU(U,U) */
 +/* 118 */	"",	/* V: JUMPV(P) */
 +/* 119 */	"",	/* V: LABELV */
 +};
 +
 +static char _isinstruction[] = {
 +/* 0 */	0,
 +/* 1 */	0,	/*  */
 +/* 2 */	0,	/*  */
 +/* 3 */	0,	/*  */
 +/* 4 */	0,	/*  */
 +/* 5 */	0,	/*  */
 +/* 6 */	0,	/*  */
 +/* 7 */	0,	/*  */
 +/* 8 */	0,	/*  */
 +/* 9 */	0,	/*  */
 +/* 10 */	0,	/*  */
 +/* 11 */	0,	/*  */
 +/* 12 */	0,	/*  */
 +/* 13 */	0,	/*  */
 +/* 14 */	0,	/*  */
 +/* 15 */	0,	/*  */
 +/* 16 */	0,	/*  */
 +/* 17 */	0,	/*  */
 +/* 18 */	0,	/*  */
 +/* 19 */	0,	/*  */
 +/* 20 */	0,	/*  */
 +/* 21 */	0,	/*  */
 +/* 22 */	0,	/*  */
 +/* 23 */	0,	/*  */
 +/* 24 */	0,	/*  */
 +/* 25 */	0,	/*  */
 +/* 26 */	0,	/*  */
 +/* 27 */	0,	/*  */
 +/* 28 */	0,	/*  */
 +/* 29 */	0,	/*  */
 +/* 30 */	0,	/*  */
 +/* 31 */	0,	/*  */
 +/* 32 */	0,	/*  */
 +/* 33 */	0,	/*  */
 +/* 34 */	0,	/*  */
 +/* 35 */	0,	/*  */
 +/* 36 */	0,	/*  */
 +/* 37 */	0,	/*  */
 +/* 38 */	0,	/*  */
 +/* 39 */	0,	/*  */
 +/* 40 */	0,	/*  */
 +/* 41 */	0,	/*  */
 +/* 42 */	0,	/*  */
 +/* 43 */	0,	/*  */
 +/* 44 */	0,	/*  */
 +/* 45 */	0,	/*  */
 +/* 46 */	0,	/*  */
 +/* 47 */	0,	/*  */
 +/* 48 */	0,	/*  */
 +/* 49 */	0,	/*  */
 +/* 50 */	0,	/*  */
 +/* 51 */	0,	/*  */
 +/* 52 */	0,	/*  */
 +/* 53 */	0,	/*  */
 +/* 54 */	0,	/*  */
 +/* 55 */	0,	/*  */
 +/* 56 */	0,	/*  */
 +/* 57 */	0,	/*  */
 +/* 58 */	0,	/*  */
 +/* 59 */	0,	/*  */
 +/* 60 */	0,	/*  */
 +/* 61 */	0,	/*  */
 +/* 62 */	0,	/*  */
 +/* 63 */	0,	/*  */
 +/* 64 */	0,	/*  */
 +/* 65 */	0,	/*  */
 +/* 66 */	0,	/*  */
 +/* 67 */	0,	/*  */
 +/* 68 */	0,	/*  */
 +/* 69 */	0,	/*  */
 +/* 70 */	0,	/*  */
 +/* 71 */	0,	/*  */
 +/* 72 */	0,	/*  */
 +/* 73 */	0,	/*  */
 +/* 74 */	0,	/*  */
 +/* 75 */	0,	/*  */
 +/* 76 */	0,	/*  */
 +/* 77 */	0,	/*  */
 +/* 78 */	0,	/*  */
 +/* 79 */	0,	/*  */
 +/* 80 */	0,	/*  */
 +/* 81 */	0,	/*  */
 +/* 82 */	0,	/*  */
 +/* 83 */	0,	/*  */
 +/* 84 */	0,	/*  */
 +/* 85 */	0,	/*  */
 +/* 86 */	0,	/*  */
 +/* 87 */	0,	/*  */
 +/* 88 */	0,	/*  */
 +/* 89 */	0,	/*  */
 +/* 90 */	0,	/*  */
 +/* 91 */	0,	/*  */
 +/* 92 */	0,	/*  */
 +/* 93 */	0,	/*  */
 +/* 94 */	0,	/*  */
 +/* 95 */	0,	/*  */
 +/* 96 */	0,	/*  */
 +/* 97 */	0,	/*  */
 +/* 98 */	0,	/*  */
 +/* 99 */	0,	/*  */
 +/* 100 */	0,	/*  */
 +/* 101 */	0,	/*  */
 +/* 102 */	0,	/*  */
 +/* 103 */	0,	/*  */
 +/* 104 */	0,	/*  */
 +/* 105 */	0,	/*  */
 +/* 106 */	0,	/*  */
 +/* 107 */	0,	/*  */
 +/* 108 */	0,	/*  */
 +/* 109 */	0,	/*  */
 +/* 110 */	0,	/*  */
 +/* 111 */	0,	/*  */
 +/* 112 */	0,	/*  */
 +/* 113 */	0,	/*  */
 +/* 114 */	0,	/*  */
 +/* 115 */	0,	/*  */
 +/* 116 */	0,	/*  */
 +/* 117 */	0,	/*  */
 +/* 118 */	0,	/*  */
 +/* 119 */	0,	/*  */
 +};
 +
 +static char *_string[] = {
 +/* 0 */	0,
 +/* 1 */	"stmt: INDIRB(P)",
 +/* 2 */	"stmt: INDIRF(P)",
 +/* 3 */	"stmt: INDIRI(P)",
 +/* 4 */	"stmt: INDIRU(P)",
 +/* 5 */	"stmt: INDIRP(P)",
 +/* 6 */	"stmt: CALLF(P)",
 +/* 7 */	"stmt: CALLI(P)",
 +/* 8 */	"stmt: CALLU(P)",
 +/* 9 */	"stmt: CALLP(P)",
 +/* 10 */	"stmt: V",
 +/* 11 */	"bogus: I",
 +/* 12 */	"bogus: U",
 +/* 13 */	"bogus: P",
 +/* 14 */	"bogus: F",
 +/* 15 */	"bogus: B",
 +/* 16 */	"bogus: V",
 +/* 17 */	"I: bogus",
 +/* 18 */	"U: bogus",
 +/* 19 */	"P: bogus",
 +/* 20 */	"F: bogus",
 +/* 21 */	"B: bogus",
 +/* 22 */	"V: bogus",
 +/* 23 */	"F: CNSTF",
 +/* 24 */	"I: CNSTI",
 +/* 25 */	"P: CNSTP",
 +/* 26 */	"U: CNSTU",
 +/* 27 */	"V: ARGB(B)",
 +/* 28 */	"V: ARGF(F)",
 +/* 29 */	"V: ARGI(I)",
 +/* 30 */	"V: ARGU(U)",
 +/* 31 */	"V: ARGP(P)",
 +/* 32 */	"V: ASGNB(P,B)",
 +/* 33 */	"V: ASGNF(P,F)",
 +/* 34 */	"V: ASGNI(P,I)",
 +/* 35 */	"V: ASGNU(P,U)",
 +/* 36 */	"V: ASGNP(P,P)",
 +/* 37 */	"B: INDIRB(P)",
 +/* 38 */	"F: INDIRF(P)",
 +/* 39 */	"I: INDIRI(P)",
 +/* 40 */	"U: INDIRU(P)",
 +/* 41 */	"P: INDIRP(P)",
 +/* 42 */	"I: CVII(I)",
 +/* 43 */	"I: CVUI(U)",
 +/* 44 */	"I: CVFI(F)",
 +/* 45 */	"U: CVIU(I)",
 +/* 46 */	"U: CVUU(U)",
 +/* 47 */	"U: CVPU(P)",
 +/* 48 */	"F: CVIF(I)",
 +/* 49 */	"F: CVFF(F)",
 +/* 50 */	"P: CVUP(U)",
 +/* 51 */	"P: CVPP(P)",
 +/* 52 */	"F: NEGF(F)",
 +/* 53 */	"I: NEGI(I)",
 +/* 54 */	"V: CALLB(P,P)",
 +/* 55 */	"F: CALLF(P)",
 +/* 56 */	"I: CALLI(P)",
 +/* 57 */	"U: CALLU(P)",
 +/* 58 */	"P: CALLP(P)",
 +/* 59 */	"V: CALLV(P)",
 +/* 60 */	"V: RETF(F)",
 +/* 61 */	"V: RETI(I)",
 +/* 62 */	"V: RETU(U)",
 +/* 63 */	"V: RETP(P)",
 +/* 64 */	"V: RETV",
 +/* 65 */	"P: ADDRGP",
 +/* 66 */	"P: ADDRFP",
 +/* 67 */	"P: ADDRLP",
 +/* 68 */	"F: ADDF(F,F)",
 +/* 69 */	"I: ADDI(I,I)",
 +/* 70 */	"P: ADDP(P,I)",
 +/* 71 */	"P: ADDP(I,P)",
 +/* 72 */	"P: ADDP(U,P)",
 +/* 73 */	"P: ADDP(P,U)",
 +/* 74 */	"U: ADDU(U,U)",
 +/* 75 */	"F: SUBF(F,F)",
 +/* 76 */	"I: SUBI(I,I)",
 +/* 77 */	"P: SUBP(P,I)",
 +/* 78 */	"P: SUBP(P,U)",
 +/* 79 */	"U: SUBU(U,U)",
 +/* 80 */	"I: LSHI(I,I)",
 +/* 81 */	"U: LSHU(U,I)",
 +/* 82 */	"I: MODI(I,I)",
 +/* 83 */	"U: MODU(U,U)",
 +/* 84 */	"I: RSHI(I,I)",
 +/* 85 */	"U: RSHU(U,I)",
 +/* 86 */	"U: BANDU(U,U)",
 +/* 87 */	"I: BANDI(I,I)",
 +/* 88 */	"U: BCOMU(U)",
 +/* 89 */	"I: BCOMI(I)",
 +/* 90 */	"I: BORI(I,I)",
 +/* 91 */	"U: BORU(U,U)",
 +/* 92 */	"U: BXORU(U,U)",
 +/* 93 */	"I: BXORI(I,I)",
 +/* 94 */	"F: DIVF(F,F)",
 +/* 95 */	"I: DIVI(I,I)",
 +/* 96 */	"U: DIVU(U,U)",
 +/* 97 */	"F: MULF(F,F)",
 +/* 98 */	"I: MULI(I,I)",
 +/* 99 */	"U: MULU(U,U)",
 +/* 100 */	"V: EQF(F,F)",
 +/* 101 */	"V: EQI(I,I)",
 +/* 102 */	"V: EQU(U,U)",
 +/* 103 */	"V: GEF(F,F)",
 +/* 104 */	"V: GEI(I,I)",
 +/* 105 */	"V: GEU(U,U)",
 +/* 106 */	"V: GTF(F,F)",
 +/* 107 */	"V: GTI(I,I)",
 +/* 108 */	"V: GTU(U,U)",
 +/* 109 */	"V: LEF(F,F)",
 +/* 110 */	"V: LEI(I,I)",
 +/* 111 */	"V: LEU(U,U)",
 +/* 112 */	"V: LTF(F,F)",
 +/* 113 */	"V: LTI(I,I)",
 +/* 114 */	"V: LTU(U,U)",
 +/* 115 */	"V: NEF(F,F)",
 +/* 116 */	"V: NEI(I,I)",
 +/* 117 */	"V: NEU(U,U)",
 +/* 118 */	"V: JUMPV(P)",
 +/* 119 */	"V: LABELV",
 +};
 +
 +static short _decode_stmt[] = {
 +	0,
 +	1,
 +	2,
 +	3,
 +	4,
 +	5,
 +	6,
 +	7,
 +	8,
 +	9,
 +	10,
 +};
 +
 +static short _decode_P[] = {
 +	0,
 +	19,
 +	25,
 +	41,
 +	50,
 +	51,
 +	58,
 +	65,
 +	66,
 +	67,
 +	70,
 +	71,
 +	72,
 +	73,
 +	77,
 +	78,
 +};
 +
 +static short _decode_V[] = {
 +	0,
 +	22,
 +	27,
 +	28,
 +	29,
 +	30,
 +	31,
 +	32,
 +	33,
 +	34,
 +	35,
 +	36,
 +	54,
 +	59,
 +	60,
 +	61,
 +	62,
 +	63,
 +	64,
 +	100,
 +	101,
 +	102,
 +	103,
 +	104,
 +	105,
 +	106,
 +	107,
 +	108,
 +	109,
 +	110,
 +	111,
 +	112,
 +	113,
 +	114,
 +	115,
 +	116,
 +	117,
 +	118,
 +	119,
 +};
 +
 +static short _decode_bogus[] = {
 +	0,
 +	11,
 +	12,
 +	13,
 +	14,
 +	15,
 +	16,
 +};
 +
 +static short _decode_I[] = {
 +	0,
 +	17,
 +	24,
 +	39,
 +	42,
 +	43,
 +	44,
 +	53,
 +	56,
 +	69,
 +	76,
 +	80,
 +	82,
 +	84,
 +	87,
 +	89,
 +	90,
 +	93,
 +	95,
 +	98,
 +};
 +
 +static short _decode_U[] = {
 +	0,
 +	18,
 +	26,
 +	40,
 +	45,
 +	46,
 +	47,
 +	57,
 +	74,
 +	79,
 +	81,
 +	83,
 +	85,
 +	86,
 +	88,
 +	91,
 +	92,
 +	96,
 +	99,
 +};
 +
 +static short _decode_F[] = {
 +	0,
 +	20,
 +	23,
 +	38,
 +	48,
 +	49,
 +	52,
 +	55,
 +	68,
 +	75,
 +	94,
 +	97,
 +};
 +
 +static short _decode_B[] = {
 +	0,
 +	21,
 +	37,
 +};
 +
 +static int _rule(void *state, int goalnt) {
 +	if (goalnt < 1 || goalnt > 8)
 +		fatal("_rule", "Bad goal nonterminal %d\n", goalnt);
 +	if (!state)
 +		return 0;
 +	switch (goalnt) {
 +	case _stmt_NT:	return _decode_stmt[((struct _state *)state)->rule._stmt];
 +	case _P_NT:	return _decode_P[((struct _state *)state)->rule._P];
 +	case _V_NT:	return _decode_V[((struct _state *)state)->rule._V];
 +	case _bogus_NT:	return _decode_bogus[((struct _state *)state)->rule._bogus];
 +	case _I_NT:	return _decode_I[((struct _state *)state)->rule._I];
 +	case _U_NT:	return _decode_U[((struct _state *)state)->rule._U];
 +	case _F_NT:	return _decode_F[((struct _state *)state)->rule._F];
 +	case _B_NT:	return _decode_B[((struct _state *)state)->rule._B];
 +	default:
 +		fatal("_rule", "Bad goal nonterminal %d\n", goalnt);
 +		return 0;
 +	}
 +}
 +
 +static void _closure_P(NODEPTR_TYPE, int);
 +static void _closure_V(NODEPTR_TYPE, int);
 +static void _closure_bogus(NODEPTR_TYPE, int);
 +static void _closure_I(NODEPTR_TYPE, int);
 +static void _closure_U(NODEPTR_TYPE, int);
 +static void _closure_F(NODEPTR_TYPE, int);
 +static void _closure_B(NODEPTR_TYPE, int);
 +
 +static void _closure_P(NODEPTR_TYPE a, int c) {
 +	struct _state *p = STATE_LABEL(a);
 +	if (c + 1 < p->cost[_bogus_NT]) {
 +		p->cost[_bogus_NT] = c + 1;
 +		p->rule._bogus = 3;
 +		_closure_bogus(a, c + 1);
 +	}
 +}
 +
 +static void _closure_V(NODEPTR_TYPE a, int c) {
 +	struct _state *p = STATE_LABEL(a);
 +	if (c + 1 < p->cost[_bogus_NT]) {
 +		p->cost[_bogus_NT] = c + 1;
 +		p->rule._bogus = 6;
 +		_closure_bogus(a, c + 1);
 +	}
 +	if (c + 0 < p->cost[_stmt_NT]) {
 +		p->cost[_stmt_NT] = c + 0;
 +		p->rule._stmt = 10;
 +	}
 +}
 +
 +static void _closure_bogus(NODEPTR_TYPE a, int c) {
 +	struct _state *p = STATE_LABEL(a);
 +	if (c + 1 < p->cost[_V_NT]) {
 +		p->cost[_V_NT] = c + 1;
 +		p->rule._V = 1;
 +		_closure_V(a, c + 1);
 +	}
 +	if (c + 1 < p->cost[_B_NT]) {
 +		p->cost[_B_NT] = c + 1;
 +		p->rule._B = 1;
 +		_closure_B(a, c + 1);
 +	}
 +	if (c + 1 < p->cost[_F_NT]) {
 +		p->cost[_F_NT] = c + 1;
 +		p->rule._F = 1;
 +		_closure_F(a, c + 1);
 +	}
 +	if (c + 1 < p->cost[_P_NT]) {
 +		p->cost[_P_NT] = c + 1;
 +		p->rule._P = 1;
 +		_closure_P(a, c + 1);
 +	}
 +	if (c + 1 < p->cost[_U_NT]) {
 +		p->cost[_U_NT] = c + 1;
 +		p->rule._U = 1;
 +		_closure_U(a, c + 1);
 +	}
 +	if (c + 1 < p->cost[_I_NT]) {
 +		p->cost[_I_NT] = c + 1;
 +		p->rule._I = 1;
 +		_closure_I(a, c + 1);
 +	}
 +}
 +
 +static void _closure_I(NODEPTR_TYPE a, int c) {
 +	struct _state *p = STATE_LABEL(a);
 +	if (c + 1 < p->cost[_bogus_NT]) {
 +		p->cost[_bogus_NT] = c + 1;
 +		p->rule._bogus = 1;
 +		_closure_bogus(a, c + 1);
 +	}
 +}
 +
 +static void _closure_U(NODEPTR_TYPE a, int c) {
 +	struct _state *p = STATE_LABEL(a);
 +	if (c + 1 < p->cost[_bogus_NT]) {
 +		p->cost[_bogus_NT] = c + 1;
 +		p->rule._bogus = 2;
 +		_closure_bogus(a, c + 1);
 +	}
 +}
 +
 +static void _closure_F(NODEPTR_TYPE a, int c) {
 +	struct _state *p = STATE_LABEL(a);
 +	if (c + 1 < p->cost[_bogus_NT]) {
 +		p->cost[_bogus_NT] = c + 1;
 +		p->rule._bogus = 4;
 +		_closure_bogus(a, c + 1);
 +	}
 +}
 +
 +static void _closure_B(NODEPTR_TYPE a, int c) {
 +	struct _state *p = STATE_LABEL(a);
 +	if (c + 1 < p->cost[_bogus_NT]) {
 +		p->cost[_bogus_NT] = c + 1;
 +		p->rule._bogus = 5;
 +		_closure_bogus(a, c + 1);
 +	}
 +}
 +
 +static void _label(NODEPTR_TYPE a) {
 +	int c;
 +	struct _state *p;
 +
 +	if (!a)
 +		fatal("_label", "Null tree\n", 0);
 +	STATE_LABEL(a) = p = allocate(sizeof *p, FUNC);
 +	p->rule._stmt = 0;
 +	p->cost[1] =
 +	p->cost[2] =
 +	p->cost[3] =
 +	p->cost[4] =
 +	p->cost[5] =
 +	p->cost[6] =
 +	p->cost[7] =
 +	p->cost[8] =
 +		0x7fff;
 +	switch (OP_LABEL(a)) {
 +	case 17: /* CNSTF */
 +		/* F: CNSTF */
 +		if (0 + 0 < p->cost[_F_NT]) {
 +			p->cost[_F_NT] = 0 + 0;
 +			p->rule._F = 2;
 +			_closure_F(a, 0 + 0);
 +		}
 +		break;
 +	case 21: /* CNSTI */
 +		/* I: CNSTI */
 +		if (0 + 0 < p->cost[_I_NT]) {
 +			p->cost[_I_NT] = 0 + 0;
 +			p->rule._I = 2;
 +			_closure_I(a, 0 + 0);
 +		}
 +		break;
 +	case 22: /* CNSTU */
 +		/* U: CNSTU */
 +		if (0 + 0 < p->cost[_U_NT]) {
 +			p->cost[_U_NT] = 0 + 0;
 +			p->rule._U = 2;
 +			_closure_U(a, 0 + 0);
 +		}
 +		break;
 +	case 23: /* CNSTP */
 +		/* P: CNSTP */
 +		if (0 + 0 < p->cost[_P_NT]) {
 +			p->cost[_P_NT] = 0 + 0;
 +			p->rule._P = 2;
 +			_closure_P(a, 0 + 0);
 +		}
 +		break;
 +	case 33: /* ARGF */
 +		_label(LEFT_CHILD(a));
 +		/* V: ARGF(F) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_F_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 3;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 37: /* ARGI */
 +		_label(LEFT_CHILD(a));
 +		/* V: ARGI(I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 4;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 38: /* ARGU */
 +		_label(LEFT_CHILD(a));
 +		/* V: ARGU(U) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_U_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 5;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 39: /* ARGP */
 +		_label(LEFT_CHILD(a));
 +		/* V: ARGP(P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 6;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 41: /* ARGB */
 +		_label(LEFT_CHILD(a));
 +		/* V: ARGB(B) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_B_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 2;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 49: /* ASGNF */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* V: ASGNF(P,F) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_F_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 8;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 53: /* ASGNI */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* V: ASGNI(P,I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 9;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 54: /* ASGNU */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* V: ASGNU(P,U) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_U_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 10;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 55: /* ASGNP */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* V: ASGNP(P,P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 11;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 57: /* ASGNB */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* V: ASGNB(P,B) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_B_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 7;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 65: /* INDIRF */
 +		_label(LEFT_CHILD(a));
 +		/* stmt: INDIRF(P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_stmt_NT]) {
 +			p->cost[_stmt_NT] = c + 0;
 +			p->rule._stmt = 2;
 +		}
 +		/* F: INDIRF(P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_F_NT]) {
 +			p->cost[_F_NT] = c + 0;
 +			p->rule._F = 3;
 +			_closure_F(a, c + 0);
 +		}
 +		break;
 +	case 69: /* INDIRI */
 +		_label(LEFT_CHILD(a));
 +		/* stmt: INDIRI(P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_stmt_NT]) {
 +			p->cost[_stmt_NT] = c + 0;
 +			p->rule._stmt = 3;
 +		}
 +		/* I: INDIRI(P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_I_NT]) {
 +			p->cost[_I_NT] = c + 0;
 +			p->rule._I = 3;
 +			_closure_I(a, c + 0);
 +		}
 +		break;
 +	case 70: /* INDIRU */
 +		_label(LEFT_CHILD(a));
 +		/* stmt: INDIRU(P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_stmt_NT]) {
 +			p->cost[_stmt_NT] = c + 0;
 +			p->rule._stmt = 4;
 +		}
 +		/* U: INDIRU(P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_U_NT]) {
 +			p->cost[_U_NT] = c + 0;
 +			p->rule._U = 3;
 +			_closure_U(a, c + 0);
 +		}
 +		break;
 +	case 71: /* INDIRP */
 +		_label(LEFT_CHILD(a));
 +		/* stmt: INDIRP(P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_stmt_NT]) {
 +			p->cost[_stmt_NT] = c + 0;
 +			p->rule._stmt = 5;
 +		}
 +		/* P: INDIRP(P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_P_NT]) {
 +			p->cost[_P_NT] = c + 0;
 +			p->rule._P = 3;
 +			_closure_P(a, c + 0);
 +		}
 +		break;
 +	case 73: /* INDIRB */
 +		_label(LEFT_CHILD(a));
 +		/* stmt: INDIRB(P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_stmt_NT]) {
 +			p->cost[_stmt_NT] = c + 0;
 +			p->rule._stmt = 1;
 +		}
 +		/* B: INDIRB(P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_B_NT]) {
 +			p->cost[_B_NT] = c + 0;
 +			p->rule._B = 2;
 +			_closure_B(a, c + 0);
 +		}
 +		break;
 +	case 113: /* CVFF */
 +		_label(LEFT_CHILD(a));
 +		/* F: CVFF(F) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_F_NT] + 0;
 +		if (c + 0 < p->cost[_F_NT]) {
 +			p->cost[_F_NT] = c + 0;
 +			p->rule._F = 5;
 +			_closure_F(a, c + 0);
 +		}
 +		break;
 +	case 117: /* CVFI */
 +		_label(LEFT_CHILD(a));
 +		/* I: CVFI(F) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_F_NT] + 0;
 +		if (c + 0 < p->cost[_I_NT]) {
 +			p->cost[_I_NT] = c + 0;
 +			p->rule._I = 6;
 +			_closure_I(a, c + 0);
 +		}
 +		break;
 +	case 129: /* CVIF */
 +		_label(LEFT_CHILD(a));
 +		/* F: CVIF(I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_F_NT]) {
 +			p->cost[_F_NT] = c + 0;
 +			p->rule._F = 4;
 +			_closure_F(a, c + 0);
 +		}
 +		break;
 +	case 133: /* CVII */
 +		_label(LEFT_CHILD(a));
 +		/* I: CVII(I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_I_NT]) {
 +			p->cost[_I_NT] = c + 0;
 +			p->rule._I = 4;
 +			_closure_I(a, c + 0);
 +		}
 +		break;
 +	case 134: /* CVIU */
 +		_label(LEFT_CHILD(a));
 +		/* U: CVIU(I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_U_NT]) {
 +			p->cost[_U_NT] = c + 0;
 +			p->rule._U = 4;
 +			_closure_U(a, c + 0);
 +		}
 +		break;
 +	case 150: /* CVPU */
 +		_label(LEFT_CHILD(a));
 +		/* U: CVPU(P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_U_NT]) {
 +			p->cost[_U_NT] = c + 0;
 +			p->rule._U = 6;
 +			_closure_U(a, c + 0);
 +		}
 +		break;
 +	case 151: /* CVPP */
 +		_label(LEFT_CHILD(a));
 +		/* P: CVPP(P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_P_NT]) {
 +			p->cost[_P_NT] = c + 0;
 +			p->rule._P = 5;
 +			_closure_P(a, c + 0);
 +		}
 +		break;
 +	case 181: /* CVUI */
 +		_label(LEFT_CHILD(a));
 +		/* I: CVUI(U) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_U_NT] + 0;
 +		if (c + 0 < p->cost[_I_NT]) {
 +			p->cost[_I_NT] = c + 0;
 +			p->rule._I = 5;
 +			_closure_I(a, c + 0);
 +		}
 +		break;
 +	case 182: /* CVUU */
 +		_label(LEFT_CHILD(a));
 +		/* U: CVUU(U) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_U_NT] + 0;
 +		if (c + 0 < p->cost[_U_NT]) {
 +			p->cost[_U_NT] = c + 0;
 +			p->rule._U = 5;
 +			_closure_U(a, c + 0);
 +		}
 +		break;
 +	case 183: /* CVUP */
 +		_label(LEFT_CHILD(a));
 +		/* P: CVUP(U) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_U_NT] + 0;
 +		if (c + 0 < p->cost[_P_NT]) {
 +			p->cost[_P_NT] = c + 0;
 +			p->rule._P = 4;
 +			_closure_P(a, c + 0);
 +		}
 +		break;
 +	case 193: /* NEGF */
 +		_label(LEFT_CHILD(a));
 +		/* F: NEGF(F) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_F_NT] + 0;
 +		if (c + 0 < p->cost[_F_NT]) {
 +			p->cost[_F_NT] = c + 0;
 +			p->rule._F = 6;
 +			_closure_F(a, c + 0);
 +		}
 +		break;
 +	case 197: /* NEGI */
 +		_label(LEFT_CHILD(a));
 +		/* I: NEGI(I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_I_NT]) {
 +			p->cost[_I_NT] = c + 0;
 +			p->rule._I = 7;
 +			_closure_I(a, c + 0);
 +		}
 +		break;
 +	case 209: /* CALLF */
 +		_label(LEFT_CHILD(a));
 +		/* stmt: CALLF(P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_stmt_NT]) {
 +			p->cost[_stmt_NT] = c + 0;
 +			p->rule._stmt = 6;
 +		}
 +		/* F: CALLF(P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_F_NT]) {
 +			p->cost[_F_NT] = c + 0;
 +			p->rule._F = 7;
 +			_closure_F(a, c + 0);
 +		}
 +		break;
 +	case 213: /* CALLI */
 +		_label(LEFT_CHILD(a));
 +		/* stmt: CALLI(P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_stmt_NT]) {
 +			p->cost[_stmt_NT] = c + 0;
 +			p->rule._stmt = 7;
 +		}
 +		/* I: CALLI(P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_I_NT]) {
 +			p->cost[_I_NT] = c + 0;
 +			p->rule._I = 8;
 +			_closure_I(a, c + 0);
 +		}
 +		break;
 +	case 214: /* CALLU */
 +		_label(LEFT_CHILD(a));
 +		/* stmt: CALLU(P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_stmt_NT]) {
 +			p->cost[_stmt_NT] = c + 0;
 +			p->rule._stmt = 8;
 +		}
 +		/* U: CALLU(P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_U_NT]) {
 +			p->cost[_U_NT] = c + 0;
 +			p->rule._U = 7;
 +			_closure_U(a, c + 0);
 +		}
 +		break;
 +	case 215: /* CALLP */
 +		_label(LEFT_CHILD(a));
 +		/* stmt: CALLP(P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_stmt_NT]) {
 +			p->cost[_stmt_NT] = c + 0;
 +			p->rule._stmt = 9;
 +		}
 +		/* P: CALLP(P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_P_NT]) {
 +			p->cost[_P_NT] = c + 0;
 +			p->rule._P = 6;
 +			_closure_P(a, c + 0);
 +		}
 +		break;
 +	case 216: /* CALLV */
 +		_label(LEFT_CHILD(a));
 +		/* V: CALLV(P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 13;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 217: /* CALLB */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* V: CALLB(P,P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 12;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 241: /* RETF */
 +		_label(LEFT_CHILD(a));
 +		/* V: RETF(F) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_F_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 14;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 245: /* RETI */
 +		_label(LEFT_CHILD(a));
 +		/* V: RETI(I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 15;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 246: /* RETU */
 +		_label(LEFT_CHILD(a));
 +		/* V: RETU(U) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_U_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 16;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 247: /* RETP */
 +		_label(LEFT_CHILD(a));
 +		/* V: RETP(P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 17;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 248: /* RETV */
 +		/* V: RETV */
 +		if (0 + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = 0 + 0;
 +			p->rule._V = 18;
 +			_closure_V(a, 0 + 0);
 +		}
 +		break;
 +	case 263: /* ADDRGP */
 +		/* P: ADDRGP */
 +		if (0 + 0 < p->cost[_P_NT]) {
 +			p->cost[_P_NT] = 0 + 0;
 +			p->rule._P = 7;
 +			_closure_P(a, 0 + 0);
 +		}
 +		break;
 +	case 279: /* ADDRFP */
 +		/* P: ADDRFP */
 +		if (0 + 0 < p->cost[_P_NT]) {
 +			p->cost[_P_NT] = 0 + 0;
 +			p->rule._P = 8;
 +			_closure_P(a, 0 + 0);
 +		}
 +		break;
 +	case 295: /* ADDRLP */
 +		/* P: ADDRLP */
 +		if (0 + 0 < p->cost[_P_NT]) {
 +			p->cost[_P_NT] = 0 + 0;
 +			p->rule._P = 9;
 +			_closure_P(a, 0 + 0);
 +		}
 +		break;
 +	case 305: /* ADDF */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* F: ADDF(F,F) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_F_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_F_NT] + 0;
 +		if (c + 0 < p->cost[_F_NT]) {
 +			p->cost[_F_NT] = c + 0;
 +			p->rule._F = 8;
 +			_closure_F(a, c + 0);
 +		}
 +		break;
 +	case 309: /* ADDI */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* I: ADDI(I,I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_I_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_I_NT]) {
 +			p->cost[_I_NT] = c + 0;
 +			p->rule._I = 9;
 +			_closure_I(a, c + 0);
 +		}
 +		break;
 +	case 310: /* ADDU */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* U: ADDU(U,U) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_U_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_U_NT] + 0;
 +		if (c + 0 < p->cost[_U_NT]) {
 +			p->cost[_U_NT] = c + 0;
 +			p->rule._U = 8;
 +			_closure_U(a, c + 0);
 +		}
 +		break;
 +	case 311: /* ADDP */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* P: ADDP(P,I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_P_NT]) {
 +			p->cost[_P_NT] = c + 0;
 +			p->rule._P = 10;
 +			_closure_P(a, c + 0);
 +		}
 +		/* P: ADDP(I,P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_I_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_P_NT]) {
 +			p->cost[_P_NT] = c + 0;
 +			p->rule._P = 11;
 +			_closure_P(a, c + 0);
 +		}
 +		/* P: ADDP(U,P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_U_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_P_NT]) {
 +			p->cost[_P_NT] = c + 0;
 +			p->rule._P = 12;
 +			_closure_P(a, c + 0);
 +		}
 +		/* P: ADDP(P,U) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_U_NT] + 0;
 +		if (c + 0 < p->cost[_P_NT]) {
 +			p->cost[_P_NT] = c + 0;
 +			p->rule._P = 13;
 +			_closure_P(a, c + 0);
 +		}
 +		break;
 +	case 321: /* SUBF */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* F: SUBF(F,F) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_F_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_F_NT] + 0;
 +		if (c + 0 < p->cost[_F_NT]) {
 +			p->cost[_F_NT] = c + 0;
 +			p->rule._F = 9;
 +			_closure_F(a, c + 0);
 +		}
 +		break;
 +	case 325: /* SUBI */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* I: SUBI(I,I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_I_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_I_NT]) {
 +			p->cost[_I_NT] = c + 0;
 +			p->rule._I = 10;
 +			_closure_I(a, c + 0);
 +		}
 +		break;
 +	case 326: /* SUBU */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* U: SUBU(U,U) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_U_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_U_NT] + 0;
 +		if (c + 0 < p->cost[_U_NT]) {
 +			p->cost[_U_NT] = c + 0;
 +			p->rule._U = 9;
 +			_closure_U(a, c + 0);
 +		}
 +		break;
 +	case 327: /* SUBP */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* P: SUBP(P,I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_P_NT]) {
 +			p->cost[_P_NT] = c + 0;
 +			p->rule._P = 14;
 +			_closure_P(a, c + 0);
 +		}
 +		/* P: SUBP(P,U) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_U_NT] + 0;
 +		if (c + 0 < p->cost[_P_NT]) {
 +			p->cost[_P_NT] = c + 0;
 +			p->rule._P = 15;
 +			_closure_P(a, c + 0);
 +		}
 +		break;
 +	case 341: /* LSHI */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* I: LSHI(I,I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_I_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_I_NT]) {
 +			p->cost[_I_NT] = c + 0;
 +			p->rule._I = 11;
 +			_closure_I(a, c + 0);
 +		}
 +		break;
 +	case 342: /* LSHU */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* U: LSHU(U,I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_U_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_U_NT]) {
 +			p->cost[_U_NT] = c + 0;
 +			p->rule._U = 10;
 +			_closure_U(a, c + 0);
 +		}
 +		break;
 +	case 357: /* MODI */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* I: MODI(I,I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_I_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_I_NT]) {
 +			p->cost[_I_NT] = c + 0;
 +			p->rule._I = 12;
 +			_closure_I(a, c + 0);
 +		}
 +		break;
 +	case 358: /* MODU */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* U: MODU(U,U) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_U_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_U_NT] + 0;
 +		if (c + 0 < p->cost[_U_NT]) {
 +			p->cost[_U_NT] = c + 0;
 +			p->rule._U = 11;
 +			_closure_U(a, c + 0);
 +		}
 +		break;
 +	case 373: /* RSHI */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* I: RSHI(I,I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_I_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_I_NT]) {
 +			p->cost[_I_NT] = c + 0;
 +			p->rule._I = 13;
 +			_closure_I(a, c + 0);
 +		}
 +		break;
 +	case 374: /* RSHU */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* U: RSHU(U,I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_U_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_U_NT]) {
 +			p->cost[_U_NT] = c + 0;
 +			p->rule._U = 12;
 +			_closure_U(a, c + 0);
 +		}
 +		break;
 +	case 389: /* BANDI */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* I: BANDI(I,I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_I_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_I_NT]) {
 +			p->cost[_I_NT] = c + 0;
 +			p->rule._I = 14;
 +			_closure_I(a, c + 0);
 +		}
 +		break;
 +	case 390: /* BANDU */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* U: BANDU(U,U) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_U_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_U_NT] + 0;
 +		if (c + 0 < p->cost[_U_NT]) {
 +			p->cost[_U_NT] = c + 0;
 +			p->rule._U = 13;
 +			_closure_U(a, c + 0);
 +		}
 +		break;
 +	case 405: /* BCOMI */
 +		_label(LEFT_CHILD(a));
 +		/* I: BCOMI(I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_I_NT]) {
 +			p->cost[_I_NT] = c + 0;
 +			p->rule._I = 15;
 +			_closure_I(a, c + 0);
 +		}
 +		break;
 +	case 406: /* BCOMU */
 +		_label(LEFT_CHILD(a));
 +		/* U: BCOMU(U) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_U_NT] + 0;
 +		if (c + 0 < p->cost[_U_NT]) {
 +			p->cost[_U_NT] = c + 0;
 +			p->rule._U = 14;
 +			_closure_U(a, c + 0);
 +		}
 +		break;
 +	case 421: /* BORI */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* I: BORI(I,I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_I_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_I_NT]) {
 +			p->cost[_I_NT] = c + 0;
 +			p->rule._I = 16;
 +			_closure_I(a, c + 0);
 +		}
 +		break;
 +	case 422: /* BORU */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* U: BORU(U,U) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_U_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_U_NT] + 0;
 +		if (c + 0 < p->cost[_U_NT]) {
 +			p->cost[_U_NT] = c + 0;
 +			p->rule._U = 15;
 +			_closure_U(a, c + 0);
 +		}
 +		break;
 +	case 437: /* BXORI */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* I: BXORI(I,I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_I_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_I_NT]) {
 +			p->cost[_I_NT] = c + 0;
 +			p->rule._I = 17;
 +			_closure_I(a, c + 0);
 +		}
 +		break;
 +	case 438: /* BXORU */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* U: BXORU(U,U) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_U_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_U_NT] + 0;
 +		if (c + 0 < p->cost[_U_NT]) {
 +			p->cost[_U_NT] = c + 0;
 +			p->rule._U = 16;
 +			_closure_U(a, c + 0);
 +		}
 +		break;
 +	case 449: /* DIVF */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* F: DIVF(F,F) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_F_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_F_NT] + 0;
 +		if (c + 0 < p->cost[_F_NT]) {
 +			p->cost[_F_NT] = c + 0;
 +			p->rule._F = 10;
 +			_closure_F(a, c + 0);
 +		}
 +		break;
 +	case 453: /* DIVI */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* I: DIVI(I,I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_I_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_I_NT]) {
 +			p->cost[_I_NT] = c + 0;
 +			p->rule._I = 18;
 +			_closure_I(a, c + 0);
 +		}
 +		break;
 +	case 454: /* DIVU */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* U: DIVU(U,U) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_U_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_U_NT] + 0;
 +		if (c + 0 < p->cost[_U_NT]) {
 +			p->cost[_U_NT] = c + 0;
 +			p->rule._U = 17;
 +			_closure_U(a, c + 0);
 +		}
 +		break;
 +	case 465: /* MULF */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* F: MULF(F,F) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_F_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_F_NT] + 0;
 +		if (c + 0 < p->cost[_F_NT]) {
 +			p->cost[_F_NT] = c + 0;
 +			p->rule._F = 11;
 +			_closure_F(a, c + 0);
 +		}
 +		break;
 +	case 469: /* MULI */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* I: MULI(I,I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_I_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_I_NT]) {
 +			p->cost[_I_NT] = c + 0;
 +			p->rule._I = 19;
 +			_closure_I(a, c + 0);
 +		}
 +		break;
 +	case 470: /* MULU */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* U: MULU(U,U) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_U_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_U_NT] + 0;
 +		if (c + 0 < p->cost[_U_NT]) {
 +			p->cost[_U_NT] = c + 0;
 +			p->rule._U = 18;
 +			_closure_U(a, c + 0);
 +		}
 +		break;
 +	case 481: /* EQF */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* V: EQF(F,F) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_F_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_F_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 19;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 485: /* EQI */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* V: EQI(I,I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_I_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 20;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 486: /* EQU */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* V: EQU(U,U) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_U_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_U_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 21;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 497: /* GEF */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* V: GEF(F,F) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_F_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_F_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 22;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 501: /* GEI */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* V: GEI(I,I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_I_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 23;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 502: /* GEU */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* V: GEU(U,U) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_U_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_U_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 24;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 513: /* GTF */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* V: GTF(F,F) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_F_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_F_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 25;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 517: /* GTI */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* V: GTI(I,I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_I_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 26;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 518: /* GTU */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* V: GTU(U,U) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_U_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_U_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 27;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 529: /* LEF */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* V: LEF(F,F) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_F_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_F_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 28;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 533: /* LEI */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* V: LEI(I,I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_I_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 29;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 534: /* LEU */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* V: LEU(U,U) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_U_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_U_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 30;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 545: /* LTF */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* V: LTF(F,F) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_F_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_F_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 31;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 549: /* LTI */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* V: LTI(I,I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_I_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 32;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 550: /* LTU */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* V: LTU(U,U) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_U_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_U_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 33;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 561: /* NEF */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* V: NEF(F,F) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_F_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_F_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 34;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 565: /* NEI */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* V: NEI(I,I) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_I_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_I_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 35;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 566: /* NEU */
 +		_label(LEFT_CHILD(a));
 +		_label(RIGHT_CHILD(a));
 +		/* V: NEU(U,U) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_U_NT] + ((struct _state *)(RIGHT_CHILD(a)->x.state))->cost[_U_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 36;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 584: /* JUMPV */
 +		_label(LEFT_CHILD(a));
 +		/* V: JUMPV(P) */
 +		c = ((struct _state *)(LEFT_CHILD(a)->x.state))->cost[_P_NT] + 0;
 +		if (c + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = c + 0;
 +			p->rule._V = 37;
 +			_closure_V(a, c + 0);
 +		}
 +		break;
 +	case 600: /* LABELV */
 +		/* V: LABELV */
 +		if (0 + 0 < p->cost[_V_NT]) {
 +			p->cost[_V_NT] = 0 + 0;
 +			p->rule._V = 38;
 +			_closure_V(a, 0 + 0);
 +		}
 +		break;
 +	default:
 +		fatal("_label", "Bad terminal %d\n", OP_LABEL(a));
 +	}
 +}
 +
 +static void _kids(NODEPTR_TYPE p, int eruleno, NODEPTR_TYPE kids[]) {
 +	if (!p)
 +		fatal("_kids", "Null tree\n", 0);
 +	if (!kids)
 +		fatal("_kids", "Null kids\n", 0);
 +	switch (eruleno) {
 +	case 118: /* V: JUMPV(P) */
 +	case 89: /* I: BCOMI(I) */
 +	case 88: /* U: BCOMU(U) */
 +	case 63: /* V: RETP(P) */
 +	case 62: /* V: RETU(U) */
 +	case 61: /* V: RETI(I) */
 +	case 60: /* V: RETF(F) */
 +	case 59: /* V: CALLV(P) */
 +	case 58: /* P: CALLP(P) */
 +	case 57: /* U: CALLU(P) */
 +	case 56: /* I: CALLI(P) */
 +	case 55: /* F: CALLF(P) */
 +	case 53: /* I: NEGI(I) */
 +	case 52: /* F: NEGF(F) */
 +	case 51: /* P: CVPP(P) */
 +	case 50: /* P: CVUP(U) */
 +	case 49: /* F: CVFF(F) */
 +	case 48: /* F: CVIF(I) */
 +	case 47: /* U: CVPU(P) */
 +	case 46: /* U: CVUU(U) */
 +	case 45: /* U: CVIU(I) */
 +	case 44: /* I: CVFI(F) */
 +	case 43: /* I: CVUI(U) */
 +	case 42: /* I: CVII(I) */
 +	case 41: /* P: INDIRP(P) */
 +	case 40: /* U: INDIRU(P) */
 +	case 39: /* I: INDIRI(P) */
 +	case 38: /* F: INDIRF(P) */
 +	case 37: /* B: INDIRB(P) */
 +	case 31: /* V: ARGP(P) */
 +	case 30: /* V: ARGU(U) */
 +	case 29: /* V: ARGI(I) */
 +	case 28: /* V: ARGF(F) */
 +	case 27: /* V: ARGB(B) */
 +	case 9: /* stmt: CALLP(P) */
 +	case 8: /* stmt: CALLU(P) */
 +	case 7: /* stmt: CALLI(P) */
 +	case 6: /* stmt: CALLF(P) */
 +	case 5: /* stmt: INDIRP(P) */
 +	case 4: /* stmt: INDIRU(P) */
 +	case 3: /* stmt: INDIRI(P) */
 +	case 2: /* stmt: INDIRF(P) */
 +	case 1: /* stmt: INDIRB(P) */
 +		kids[0] = LEFT_CHILD(p);
 +		break;
 +	case 22: /* V: bogus */
 +	case 21: /* B: bogus */
 +	case 20: /* F: bogus */
 +	case 19: /* P: bogus */
 +	case 18: /* U: bogus */
 +	case 17: /* I: bogus */
 +	case 16: /* bogus: V */
 +	case 15: /* bogus: B */
 +	case 14: /* bogus: F */
 +	case 13: /* bogus: P */
 +	case 12: /* bogus: U */
 +	case 11: /* bogus: I */
 +	case 10: /* stmt: V */
 +		kids[0] = p;
 +		break;
 +	case 119: /* V: LABELV */
 +	case 67: /* P: ADDRLP */
 +	case 66: /* P: ADDRFP */
 +	case 65: /* P: ADDRGP */
 +	case 64: /* V: RETV */
 +	case 26: /* U: CNSTU */
 +	case 25: /* P: CNSTP */
 +	case 24: /* I: CNSTI */
 +	case 23: /* F: CNSTF */
 +		break;
 +	case 117: /* V: NEU(U,U) */
 +	case 116: /* V: NEI(I,I) */
 +	case 115: /* V: NEF(F,F) */
 +	case 114: /* V: LTU(U,U) */
 +	case 113: /* V: LTI(I,I) */
 +	case 112: /* V: LTF(F,F) */
 +	case 111: /* V: LEU(U,U) */
 +	case 110: /* V: LEI(I,I) */
 +	case 109: /* V: LEF(F,F) */
 +	case 108: /* V: GTU(U,U) */
 +	case 107: /* V: GTI(I,I) */
 +	case 106: /* V: GTF(F,F) */
 +	case 105: /* V: GEU(U,U) */
 +	case 104: /* V: GEI(I,I) */
 +	case 103: /* V: GEF(F,F) */
 +	case 102: /* V: EQU(U,U) */
 +	case 101: /* V: EQI(I,I) */
 +	case 100: /* V: EQF(F,F) */
 +	case 99: /* U: MULU(U,U) */
 +	case 98: /* I: MULI(I,I) */
 +	case 97: /* F: MULF(F,F) */
 +	case 96: /* U: DIVU(U,U) */
 +	case 95: /* I: DIVI(I,I) */
 +	case 94: /* F: DIVF(F,F) */
 +	case 93: /* I: BXORI(I,I) */
 +	case 92: /* U: BXORU(U,U) */
 +	case 91: /* U: BORU(U,U) */
 +	case 90: /* I: BORI(I,I) */
 +	case 87: /* I: BANDI(I,I) */
 +	case 86: /* U: BANDU(U,U) */
 +	case 85: /* U: RSHU(U,I) */
 +	case 84: /* I: RSHI(I,I) */
 +	case 83: /* U: MODU(U,U) */
 +	case 82: /* I: MODI(I,I) */
 +	case 81: /* U: LSHU(U,I) */
 +	case 80: /* I: LSHI(I,I) */
 +	case 79: /* U: SUBU(U,U) */
 +	case 78: /* P: SUBP(P,U) */
 +	case 77: /* P: SUBP(P,I) */
 +	case 76: /* I: SUBI(I,I) */
 +	case 75: /* F: SUBF(F,F) */
 +	case 74: /* U: ADDU(U,U) */
 +	case 73: /* P: ADDP(P,U) */
 +	case 72: /* P: ADDP(U,P) */
 +	case 71: /* P: ADDP(I,P) */
 +	case 70: /* P: ADDP(P,I) */
 +	case 69: /* I: ADDI(I,I) */
 +	case 68: /* F: ADDF(F,F) */
 +	case 54: /* V: CALLB(P,P) */
 +	case 36: /* V: ASGNP(P,P) */
 +	case 35: /* V: ASGNU(P,U) */
 +	case 34: /* V: ASGNI(P,I) */
 +	case 33: /* V: ASGNF(P,F) */
 +	case 32: /* V: ASGNB(P,B) */
 +		kids[0] = LEFT_CHILD(p);
 +		kids[1] = RIGHT_CHILD(p);
 +		break;
 +	default:
 +		fatal("_kids", "Bad rule number %d\n", eruleno);
 +	}
 +}
 +
 +
 +static void reduce(NODEPTR_TYPE p, int goalnt) {
 +	int i, sz = opsize(p->op), rulenumber = _rule(p->x.state, goalnt);
 +	short *nts = _nts[rulenumber];
 +	NODEPTR_TYPE kids[10];
 +
 +	assert(rulenumber);
 +	_kids(p, rulenumber, kids);
 +	for (i = 0; nts[i]; i++)
 +		reduce(kids[i], nts[i]);
 +	switch (optype(p->op)) {
 +#define xx(ty) if (sz == ty->size) return
 +	case I:
 +	case U:
 +		xx(chartype);
 +		xx(shorttype);
 +		xx(inttype);
 +		xx(longtype);
 +		xx(longlong);
 +		break;
 +	case F:
 +		xx(floattype);
 +		xx(doubletype);
 +		xx(longdouble);
 +		break;
 +	case P:
 +		xx(voidptype);
 +		xx(funcptype);
 +		break;
 +	case V:
 +	case B: if (sz == 0) return;
 +#undef xx
 +	}
 +	printdag(p, 2);
 +	assert(0);
 +}
 +
 +void check(Node p) {
 +	struct _state { short cost[1]; };
 +
 +	_label(p);
 +	if (((struct _state *)p->x.state)->cost[1] > 0) {
 +		printdag(p, 2);
 +		assert(0);
 +	}
 +	reduce(p, 1);
 +}
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/dagcheck.d b/src/tools/lcc/build-mingw32-x86/rcc/dagcheck.d new file mode 100644 index 0000000..d85ec02 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/dagcheck.d @@ -0,0 +1,2 @@ +build-mingw32-x86/rcc/dagcheck.o: build-mingw32-x86/rcc/dagcheck.c \
 +  src/c.h src/config.h src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/dagcheck.o b/src/tools/lcc/build-mingw32-x86/rcc/dagcheck.o Binary files differnew file mode 100644 index 0000000..90ef42d --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/dagcheck.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/decl.d b/src/tools/lcc/build-mingw32-x86/rcc/decl.d new file mode 100644 index 0000000..421c4ef --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/decl.d @@ -0,0 +1 @@ +build-mingw32-x86/rcc/decl.o: src/decl.c src/c.h src/config.h src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/decl.o b/src/tools/lcc/build-mingw32-x86/rcc/decl.o Binary files differnew file mode 100644 index 0000000..53ca051 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/decl.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/enode.d b/src/tools/lcc/build-mingw32-x86/rcc/enode.d new file mode 100644 index 0000000..2a1ead7 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/enode.d @@ -0,0 +1,2 @@ +build-mingw32-x86/rcc/enode.o: src/enode.c src/c.h src/config.h \
 +  src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/enode.o b/src/tools/lcc/build-mingw32-x86/rcc/enode.o Binary files differnew file mode 100644 index 0000000..919036a --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/enode.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/error.d b/src/tools/lcc/build-mingw32-x86/rcc/error.d new file mode 100644 index 0000000..d8cfbea --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/error.d @@ -0,0 +1,2 @@ +build-mingw32-x86/rcc/error.o: src/error.c src/c.h src/config.h \
 +  src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/error.o b/src/tools/lcc/build-mingw32-x86/rcc/error.o Binary files differnew file mode 100644 index 0000000..1561a3c --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/error.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/event.d b/src/tools/lcc/build-mingw32-x86/rcc/event.d new file mode 100644 index 0000000..6199ef9 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/event.d @@ -0,0 +1,2 @@ +build-mingw32-x86/rcc/event.o: src/event.c src/c.h src/config.h \
 +  src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/event.o b/src/tools/lcc/build-mingw32-x86/rcc/event.o Binary files differnew file mode 100644 index 0000000..37394fc --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/event.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/expr.d b/src/tools/lcc/build-mingw32-x86/rcc/expr.d new file mode 100644 index 0000000..b74a210 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/expr.d @@ -0,0 +1 @@ +build-mingw32-x86/rcc/expr.o: src/expr.c src/c.h src/config.h src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/expr.o b/src/tools/lcc/build-mingw32-x86/rcc/expr.o Binary files differnew file mode 100644 index 0000000..c383f37 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/expr.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/gen.d b/src/tools/lcc/build-mingw32-x86/rcc/gen.d new file mode 100644 index 0000000..914de8c --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/gen.d @@ -0,0 +1 @@ +build-mingw32-x86/rcc/gen.o: src/gen.c src/c.h src/config.h src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/gen.o b/src/tools/lcc/build-mingw32-x86/rcc/gen.o Binary files differnew file mode 100644 index 0000000..f89b17b --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/gen.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/init.d b/src/tools/lcc/build-mingw32-x86/rcc/init.d new file mode 100644 index 0000000..3e9469d --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/init.d @@ -0,0 +1 @@ +build-mingw32-x86/rcc/init.o: src/init.c src/c.h src/config.h src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/init.o b/src/tools/lcc/build-mingw32-x86/rcc/init.o Binary files differnew file mode 100644 index 0000000..b2715a5 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/init.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/inits.d b/src/tools/lcc/build-mingw32-x86/rcc/inits.d new file mode 100644 index 0000000..8a60745 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/inits.d @@ -0,0 +1 @@ +build-mingw32-x86/rcc/inits.o: src/inits.c
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/inits.o b/src/tools/lcc/build-mingw32-x86/rcc/inits.o Binary files differnew file mode 100644 index 0000000..71d3c66 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/inits.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/input.d b/src/tools/lcc/build-mingw32-x86/rcc/input.d new file mode 100644 index 0000000..c1f8d18 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/input.d @@ -0,0 +1,2 @@ +build-mingw32-x86/rcc/input.o: src/input.c src/c.h src/config.h \
 +  src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/input.o b/src/tools/lcc/build-mingw32-x86/rcc/input.o Binary files differnew file mode 100644 index 0000000..6451477 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/input.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/lex.d b/src/tools/lcc/build-mingw32-x86/rcc/lex.d new file mode 100644 index 0000000..cdd3511 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/lex.d @@ -0,0 +1 @@ +build-mingw32-x86/rcc/lex.o: src/lex.c src/c.h src/config.h src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/lex.o b/src/tools/lcc/build-mingw32-x86/rcc/lex.o Binary files differnew file mode 100644 index 0000000..a8fc969 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/lex.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/list.d b/src/tools/lcc/build-mingw32-x86/rcc/list.d new file mode 100644 index 0000000..958081e --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/list.d @@ -0,0 +1 @@ +build-mingw32-x86/rcc/list.o: src/list.c src/c.h src/config.h src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/list.o b/src/tools/lcc/build-mingw32-x86/rcc/list.o Binary files differnew file mode 100644 index 0000000..c7efee0 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/list.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/main.d b/src/tools/lcc/build-mingw32-x86/rcc/main.d new file mode 100644 index 0000000..79e569f --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/main.d @@ -0,0 +1 @@ +build-mingw32-x86/rcc/main.o: src/main.c src/c.h src/config.h src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/main.o b/src/tools/lcc/build-mingw32-x86/rcc/main.o Binary files differnew file mode 100644 index 0000000..dcf6fba --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/main.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/null.d b/src/tools/lcc/build-mingw32-x86/rcc/null.d new file mode 100644 index 0000000..2265860 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/null.d @@ -0,0 +1 @@ +build-mingw32-x86/rcc/null.o: src/null.c src/c.h src/config.h src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/null.o b/src/tools/lcc/build-mingw32-x86/rcc/null.o Binary files differnew file mode 100644 index 0000000..4ddc94f --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/null.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/output.d b/src/tools/lcc/build-mingw32-x86/rcc/output.d new file mode 100644 index 0000000..9280f5e --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/output.d @@ -0,0 +1,2 @@ +build-mingw32-x86/rcc/output.o: src/output.c src/c.h src/config.h \
 +  src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/output.o b/src/tools/lcc/build-mingw32-x86/rcc/output.o Binary files differnew file mode 100644 index 0000000..20ea67e --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/output.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/prof.d b/src/tools/lcc/build-mingw32-x86/rcc/prof.d new file mode 100644 index 0000000..7e14e65 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/prof.d @@ -0,0 +1 @@ +build-mingw32-x86/rcc/prof.o: src/prof.c src/c.h src/config.h src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/prof.o b/src/tools/lcc/build-mingw32-x86/rcc/prof.o Binary files differnew file mode 100644 index 0000000..f82ba84 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/prof.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/profio.d b/src/tools/lcc/build-mingw32-x86/rcc/profio.d new file mode 100644 index 0000000..0d696e0 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/profio.d @@ -0,0 +1,2 @@ +build-mingw32-x86/rcc/profio.o: src/profio.c src/c.h src/config.h \
 +  src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/profio.o b/src/tools/lcc/build-mingw32-x86/rcc/profio.o Binary files differnew file mode 100644 index 0000000..da6b192 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/profio.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/simp.d b/src/tools/lcc/build-mingw32-x86/rcc/simp.d new file mode 100644 index 0000000..fea121a --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/simp.d @@ -0,0 +1 @@ +build-mingw32-x86/rcc/simp.o: src/simp.c src/c.h src/config.h src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/simp.o b/src/tools/lcc/build-mingw32-x86/rcc/simp.o Binary files differnew file mode 100644 index 0000000..90854b2 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/simp.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/stmt.d b/src/tools/lcc/build-mingw32-x86/rcc/stmt.d new file mode 100644 index 0000000..86a7a3b --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/stmt.d @@ -0,0 +1 @@ +build-mingw32-x86/rcc/stmt.o: src/stmt.c src/c.h src/config.h src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/stmt.o b/src/tools/lcc/build-mingw32-x86/rcc/stmt.o Binary files differnew file mode 100644 index 0000000..381700d --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/stmt.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/string.d b/src/tools/lcc/build-mingw32-x86/rcc/string.d new file mode 100644 index 0000000..ea51f75 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/string.d @@ -0,0 +1,2 @@ +build-mingw32-x86/rcc/string.o: src/string.c src/c.h src/config.h \
 +  src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/string.o b/src/tools/lcc/build-mingw32-x86/rcc/string.o Binary files differnew file mode 100644 index 0000000..2638c66 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/string.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/sym.d b/src/tools/lcc/build-mingw32-x86/rcc/sym.d new file mode 100644 index 0000000..e8c1b32 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/sym.d @@ -0,0 +1 @@ +build-mingw32-x86/rcc/sym.o: src/sym.c src/c.h src/config.h src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/sym.o b/src/tools/lcc/build-mingw32-x86/rcc/sym.o Binary files differnew file mode 100644 index 0000000..289d279 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/sym.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/symbolic.d b/src/tools/lcc/build-mingw32-x86/rcc/symbolic.d new file mode 100644 index 0000000..4efac41 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/symbolic.d @@ -0,0 +1,2 @@ +build-mingw32-x86/rcc/symbolic.o: src/symbolic.c src/c.h src/config.h \
 +  src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/symbolic.o b/src/tools/lcc/build-mingw32-x86/rcc/symbolic.o Binary files differnew file mode 100644 index 0000000..7c8d341 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/symbolic.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/trace.d b/src/tools/lcc/build-mingw32-x86/rcc/trace.d new file mode 100644 index 0000000..a238f08 --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/trace.d @@ -0,0 +1,2 @@ +build-mingw32-x86/rcc/trace.o: src/trace.c src/c.h src/config.h \
 +  src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/trace.o b/src/tools/lcc/build-mingw32-x86/rcc/trace.o Binary files differnew file mode 100644 index 0000000..5bf3e1c --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/trace.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/tree.d b/src/tools/lcc/build-mingw32-x86/rcc/tree.d new file mode 100644 index 0000000..f81779f --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/tree.d @@ -0,0 +1 @@ +build-mingw32-x86/rcc/tree.o: src/tree.c src/c.h src/config.h src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/tree.o b/src/tools/lcc/build-mingw32-x86/rcc/tree.o Binary files differnew file mode 100644 index 0000000..b54093f --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/tree.o diff --git a/src/tools/lcc/build-mingw32-x86/rcc/types.d b/src/tools/lcc/build-mingw32-x86/rcc/types.d new file mode 100644 index 0000000..0232edd --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/types.d @@ -0,0 +1,2 @@ +build-mingw32-x86/rcc/types.o: src/types.c src/c.h src/config.h \
 +  src/token.h
 diff --git a/src/tools/lcc/build-mingw32-x86/rcc/types.o b/src/tools/lcc/build-mingw32-x86/rcc/types.o Binary files differnew file mode 100644 index 0000000..549d66b --- /dev/null +++ b/src/tools/lcc/build-mingw32-x86/rcc/types.o diff --git a/src/tools/lcc/cpp/cpp.c b/src/tools/lcc/cpp/cpp.c new file mode 100644 index 0000000..6739e4d --- /dev/null +++ b/src/tools/lcc/cpp/cpp.c @@ -0,0 +1,322 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <stdarg.h> +#include "cpp.h" + +char rcsid[] = "cpp.c - faked rcsid"; + +#define	OUTS	16384 +char	outbuf[OUTS]; +char	*outp = outbuf; +Source	*cursource; +int	nerrs; +struct	token nltoken = { NL, 0, 0, 0, 1, (uchar*)"\n" }; +char	*curtime; +int	incdepth; +int	ifdepth; +int	ifsatisfied[NIF]; +int	skipping; + + +int +main(int argc, char **argv) +{ +	Tokenrow tr; +	time_t t; +	char ebuf[BUFSIZ]; + +	setbuf(stderr, ebuf); +	t = time(NULL); +	curtime = ctime(&t); +	maketokenrow(3, &tr); +	expandlex(); +	setup(argc, argv); +	fixlex(); +	iniths(); +	genline(); +	process(&tr); +	flushout(); +	fflush(stderr); +	exit(nerrs > 0); +	return 0; +} + +void +process(Tokenrow *trp) +{ +	int anymacros = 0; + +	for (;;) { +		if (trp->tp >= trp->lp) { +			trp->tp = trp->lp = trp->bp; +			outp = outbuf; +			anymacros |= gettokens(trp, 1); +			trp->tp = trp->bp; +		} +		if (trp->tp->type == END) { +			if (--incdepth>=0) { +				if (cursource->ifdepth) +					error(ERROR, +					 "Unterminated conditional in #include"); +				unsetsource(); +				cursource->line += cursource->lineinc; +				trp->tp = trp->lp; +				genline(); +				continue; +			} +			if (ifdepth) +				error(ERROR, "Unterminated #if/#ifdef/#ifndef"); +			break; +		} +		if (trp->tp->type==SHARP) { +			trp->tp += 1; +			control(trp); +		} else if (!skipping && anymacros) +			expandrow(trp, NULL); +		if (skipping) +			setempty(trp); +		puttokens(trp); +		anymacros = 0; +		cursource->line += cursource->lineinc; +		if (cursource->lineinc>1) { +			genline(); +		} +	} +} +	 +void +control(Tokenrow *trp) +{ +	Nlist *np; +	Token *tp; + +	tp = trp->tp; +	if (tp->type!=NAME) { +		if (tp->type==NUMBER) +			goto kline; +		if (tp->type != NL) +			error(ERROR, "Unidentifiable control line"); +		return;			/* else empty line */ +	} +	if ((np = lookup(tp, 0))==NULL || ((np->flag&ISKW)==0 && !skipping)) { +		error(WARNING, "Unknown preprocessor control %t", tp); +		return; +	} +	if (skipping) { +		switch (np->val) { +		case KENDIF: +			if (--ifdepth<skipping) +				skipping = 0; +			--cursource->ifdepth; +			setempty(trp); +			return; + +		case KIFDEF: +		case KIFNDEF: +		case KIF: +			if (++ifdepth >= NIF) +				error(FATAL, "#if too deeply nested"); +			++cursource->ifdepth; +			return; + +		case KELIF: +		case KELSE: +			if (ifdepth<=skipping) +				break; +			return; + +		default: +			return; +		} +	} +	switch (np->val) { +	case KDEFINE: +		dodefine(trp); +		break; + +	case KUNDEF: +		tp += 1; +		if (tp->type!=NAME || trp->lp - trp->bp != 4) { +			error(ERROR, "Syntax error in #undef"); +			break; +		} +		if ((np = lookup(tp, 0)) != NULL) +			np->flag &= ~ISDEFINED; +		break; + +	case KPRAGMA: +		return; + +	case KIFDEF: +	case KIFNDEF: +	case KIF: +		if (++ifdepth >= NIF) +			error(FATAL, "#if too deeply nested"); +		++cursource->ifdepth; +		ifsatisfied[ifdepth] = 0; +		if (eval(trp, np->val)) +			ifsatisfied[ifdepth] = 1; +		else +			skipping = ifdepth; +		break; + +	case KELIF: +		if (ifdepth==0) { +			error(ERROR, "#elif with no #if"); +			return; +		} +		if (ifsatisfied[ifdepth]==2) +			error(ERROR, "#elif after #else"); +		if (eval(trp, np->val)) { +			if (ifsatisfied[ifdepth]) +				skipping = ifdepth; +			else { +				skipping = 0; +				ifsatisfied[ifdepth] = 1; +			} +		} else +			skipping = ifdepth; +		break; + +	case KELSE: +		if (ifdepth==0 || cursource->ifdepth==0) { +			error(ERROR, "#else with no #if"); +			return; +		} +		if (ifsatisfied[ifdepth]==2) +			error(ERROR, "#else after #else"); +		if (trp->lp - trp->bp != 3) +			error(ERROR, "Syntax error in #else"); +		skipping = ifsatisfied[ifdepth]? ifdepth: 0; +		ifsatisfied[ifdepth] = 2; +		break; + +	case KENDIF: +		if (ifdepth==0 || cursource->ifdepth==0) { +			error(ERROR, "#endif with no #if"); +			return; +		} +		--ifdepth; +		--cursource->ifdepth; +		if (trp->lp - trp->bp != 3) +			error(WARNING, "Syntax error in #endif"); +		break; + +	case KERROR: +		trp->tp = tp+1; +		error(WARNING, "#error directive: %r", trp); +		break; + +	case KLINE: +		trp->tp = tp+1; +		expandrow(trp, "<line>"); +		tp = trp->bp+2; +	kline: +		if (tp+1>=trp->lp || tp->type!=NUMBER || tp+3<trp->lp +		 || ((tp+3==trp->lp && ((tp+1)->type!=STRING))||*(tp+1)->t=='L')){ +			error(ERROR, "Syntax error in #line"); +			return; +		} +		cursource->line = atol((char*)tp->t)-1; +		if (cursource->line<0 || cursource->line>=32768) +			error(WARNING, "#line specifies number out of range"); +		tp = tp+1; +		if (tp+1<trp->lp) +			cursource->filename=(char*)newstring(tp->t+1,tp->len-2,0); +		return; + +	case KDEFINED: +		error(ERROR, "Bad syntax for control line"); +		break; + +	case KINCLUDE: +		doinclude(trp); +		trp->lp = trp->bp; +		return; + +	case KEVAL: +		eval(trp, np->val); +		break; + +	default: +		error(ERROR, "Preprocessor control `%t' not yet implemented", tp); +		break; +	} +	setempty(trp); +	return; +} + +void * +domalloc(int size) +{ +	void *p = malloc(size); + +	if (p==NULL) +		error(FATAL, "Out of memory from malloc"); +	return p; +} + +void +dofree(void *p) +{ +	free(p); +} + +void +error(enum errtype type, char *string, ...) +{ +	va_list ap; +	char *cp, *ep; +	Token *tp; +	Tokenrow *trp; +	Source *s; +	int i; + +	fprintf(stderr, "cpp: "); +	for (s=cursource; s; s=s->next) +		if (*s->filename) +			fprintf(stderr, "%s:%d ", s->filename, s->line); +	va_start(ap, string); +	for (ep=string; *ep; ep++) { +		if (*ep=='%') { +			switch (*++ep) { + +			case 's': +				cp = va_arg(ap, char *); +				fprintf(stderr, "%s", cp); +				break; +			case 'd': +				i = va_arg(ap, int); +				fprintf(stderr, "%d", i); +				break; +			case 't': +				tp = va_arg(ap, Token *); +				fprintf(stderr, "%.*s", tp->len, tp->t); +				break; + +			case 'r': +				trp = va_arg(ap, Tokenrow *); +				for (tp=trp->tp; tp<trp->lp&&tp->type!=NL; tp++) { +					if (tp>trp->tp && tp->wslen) +						fputc(' ', stderr); +					fprintf(stderr, "%.*s", tp->len, tp->t); +				} +				break; + +			default: +				fputc(*ep, stderr); +				break; +			} +		} else +			fputc(*ep, stderr); +	} +	va_end(ap); +	fputc('\n', stderr); +	if (type==FATAL) +		exit(1); +	if (type!=WARNING) +		nerrs = 1; +	fflush(stderr); +} diff --git a/src/tools/lcc/cpp/cpp.h b/src/tools/lcc/cpp/cpp.h new file mode 100644 index 0000000..ae855c9 --- /dev/null +++ b/src/tools/lcc/cpp/cpp.h @@ -0,0 +1,166 @@ +#define	INS	32768		/* input buffer */ +#define	OBS	4096		/* outbut buffer */ +#define	NARG	32		/* Max number arguments to a macro */ +#define	NINCLUDE 32		/* Max number of include directories (-I) */ +#define	NIF	32		/* depth of nesting of #if */ +#ifndef EOF +#define	EOF	(-1) +#endif +#ifndef NULL +#define NULL	0 +#endif + +#ifndef __alpha +typedef unsigned char uchar; +#endif + +enum toktype { END, UNCLASS, NAME, NUMBER, STRING, CCON, NL, WS, DSHARP, +		EQ, NEQ, LEQ, GEQ, LSH, RSH, LAND, LOR, PPLUS, MMINUS, +		ARROW, SBRA, SKET, LP, RP, DOT, AND, STAR, PLUS, MINUS, +		TILDE, NOT, SLASH, PCT, LT, GT, CIRC, OR, QUEST, +		COLON, ASGN, COMMA, SHARP, SEMIC, CBRA, CKET, +		ASPLUS, ASMINUS, ASSTAR, ASSLASH, ASPCT, ASCIRC, ASLSH, +		ASRSH, ASOR, ASAND, ELLIPS, +		DSHARP1, NAME1, DEFINED, UMINUS }; + +enum kwtype { KIF, KIFDEF, KIFNDEF, KELIF, KELSE, KENDIF, KINCLUDE, KDEFINE, +		KUNDEF, KLINE, KERROR, KPRAGMA, KDEFINED, +		KLINENO, KFILE, KDATE, KTIME, KSTDC, KEVAL }; + +#define	ISDEFINED	01	/* has #defined value */ +#define	ISKW		02	/* is PP keyword */ +#define	ISUNCHANGE	04	/* can't be #defined in PP */ +#define	ISMAC		010	/* builtin macro, e.g. __LINE__ */ + +#define	EOB	0xFE		/* sentinel for end of input buffer */ +#define	EOFC	0xFD		/* sentinel for end of input file */ +#define	XPWS	1		/* token flag: white space to assure token sep. */ + +typedef struct token { +	unsigned char	type; +	unsigned char 	flag; +	unsigned short	hideset; +	unsigned int	wslen; +	unsigned int	len; +	uchar	*t; +} Token; + +typedef struct tokenrow { +	Token	*tp;		/* current one to scan */ +	Token	*bp;		/* base (allocated value) */ +	Token	*lp;		/* last+1 token used */ +	int	max;		/* number allocated */ +} Tokenrow; + +typedef struct source { +	char	*filename;	/* name of file of the source */ +	int	line;		/* current line number */ +	int	lineinc;	/* adjustment for \\n lines */ +	uchar	*inb;		/* input buffer */ +	uchar	*inp;		/* input pointer */ +	uchar	*inl;		/* end of input */ +	int	fd;		/* input source */ +	int	ifdepth;	/* conditional nesting in include */ +	struct	source *next;	/* stack for #include */ +} Source; + +typedef struct nlist { +	struct nlist *next; +	uchar	*name; +	int	len; +	Tokenrow *vp;		/* value as macro */ +	Tokenrow *ap;		/* list of argument names, if any */ +	char	val;		/* value as preprocessor name */ +	char	flag;		/* is defined, is pp name */ +} Nlist; + +typedef	struct	includelist { +	char	deleted; +	char	always; +	char	*file; +} Includelist; + +#define	new(t)	(t *)domalloc(sizeof(t)) +#define	quicklook(a,b)	(namebit[(a)&077] & (1<<((b)&037))) +#define	quickset(a,b)	namebit[(a)&077] |= (1<<((b)&037)) +extern	unsigned long namebit[077+1]; + +enum errtype { WARNING, ERROR, FATAL }; + +void	expandlex(void); +void	fixlex(void); +void	setup(int, char **); +int	gettokens(Tokenrow *, int); +int	comparetokens(Tokenrow *, Tokenrow *); +Source	*setsource(char *, int, char *); +void	unsetsource(void); +void	puttokens(Tokenrow *); +void	process(Tokenrow *); +void	*domalloc(int); +void	dofree(void *); +void	error(enum errtype, char *, ...); +void	flushout(void); +int	fillbuf(Source *); +int	trigraph(Source *); +int	foldline(Source *); +Nlist	*lookup(Token *, int); +void	control(Tokenrow *); +void	dodefine(Tokenrow *); +void	doadefine(Tokenrow *, int); +void	doinclude(Tokenrow *); +void	appendDirToIncludeList( char *dir ); +void	doif(Tokenrow *, enum kwtype); +void	expand(Tokenrow *, Nlist *); +void	builtin(Tokenrow *, int); +int	gatherargs(Tokenrow *, Tokenrow **, int *); +void	substargs(Nlist *, Tokenrow *, Tokenrow **); +void	expandrow(Tokenrow *, char *); +void	maketokenrow(int, Tokenrow *); +Tokenrow *copytokenrow(Tokenrow *, Tokenrow *); +Token	*growtokenrow(Tokenrow *); +Tokenrow *normtokenrow(Tokenrow *); +void	adjustrow(Tokenrow *, int); +void	movetokenrow(Tokenrow *, Tokenrow *); +void	insertrow(Tokenrow *, int, Tokenrow *); +void	peektokens(Tokenrow *, char *); +void	doconcat(Tokenrow *); +Tokenrow *stringify(Tokenrow *); +int	lookuparg(Nlist *, Token *); +long	eval(Tokenrow *, int); +void	genline(void); +void	setempty(Tokenrow *); +void	makespace(Tokenrow *); +char	*outnum(char *, int); +int	digit(int); +uchar	*newstring(uchar *, int, int); +int	checkhideset(int, Nlist *); +void	prhideset(int); +int	newhideset(int, Nlist *); +int	unionhideset(int, int); +void	iniths(void); +void	setobjname(char *); +#define	rowlen(tokrow)	((tokrow)->lp - (tokrow)->bp) + +char *basepath( char *fname ); + +extern	char *outp; +extern	Token	nltoken; +extern	Source *cursource; +extern	char *curtime; +extern	int incdepth; +extern	int ifdepth; +extern	int ifsatisfied[NIF]; +extern	int Mflag; +extern	int skipping; +extern	int verbose; +extern	int Cplusplus; +extern	Nlist *kwdefined; +extern	Includelist includelist[NINCLUDE]; +extern	char wd[]; + +#ifndef _WIN32 +#include <unistd.h> +#else +#include <io.h> +#endif +#include <fcntl.h> diff --git a/src/tools/lcc/cpp/eval.c b/src/tools/lcc/cpp/eval.c new file mode 100644 index 0000000..95a9e11 --- /dev/null +++ b/src/tools/lcc/cpp/eval.c @@ -0,0 +1,524 @@ +#include <stdlib.h> +#include <string.h> +#include "cpp.h" + +#define	NSTAK	32 +#define	SGN	0 +#define	UNS	1 +#define	UND	2 + +#define	UNSMARK	0x1000 + +struct value { +	long	val; +	int	type; +}; + +/* conversion types */ +#define	RELAT	1 +#define	ARITH	2 +#define	LOGIC	3 +#define	SPCL	4 +#define	SHIFT	5 +#define	UNARY	6 + +/* operator priority, arity, and conversion type, indexed by tokentype */ +struct pri { +	char	pri; +	char	arity; +	char	ctype; +} priority[] = { +	{ 0, 0, 0 },		/* END */ +	{ 0, 0, 0 },		/* UNCLASS */ +	{ 0, 0, 0 },		/* NAME */ +	{ 0, 0, 0 },		/* NUMBER */ +	{ 0, 0, 0 },		/* STRING */ +	{ 0, 0, 0 },		/* CCON */ +	{ 0, 0, 0 },		/* NL */ +	{ 0, 0, 0 },		/* WS */ +	{ 0, 0, 0 },		/* DSHARP */ +	{ 11, 2, RELAT },	/* EQ */ +	{ 11, 2, RELAT },	/* NEQ */ +	{ 12, 2, RELAT },	/* LEQ */ +	{ 12, 2, RELAT },	/* GEQ */ +	{ 13, 2, SHIFT },	/* LSH */ +	{ 13, 2, SHIFT },	/* RSH */ +	{ 7, 2, LOGIC },	/* LAND */ +	{ 6, 2, LOGIC },	/* LOR */ +	{ 0, 0, 0 },		/* PPLUS */ +	{ 0, 0, 0 },		/* MMINUS */ +	{ 0, 0, 0 },		/* ARROW */ +	{ 0, 0, 0 },		/* SBRA */ +	{ 0, 0, 0 },		/* SKET */ +	{ 3, 0, 0 },		/* LP */ +	{ 3, 0, 0 },		/* RP */ +	{ 0, 0, 0 },		/* DOT */ +	{ 10, 2, ARITH },	/* AND */ +	{ 15, 2, ARITH },	/* STAR */ +	{ 14, 2, ARITH },	/* PLUS */ +	{ 14, 2, ARITH },	/* MINUS */ +	{ 16, 1, UNARY },	/* TILDE */ +	{ 16, 1, UNARY },	/* NOT */ +	{ 15, 2, ARITH },	/* SLASH */ +	{ 15, 2, ARITH },	/* PCT */ +	{ 12, 2, RELAT },	/* LT */ +	{ 12, 2, RELAT },	/* GT */ +	{ 9, 2, ARITH },	/* CIRC */ +	{ 8, 2, ARITH },	/* OR */ +	{ 5, 2, SPCL },		/* QUEST */ +	{ 5, 2, SPCL },		/* COLON */ +	{ 0, 0, 0 },		/* ASGN */ +	{ 4, 2, 0 },		/* COMMA */ +	{ 0, 0, 0 },		/* SHARP */ +	{ 0, 0, 0 },		/* SEMIC */ +	{ 0, 0, 0 },		/* CBRA */ +	{ 0, 0, 0 },		/* CKET */ +	{ 0, 0, 0 },		/* ASPLUS */ + 	{ 0, 0, 0 },		/* ASMINUS */ + 	{ 0, 0, 0 },		/* ASSTAR */ + 	{ 0, 0, 0 },		/* ASSLASH */ + 	{ 0, 0, 0 },		/* ASPCT */ + 	{ 0, 0, 0 },		/* ASCIRC */ + 	{ 0, 0, 0 },		/* ASLSH */ +	{ 0, 0, 0 },		/* ASRSH */ + 	{ 0, 0, 0 },		/* ASOR */ + 	{ 0, 0, 0 },		/* ASAND */ +	{ 0, 0, 0 },		/* ELLIPS */ +	{ 0, 0, 0 },		/* DSHARP1 */ +	{ 0, 0, 0 },		/* NAME1 */ +	{ 16, 1, UNARY },	/* DEFINED */ +	{ 16, 0, UNARY },	/* UMINUS */ +}; + +int	evalop(struct pri); +struct	value tokval(Token *); +struct value vals[NSTAK], *vp; +enum toktype ops[NSTAK], *op; + +/* + * Evaluate an #if #elif #ifdef #ifndef line.  trp->tp points to the keyword. + */ +long +eval(Tokenrow *trp, int kw) +{ +	Token *tp; +	Nlist *np; +	int ntok, rand; + +	trp->tp++; +	if (kw==KIFDEF || kw==KIFNDEF) { +		if (trp->lp - trp->bp != 4 || trp->tp->type!=NAME) { +			error(ERROR, "Syntax error in #ifdef/#ifndef"); +			return 0; +		} +		np = lookup(trp->tp, 0); +		return (kw==KIFDEF) == (np && np->flag&(ISDEFINED|ISMAC)); +	} +	ntok = trp->tp - trp->bp; +	kwdefined->val = KDEFINED;	/* activate special meaning of defined */ +	expandrow(trp, "<if>"); +	kwdefined->val = NAME; +	vp = vals; +	op = ops; +	*op++ = END; +	for (rand=0, tp = trp->bp+ntok; tp < trp->lp; tp++) { +		switch(tp->type) { +		case WS: +		case NL: +			continue; + +		/* nilary */ +		case NAME: +		case NAME1: +		case NUMBER: +		case CCON: +		case STRING: +			if (rand) +				goto syntax; +			*vp++ = tokval(tp); +			rand = 1; +			continue; + +		/* unary */ +		case DEFINED: +		case TILDE: +		case NOT: +			if (rand) +				goto syntax; +			*op++ = tp->type; +			continue; + +		/* unary-binary */ +		case PLUS: case MINUS: case STAR: case AND: +			if (rand==0) { +				if (tp->type==MINUS) +					*op++ = UMINUS; +				if (tp->type==STAR || tp->type==AND) { +					error(ERROR, "Illegal operator * or & in #if/#elsif"); +					return 0; +				} +				continue; +			} +			/* flow through */ + +		/* plain binary */ +		case EQ: case NEQ: case LEQ: case GEQ: case LSH: case RSH: +		case LAND: case LOR: case SLASH: case PCT: +		case LT: case GT: case CIRC: case OR: case QUEST: +		case COLON: case COMMA: +			if (rand==0) +				goto syntax; +			if (evalop(priority[tp->type])!=0) +				return 0; +			*op++ = tp->type; +			rand = 0; +			continue; + +		case LP: +			if (rand) +				goto syntax; +			*op++ = LP; +			continue; + +		case RP: +			if (!rand) +				goto syntax; +			if (evalop(priority[RP])!=0) +				return 0; +			if (op<=ops || op[-1]!=LP) { +				goto syntax; +			} +			op--; +			continue; + +		default: +			error(ERROR,"Bad operator (%t) in #if/#elsif", tp); +			return 0; +		} +	} +	if (rand==0) +		goto syntax; +	if (evalop(priority[END])!=0) +		return 0; +	if (op!=&ops[1] || vp!=&vals[1]) { +		error(ERROR, "Botch in #if/#elsif"); +		return 0; +	} +	if (vals[0].type==UND) +		error(ERROR, "Undefined expression value"); +	return vals[0].val; +syntax: +	error(ERROR, "Syntax error in #if/#elsif"); +	return 0; +} + +int +evalop(struct pri pri) +{ +	struct value v1, v2; +	long rv1, rv2; +	int rtype, oper; + +	/* prevent compiler whining. */ +	v1.val = v2.val = 0; +	v1.type = v2.type = 0; + +	rv2=0; +	rtype=0; +	while (pri.pri < priority[op[-1]].pri) { +		oper = *--op; +		if (priority[oper].arity==2) { +			v2 = *--vp; +			rv2 = v2.val; +		} +		v1 = *--vp; +		rv1 = v1.val; +/*lint -e574 -e644 */ +		switch (priority[oper].ctype) { +		case 0: +		default: +			error(WARNING, "Syntax error in #if/#endif"); +			return 1; +		case ARITH: +		case RELAT: +			if (v1.type==UNS || v2.type==UNS) +				rtype = UNS; +			else +				rtype = SGN; +			if (v1.type==UND || v2.type==UND) +				rtype = UND; +			if (priority[oper].ctype==RELAT && rtype==UNS) { +				oper |= UNSMARK; +				rtype = SGN; +			} +			break; +		case SHIFT: +			if (v1.type==UND || v2.type==UND) +				rtype = UND; +			else +				rtype = v1.type; +			if (rtype==UNS) +				oper |= UNSMARK; +			break; +		case UNARY: +			rtype = v1.type; +			break; +		case LOGIC: +		case SPCL: +			break; +		} +		switch (oper) { +		case EQ: case EQ|UNSMARK: +			rv1 = rv1==rv2; break; +		case NEQ: case NEQ|UNSMARK: +			rv1 = rv1!=rv2; break; +		case LEQ: +			rv1 = rv1<=rv2; break; +		case GEQ: +			rv1 = rv1>=rv2; break; +		case LT: +			rv1 = rv1<rv2; break; +		case GT: +			rv1 = rv1>rv2; break; +		case LEQ|UNSMARK: +			rv1 = (unsigned long)rv1<=rv2; break; +		case GEQ|UNSMARK: +			rv1 = (unsigned long)rv1>=rv2; break; +		case LT|UNSMARK: +			rv1 = (unsigned long)rv1<rv2; break; +		case GT|UNSMARK: +			rv1 = (unsigned long)rv1>rv2; break; +		case LSH: +			rv1 <<= rv2; break; +		case LSH|UNSMARK: +			rv1 = (unsigned long)rv1<<rv2; break; +		case RSH: +			rv1 >>= rv2; break; +		case RSH|UNSMARK: +			rv1 = (unsigned long)rv1>>rv2; break; +		case LAND: +			rtype = UND; +			if (v1.type==UND) +				break; +			if (rv1!=0) { +				if (v2.type==UND) +					break; +				rv1 = rv2!=0; +			} else +				rv1 = 0; +			rtype = SGN; +			break; +		case LOR: +			rtype = UND; +			if (v1.type==UND) +				break; +			if (rv1==0) { +				if (v2.type==UND) +					break; +				rv1 = rv2!=0; +			} else +				rv1 = 1; +			rtype = SGN; +			break; +		case AND: +			rv1 &= rv2; break; +		case STAR: +			rv1 *= rv2; break; +		case PLUS: +			rv1 += rv2; break; +		case MINUS: +			rv1 -= rv2; break; +		case UMINUS: +			if (v1.type==UND) +				rtype = UND; +			rv1 = -rv1; break; +		case OR: +			rv1 |= rv2; break; +		case CIRC: +			rv1 ^= rv2; break; +		case TILDE: +			rv1 = ~rv1; break; +		case NOT: +			rv1 = !rv1; if (rtype!=UND) rtype = SGN; break; +		case SLASH: +			if (rv2==0) { +				rtype = UND; +				break; +			} +			if (rtype==UNS) +				rv1 /= (unsigned long)rv2; +			else +				rv1 /= rv2; +			break; +		case PCT: +			if (rv2==0) { +				rtype = UND; +				break; +			} +			if (rtype==UNS) +				rv1 %= (unsigned long)rv2; +			else +				rv1 %= rv2; +			break; +		case COLON: +			if (op[-1] != QUEST) +				error(ERROR, "Bad ?: in #if/endif"); +			else { +				op--; +				if ((--vp)->val==0) +					v1 = v2; +				rtype = v1.type; +				rv1 = v1.val; +			} +			break; +		case DEFINED: +			break; +		default: +			error(ERROR, "Eval botch (unknown operator)"); +			return 1; +		} +/*lint +e574 +e644 */ +		v1.val = rv1; +		v1.type = rtype; +		*vp++ = v1; +	} +	return 0; +} + +struct value +tokval(Token *tp) +{ +	struct value v; +	Nlist *np; +	int i, base, c; +	unsigned long n; +	uchar *p; + +	v.type = SGN; +	v.val = 0; +	switch (tp->type) { + +	case NAME: +		v.val = 0; +		break; + +	case NAME1: +		if ((np = lookup(tp, 0)) != NULL && np->flag&(ISDEFINED|ISMAC)) +			v.val = 1; +		break; + +	case NUMBER: +		n = 0; +		base = 10; +		p = tp->t; +		c = p[tp->len]; +		p[tp->len] = '\0'; +		if (*p=='0') { +			base = 8; +			if (p[1]=='x' || p[1]=='X') { +				base = 16; +				p++; +			} +			p++; +		} +		for (;; p++) { +			if ((i = digit(*p)) < 0) +				break; +			if (i>=base) +				error(WARNING, +				  "Bad digit in number %t", tp); +			n *= base; +			n += i; +		} +		if (n>=0x80000000 && base!=10) +			v.type = UNS; +		for (; *p; p++) { +			if (*p=='u' || *p=='U') +				v.type = UNS; +			else if (*p=='l' || *p=='L') +				; +			else { +				error(ERROR, +				  "Bad number %t in #if/#elsif", tp); +				break; +			} +		} +		v.val = n; +		tp->t[tp->len] = c; +		break; + +	case CCON: +		n = 0; +		p = tp->t; +		if (*p=='L') { +			p += 1; +			error(WARNING, "Wide char constant value undefined"); +		} +		p += 1; +		if (*p=='\\') { +			p += 1; +			if ((i = digit(*p))>=0 && i<=7) { +				n = i; +				p += 1; +				if ((i = digit(*p))>=0 && i<=7) { +					p += 1; +					n <<= 3; +					n += i; +					if ((i = digit(*p))>=0 && i<=7) { +						p += 1; +						n <<= 3; +						n += i; +					} +				} +			} else if (*p=='x') { +				p += 1; +				while ((i = digit(*p))>=0 && i<=15) { +					p += 1; +					n <<= 4; +					n += i; +				} +			} else { +				static char cvcon[] +				  = "b\bf\fn\nr\rt\tv\v''\"\"??\\\\"; +				for (i=0; i<sizeof(cvcon); i+=2) { +					if (*p == cvcon[i]) { +						n = cvcon[i+1]; +						break; +					} +				} +				p += 1; +				if (i>=sizeof(cvcon)) +					error(WARNING, +					 "Undefined escape in character constant"); +			} +		} else if (*p=='\'') +			error(ERROR, "Empty character constant"); +		else +			n = *p++; +		if (*p!='\'') +			error(WARNING, "Multibyte character constant undefined"); +		else if (n>127) +			error(WARNING, "Character constant taken as not signed"); +		v.val = n; +		break; + +	case STRING: +		error(ERROR, "String in #if/#elsif"); +		break; +	} +	return v; +} + +int +digit(int i) +{ +	if ('0'<=i && i<='9') +		i -= '0'; +	else if ('a'<=i && i<='f') +		i -= 'a'-10; +	else if ('A'<=i && i<='F') +		i -= 'A'-10; +	else +		i = -1; +	return i; +} diff --git a/src/tools/lcc/cpp/getopt.c b/src/tools/lcc/cpp/getopt.c new file mode 100644 index 0000000..d4cacad --- /dev/null +++ b/src/tools/lcc/cpp/getopt.c @@ -0,0 +1,53 @@ +#include	<stdio.h>
 +#include	<string.h>
 +#define EPR                 fprintf(stderr,
 +#define ERR(str, chr)       if(opterr){EPR "%s%c\n", str, chr);}
 +int     opterr = 1;
 +int     optind = 1;
 +int	optopt;
 +char    *optarg;
 +
 +int
 +lcc_getopt (int argc, char *const argv[], const char *opts)
 +{
 +	static int sp = 1;
 +	int c;
 +	char *cp;
 +
 +	if (sp == 1) {
 +		if (optind >= argc ||
 +		   argv[optind][0] != '-' || argv[optind][1] == '\0')
 +			return -1;
 +		else if (strcmp(argv[optind], "--") == 0) {
 +			optind++;
 +			return -1;
 +		}
 +	}
 +	optopt = c = argv[optind][sp];
 +	if (c == ':' || (cp=strchr(opts, c)) == 0) {
 +		ERR (": illegal option -- ", c);
 +		if (argv[optind][++sp] == '\0') {
 +			optind++;
 +			sp = 1;
 +		}
 +		return '?';
 +	}
 +	if (*++cp == ':') {
 +		if (argv[optind][sp+1] != '\0')
 +			optarg = &argv[optind++][sp+1];
 +		else if (++optind >= argc) {
 +			ERR (": option requires an argument -- ", c);
 +			sp = 1;
 +			return '?';
 +		} else
 +			optarg = argv[optind++];
 +		sp = 1;
 +	} else {
 +		if (argv[optind][++sp] == '\0') {
 +			sp = 1;
 +			optind++;
 +		}
 +		optarg = 0;
 +	}
 +	return c;
 +}
 diff --git a/src/tools/lcc/cpp/hideset.c b/src/tools/lcc/cpp/hideset.c new file mode 100644 index 0000000..bd2540d --- /dev/null +++ b/src/tools/lcc/cpp/hideset.c @@ -0,0 +1,112 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "cpp.h" + +/* + * A hideset is a null-terminated array of Nlist pointers. + * They are referred to by indices in the hidesets array. + * Hideset 0 is empty. + */ + +#define	HSSIZ	32 +typedef	Nlist	**Hideset; +Hideset	*hidesets; +int	nhidesets = 0; +int	maxhidesets = 3; +int	inserths(Hideset, Hideset, Nlist *); + +/* + * Test for membership in a hideset + */ +int +checkhideset(int hs, Nlist *np) +{ +	Hideset hsp; + +	if (hs>=nhidesets) +		abort(); +	for (hsp = hidesets[hs]; *hsp; hsp++) { +		if (*hsp == np) +			return 1; +	} +	return 0; +} + +/* + * Return the (possibly new) hideset obtained by adding np to hs. + */ +int +newhideset(int hs, Nlist *np) +{ +	int i, len; +	Nlist *nhs[HSSIZ+3]; +	Hideset hs1, hs2; + +	len = inserths(nhs, hidesets[hs], np); +	for (i=0; i<nhidesets; i++) { +		for (hs1=nhs, hs2=hidesets[i]; *hs1==*hs2; hs1++, hs2++) +			if (*hs1 == NULL) +				return i; +	} +	if (len>=HSSIZ) +		return hs; +	if (nhidesets >= maxhidesets) { +		maxhidesets = 3*maxhidesets/2+1; +		hidesets = (Hideset *)realloc(hidesets, (sizeof (Hideset *))*maxhidesets); +		if (hidesets == NULL) +			error(FATAL, "Out of memory from realloc"); +	} +	hs1 = (Hideset)domalloc(len*sizeof(Hideset)); +	memmove(hs1, nhs, len*sizeof(Hideset)); +	hidesets[nhidesets] = hs1; +	return nhidesets++; +} + +int +inserths(Hideset dhs, Hideset shs, Nlist *np) +{ +	Hideset odhs = dhs; + +	while (*shs && *shs < np) +		*dhs++ = *shs++; +	if (*shs != np) +		*dhs++ = np; +	do { +		*dhs++ = *shs; +	} while (*shs++); +	return dhs - odhs; +} + +/* + * Hideset union + */ +int +unionhideset(int hs1, int hs2) +{ +	Hideset hp; + +	for (hp = hidesets[hs2]; *hp; hp++) +		hs1 = newhideset(hs1, *hp); +	return hs1; +} + +void +iniths(void) +{ +	hidesets = (Hideset *)domalloc(maxhidesets*sizeof(Hideset *)); +	hidesets[0] = (Hideset)domalloc(sizeof(Hideset)); +	*hidesets[0] = NULL; +	nhidesets++; +} + +void +prhideset(int hs) +{ +	Hideset np; + +	for (np = hidesets[hs]; *np; np++) { +		fprintf(stderr, (char*)(*np)->name, (*np)->len); +		fprintf(stderr, " "); +	} +} diff --git a/src/tools/lcc/cpp/include.c b/src/tools/lcc/cpp/include.c new file mode 100644 index 0000000..1bb8847 --- /dev/null +++ b/src/tools/lcc/cpp/include.c @@ -0,0 +1,154 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "cpp.h" + +Includelist	includelist[NINCLUDE]; + +extern char	*objname; + +void appendDirToIncludeList( char *dir ) +{ +	int i; +	char *fqdir; + +	fqdir = (char *)newstring( (uchar *)includelist[NINCLUDE-1].file, 256, 0 ); +	strcat( fqdir, "/" ); +	strcat( fqdir, dir ); + +	//avoid adding it more than once +	for (i=NINCLUDE-2; i>=0; i--) { +		if (includelist[i].file && +				!strcmp (includelist[i].file, fqdir)) { +			return; +		} +	} + +	for (i=NINCLUDE-2; i>=0; i--) { +		if (includelist[i].file==NULL) { +			includelist[i].always = 1; +			includelist[i].file = fqdir; +			break; +		} +	} +	if (i<0) +		error(FATAL, "Too many -I directives"); +} + +void +doinclude(Tokenrow *trp) +{ +	char fname[256], iname[256]; +	Includelist *ip; +	int angled, len, fd, i; + +	trp->tp += 1; +	if (trp->tp>=trp->lp) +		goto syntax; +	if (trp->tp->type!=STRING && trp->tp->type!=LT) { +		len = trp->tp - trp->bp; +		expandrow(trp, "<include>"); +		trp->tp = trp->bp+len; +	} +	if (trp->tp->type==STRING) { +		len = trp->tp->len-2; +		if (len > sizeof(fname) - 1) +			len = sizeof(fname) - 1; +		strncpy(fname, (char*)trp->tp->t+1, len); +		angled = 0; +	} else if (trp->tp->type==LT) { +		len = 0; +		trp->tp++; +		while (trp->tp->type!=GT) { +			if (trp->tp>trp->lp || len+trp->tp->len+2 >= sizeof(fname)) +				goto syntax; +			strncpy(fname+len, (char*)trp->tp->t, trp->tp->len); +			len += trp->tp->len; +			trp->tp++; +		} +		angled = 1; +	} else +		goto syntax; +	trp->tp += 2; +	if (trp->tp < trp->lp || len==0) +		goto syntax; +	fname[len] = '\0'; + +	appendDirToIncludeList( basepath( fname ) ); + +	if (fname[0]=='/') { +		fd = open(fname, 0); +		strcpy(iname, fname); +	} else for (fd = -1,i=NINCLUDE-1; i>=0; i--) { +		ip = &includelist[i]; +		if (ip->file==NULL || ip->deleted || (angled && ip->always==0)) +			continue; +		if (strlen(fname)+strlen(ip->file)+2 > sizeof(iname)) +			continue; +		strcpy(iname, ip->file); +		strcat(iname, "/"); +		strcat(iname, fname); +		if ((fd = open(iname, 0)) >= 0) +			break; +	} +	if ( Mflag>1 || (!angled&&Mflag==1) ) { +		write(1,objname,strlen(objname)); +		write(1,iname,strlen(iname)); +		write(1,"\n",1); +	} +	if (fd >= 0) { +		if (++incdepth > 10) +			error(FATAL, "#include too deeply nested"); +		setsource((char*)newstring((uchar*)iname, strlen(iname), 0), fd, NULL); +		genline(); +	} else { +		trp->tp = trp->bp+2; +		error(ERROR, "Could not find include file %r", trp); +	} +	return; +syntax: +	error(ERROR, "Syntax error in #include"); +	return; +} + +/* + * Generate a line directive for cursource + */ +void +genline(void) +{ +	static Token ta = { UNCLASS }; +	static Tokenrow tr = { &ta, &ta, &ta+1, 1 }; +	uchar *p; + +	ta.t = p = (uchar*)outp; +	strcpy((char*)p, "#line "); +	p += sizeof("#line ")-1; +	p = (uchar*)outnum((char*)p, cursource->line); +	*p++ = ' '; *p++ = '"'; +	if (cursource->filename[0]!='/' && wd[0]) { +		strcpy((char*)p, wd); +		p += strlen(wd); +		*p++ = '/'; +	} +	strcpy((char*)p, cursource->filename); +	p += strlen((char*)p); +	*p++ = '"'; *p++ = '\n'; +	ta.len = (char*)p-outp; +	outp = (char*)p; +	tr.tp = tr.bp; +	puttokens(&tr); +} + +void +setobjname(char *f) +{ +	int n = strlen(f); +	objname = (char*)domalloc(n+5); +	strcpy(objname,f); +	if(objname[n-2]=='.'){ +		strcpy(objname+n-1,"$O: "); +	}else{ +		strcpy(objname+n,"$O: "); +	} +} diff --git a/src/tools/lcc/cpp/lex.c b/src/tools/lcc/cpp/lex.c new file mode 100644 index 0000000..8030354 --- /dev/null +++ b/src/tools/lcc/cpp/lex.c @@ -0,0 +1,580 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "cpp.h" + +/* + * lexical FSM encoding + *   when in state state, and one of the characters + *   in ch arrives, enter nextstate. + *   States >= S_SELF are either final, or at least require special action. + *   In 'fsm' there is a line for each state X charset X nextstate. + *   List chars that overwrite previous entries later (e.g. C_ALPH + *   can be overridden by '_' by a later entry; and C_XX is the + *   the universal set, and should always be first. + *   States above S_SELF are represented in the big table as negative values. + *   S_SELF and S_SELFB encode the resulting token type in the upper bits. + *   These actions differ in that S_SELF doesn't have a lookahead char, + *   S_SELFB does. + * + *   The encoding is blown out into a big table for time-efficiency. + *   Entries have + *      nextstate: 6 bits; ?\ marker: 1 bit; tokentype: 9 bits. + */ + +#define	MAXSTATE 32 +#define	ACT(tok,act)	((tok<<7)+act) +#define	QBSBIT	0100 +#define	GETACT(st)	(st>>7)&0x1ff + +/* character classes */ +#define	C_WS	1 +#define	C_ALPH	2 +#define	C_NUM	3 +#define	C_EOF	4 +#define	C_XX	5 + +enum state { +	START=0, NUM1, NUM2, NUM3, ID1, ST1, ST2, ST3, COM1, COM2, COM3, COM4, +	CC1, CC2, WS1, PLUS1, MINUS1, STAR1, SLASH1, PCT1, SHARP1, +	CIRC1, GT1, GT2, LT1, LT2, OR1, AND1, ASG1, NOT1, DOTS1, +	S_SELF=MAXSTATE, S_SELFB, S_EOF, S_NL, S_EOFSTR, +	S_STNL, S_COMNL, S_EOFCOM, S_COMMENT, S_EOB, S_WS, S_NAME +}; + +int	tottok; +int	tokkind[256]; +struct	fsm { +	int	state;		/* if in this state */ +	uchar	ch[4];		/* and see one of these characters */ +	int	nextstate;	/* enter this state if +ve */ +}; + +/*const*/ struct fsm fsm[] = { +	/* start state */ +	{START,	{ C_XX },	ACT(UNCLASS,S_SELF)}, +	{START,	{ ' ', '\t', '\v' },	WS1}, +	{START,	{ C_NUM },	NUM1}, +	{START,	{ '.' },	NUM3}, +	{START,	{ C_ALPH },	ID1}, +	{START,	{ 'L' },	ST1}, +	{START,	{ '"' },	ST2}, +	{START,	{ '\'' },	CC1}, +	{START,	{ '/' },	COM1}, +	{START,	{ EOFC },	S_EOF}, +	{START,	{ '\n' },	S_NL}, +	{START,	{ '-' },	MINUS1}, +	{START,	{ '+' },	PLUS1}, +	{START,	{ '<' },	LT1}, +	{START,	{ '>' },	GT1}, +	{START,	{ '=' },	ASG1}, +	{START,	{ '!' },	NOT1}, +	{START,	{ '&' },	AND1}, +	{START,	{ '|' },	OR1}, +	{START,	{ '#' },	SHARP1}, +	{START,	{ '%' },	PCT1}, +	{START,	{ '[' },	ACT(SBRA,S_SELF)}, +	{START,	{ ']' },	ACT(SKET,S_SELF)}, +	{START,	{ '(' },	ACT(LP,S_SELF)}, +	{START,	{ ')' },	ACT(RP,S_SELF)}, +	{START,	{ '*' },	STAR1}, +	{START,	{ ',' },	ACT(COMMA,S_SELF)}, +	{START,	{ '?' },	ACT(QUEST,S_SELF)}, +	{START,	{ ':' },	ACT(COLON,S_SELF)}, +	{START,	{ ';' },	ACT(SEMIC,S_SELF)}, +	{START,	{ '{' },	ACT(CBRA,S_SELF)}, +	{START,	{ '}' },	ACT(CKET,S_SELF)}, +	{START,	{ '~' },	ACT(TILDE,S_SELF)}, +	{START,	{ '^' },	CIRC1}, + +	/* saw a digit */ +	{NUM1,	{ C_XX },	ACT(NUMBER,S_SELFB)}, +	{NUM1,	{ C_NUM, C_ALPH, '.' },	NUM1}, +	{NUM1,	{ 'E', 'e' },	NUM2}, +	{NUM1,	{ '_' },	ACT(NUMBER,S_SELFB)}, + +	/* saw possible start of exponent, digits-e */ +	{NUM2,	{ C_XX },	ACT(NUMBER,S_SELFB)}, +	{NUM2,	{ '+', '-' },	NUM1}, +	{NUM2,	{ C_NUM, C_ALPH },	NUM1}, +	{NUM2,	{ '_' },	ACT(NUMBER,S_SELFB)}, + +	/* saw a '.', which could be a number or an operator */ +	{NUM3,	{ C_XX },	ACT(DOT,S_SELFB)}, +	{NUM3,	{ '.' },	DOTS1}, +	{NUM3,	{ C_NUM },	NUM1}, + +	{DOTS1,	{ C_XX },	ACT(UNCLASS, S_SELFB)}, +	{DOTS1,	{ C_NUM },	NUM1}, +	{DOTS1,	{ '.' },	ACT(ELLIPS, S_SELF)}, + +	/* saw a letter or _ */ +	{ID1,	{ C_XX },	ACT(NAME,S_NAME)}, +	{ID1,	{ C_ALPH, C_NUM },	ID1}, + +	/* saw L (start of wide string?) */ +	{ST1,	{ C_XX },	ACT(NAME,S_NAME)}, +	{ST1,	{ C_ALPH, C_NUM },	ID1}, +	{ST1,	{ '"' },	ST2}, +	{ST1,	{ '\'' },	CC1}, + +	/* saw " beginning string */ +	{ST2,	{ C_XX },	ST2}, +	{ST2,	{ '"' },	ACT(STRING, S_SELF)}, +	{ST2,	{ '\\' },	ST3}, +	{ST2,	{ '\n' },	S_STNL}, +	{ST2,	{ EOFC },	S_EOFSTR}, + +	/* saw \ in string */ +	{ST3,	{ C_XX },	ST2}, +	{ST3,	{ '\n' },	S_STNL}, +	{ST3,	{ EOFC },	S_EOFSTR}, + +	/* saw ' beginning character const */ +	{CC1,	{ C_XX },	CC1}, +	{CC1,	{ '\'' },	ACT(CCON, S_SELF)}, +	{CC1,	{ '\\' },	CC2}, +	{CC1,	{ '\n' },	S_STNL}, +	{CC1,	{ EOFC },	S_EOFSTR}, + +	/* saw \ in ccon */ +	{CC2,	{ C_XX },	CC1}, +	{CC2,	{ '\n' },	S_STNL}, +	{CC2,	{ EOFC },	S_EOFSTR}, + +	/* saw /, perhaps start of comment */ +	{COM1,	{ C_XX },	ACT(SLASH, S_SELFB)}, +	{COM1,	{ '=' },	ACT(ASSLASH, S_SELF)}, +	{COM1,	{ '*' },	COM2}, +	{COM1,	{ '/' },	COM4}, + +	/* saw / then *, start of comment */ +	{COM2,	{ C_XX },	COM2}, +	{COM2,	{ '\n' },	S_COMNL}, +	{COM2,	{ '*' },	COM3}, +	{COM2,	{ EOFC },	S_EOFCOM}, + +	/* saw the * possibly ending a comment */ +	{COM3,	{ C_XX },	COM2}, +	{COM3,	{ '\n' },	S_COMNL}, +	{COM3,	{ '*' },	COM3}, +	{COM3,	{ '/' },	S_COMMENT}, + +	/* // comment */ +	{COM4,	{ C_XX },	COM4}, +	{COM4,	{ '\n' },	S_NL}, +	{COM4,	{ EOFC },	S_EOFCOM}, + +	/* saw white space, eat it up */ +	{WS1,	{ C_XX },	S_WS}, +	{WS1,	{ ' ', '\t', '\v' },	WS1}, + +	/* saw -, check --, -=, -> */ +	{MINUS1,	{ C_XX },	ACT(MINUS, S_SELFB)}, +	{MINUS1,	{ '-' },	ACT(MMINUS, S_SELF)}, +	{MINUS1,	{ '=' },	ACT(ASMINUS,S_SELF)}, +	{MINUS1,	{ '>' },	ACT(ARROW,S_SELF)}, + +	/* saw +, check ++, += */ +	{PLUS1,	{ C_XX },	ACT(PLUS, S_SELFB)}, +	{PLUS1,	{ '+' },	ACT(PPLUS, S_SELF)}, +	{PLUS1,	{ '=' },	ACT(ASPLUS, S_SELF)}, + +	/* saw <, check <<, <<=, <= */ +	{LT1,	{ C_XX },	ACT(LT, S_SELFB)}, +	{LT1,	{ '<' },	LT2}, +	{LT1,	{ '=' },	ACT(LEQ, S_SELF)}, +	{LT2,	{ C_XX },	ACT(LSH, S_SELFB)}, +	{LT2,	{ '=' },	ACT(ASLSH, S_SELF)}, + +	/* saw >, check >>, >>=, >= */ +	{GT1,	{ C_XX },	ACT(GT, S_SELFB)}, +	{GT1,	{ '>' },	GT2}, +	{GT1,	{ '=' },	ACT(GEQ, S_SELF)}, +	{GT2,	{ C_XX },	ACT(RSH, S_SELFB)}, +	{GT2,	{ '=' },	ACT(ASRSH, S_SELF)}, + +	/* = */ +	{ASG1,	{ C_XX },	ACT(ASGN, S_SELFB)}, +	{ASG1,	{ '=' },	ACT(EQ, S_SELF)}, + +	/* ! */ +	{NOT1,	{ C_XX },	ACT(NOT, S_SELFB)}, +	{NOT1,	{ '=' },	ACT(NEQ, S_SELF)}, + +	/* & */ +	{AND1,	{ C_XX },	ACT(AND, S_SELFB)}, +	{AND1,	{ '&' },	ACT(LAND, S_SELF)}, +	{AND1,	{ '=' },	ACT(ASAND, S_SELF)}, + +	/* | */ +	{OR1,	{ C_XX },	ACT(OR, S_SELFB)}, +	{OR1,	{ '|' },	ACT(LOR, S_SELF)}, +	{OR1,	{ '=' },	ACT(ASOR, S_SELF)}, + +	/* # */ +	{SHARP1,	{ C_XX },	ACT(SHARP, S_SELFB)}, +	{SHARP1,	{ '#' },	ACT(DSHARP, S_SELF)}, + +	/* % */ +	{PCT1,	{ C_XX },	ACT(PCT, S_SELFB)}, +	{PCT1,	{ '=' },	ACT(ASPCT, S_SELF)}, + +	/* * */ +	{STAR1,	{ C_XX },	ACT(STAR, S_SELFB)}, +	{STAR1,	{ '=' },	ACT(ASSTAR, S_SELF)}, + +	/* ^ */ +	{CIRC1,	{ C_XX },	ACT(CIRC, S_SELFB)}, +	{CIRC1,	{ '=' },	ACT(ASCIRC, S_SELF)}, + +	{-1} +}; + +/* first index is char, second is state */ +/* increase #states to power of 2 to encourage use of shift */ +short	bigfsm[256][MAXSTATE]; + +void +expandlex(void) +{ +	/*const*/ struct fsm *fp; +	int i, j, nstate; + +	for (fp = fsm; fp->state>=0; fp++) { +		for (i=0; fp->ch[i]; i++) { +			nstate = fp->nextstate; +			if (nstate >= S_SELF) +				nstate = ~nstate; +			switch (fp->ch[i]) { + +			case C_XX:		/* random characters */ +				for (j=0; j<256; j++) +					bigfsm[j][fp->state] = nstate; +				continue; +			case C_ALPH: +				for (j=0; j<=256; j++) +					if (('a'<=j&&j<='z') || ('A'<=j&&j<='Z') +					  || j=='_') +						bigfsm[j][fp->state] = nstate; +				continue; +			case C_NUM: +				for (j='0'; j<='9'; j++) +					bigfsm[j][fp->state] = nstate; +				continue; +			default: +				bigfsm[fp->ch[i]][fp->state] = nstate; +			} +		} +	} +	/* install special cases for ? (trigraphs),  \ (splicing), runes, and EOB */ +	for (i=0; i<MAXSTATE; i++) { +		for (j=0; j<0xFF; j++) +			if (j=='?' || j=='\\') { +				if (bigfsm[j][i]>0) +					bigfsm[j][i] = ~bigfsm[j][i]; +				bigfsm[j][i] &= ~QBSBIT; +			} +		bigfsm[EOB][i] = ~S_EOB; +		if (bigfsm[EOFC][i]>=0) +			bigfsm[EOFC][i] = ~S_EOF; +	} +} + +void +fixlex(void) +{ +	/* do C++ comments? */ +	if (Cplusplus==0) +		bigfsm['/'][COM1] = bigfsm['x'][COM1]; +} + +/* + * fill in a row of tokens from input, terminated by NL or END + * First token is put at trp->lp. + * Reset is non-zero when the input buffer can be "rewound." + * The value is a flag indicating that possible macros have + * been seen in the row. + */ +int +gettokens(Tokenrow *trp, int reset) +{ +	register int c, state, oldstate; +	register uchar *ip; +	register Token *tp, *maxp; +	int runelen; +	Source *s = cursource; +	int nmac = 0; + +	tp = trp->lp; +	ip = s->inp; +	if (reset) { +		s->lineinc = 0; +		if (ip>=s->inl) {		/* nothing in buffer */ +			s->inl = s->inb; +			fillbuf(s); +			ip = s->inp = s->inb; +		} else if (ip >= s->inb+(3*INS/4)) { +			memmove(s->inb, ip, 4+s->inl-ip); +			s->inl = s->inb+(s->inl-ip); +			ip = s->inp = s->inb; +		} +	} +	maxp = &trp->bp[trp->max]; +	runelen = 1; +	for (;;) { +	   continue2: +		if (tp>=maxp) { +			trp->lp = tp; +			tp = growtokenrow(trp); +			maxp = &trp->bp[trp->max]; +		} +		tp->type = UNCLASS; +		tp->hideset = 0; +		tp->t = ip; +		tp->wslen = 0; +		tp->flag = 0; +		state = START; +		for (;;) { +			oldstate = state; +			c = *ip; +			if ((state = bigfsm[c][state]) >= 0) { +				ip += runelen; +				runelen = 1; +				continue; +			} +			state = ~state; +		reswitch: +			switch (state&0177) { +			case S_SELF: +				ip += runelen; +				runelen = 1; +			case S_SELFB: +				tp->type = GETACT(state); +				tp->len = ip - tp->t; +				tp++; +				goto continue2; + +			case S_NAME:	/* like S_SELFB but with nmac check */ +				tp->type = NAME; +				tp->len = ip - tp->t; +				nmac |= quicklook(tp->t[0], tp->len>1?tp->t[1]:0); +				tp++; +				goto continue2; + +			case S_WS: +				tp->wslen = ip - tp->t; +				tp->t = ip; +				state = START; +				continue; + +			default: +				if ((state&QBSBIT)==0) { +					ip += runelen; +					runelen = 1; +					continue; +				} +				state &= ~QBSBIT; +				s->inp = ip; +				if (c=='?') { 	/* check trigraph */ +					if (trigraph(s)) { +						state = oldstate; +						continue; +					} +					goto reswitch; +				} +				if (c=='\\') { /* line-folding */ +					if (foldline(s)) { +						s->lineinc++; +						state = oldstate; +						continue; +					} +					goto reswitch; +				} +				error(WARNING, "Lexical botch in cpp"); +				ip += runelen; +				runelen = 1; +				continue; + +			case S_EOB: +				s->inp = ip; +				fillbuf(cursource); +				state = oldstate; +				continue; + +			case S_EOF: +				tp->type = END; +				tp->len = 0; +				s->inp = ip; +				if (tp!=trp->bp && (tp-1)->type!=NL && cursource->fd!=-1) +					error(WARNING,"No newline at end of file"); +				trp->lp = tp+1; +				return nmac; + +			case S_STNL: +				error(ERROR, "Unterminated string or char const"); +			case S_NL: +				tp->t = ip; +				tp->type = NL; +				tp->len = 1; +				tp->wslen = 0; +				s->lineinc++; +				s->inp = ip+1; +				trp->lp = tp+1; +				return nmac; + +			case S_EOFSTR: +				error(FATAL, "EOF in string or char constant"); +				break; + +			case S_COMNL: +				s->lineinc++; +				state = COM2; +				ip += runelen; +				runelen = 1; +				if (ip >= s->inb+(7*INS/8)) { /* very long comment */ +					memmove(tp->t, ip, 4+s->inl-ip); +					s->inl -= ip-tp->t; +					ip = tp->t+1; +				} +				continue; + +			case S_EOFCOM: +				error(WARNING, "EOF inside comment"); +				--ip; +			case S_COMMENT: +				++ip; +				tp->t = ip; +				tp->t[-1] = ' '; +				tp->wslen = 1; +				state = START; +				continue; +			} +			break; +		} +		ip += runelen; +		runelen = 1; +		tp->len = ip - tp->t; +		tp++; +	} +} + +/* have seen ?; handle the trigraph it starts (if any) else 0 */ +int +trigraph(Source *s) +{ +	int c; + +	while (s->inp+2 >= s->inl && fillbuf(s)!=EOF) +		; +	if (s->inp[1]!='?') +		return 0; +	c = 0; +	switch(s->inp[2]) { +	case '=': +		c = '#'; break; +	case '(': +		c = '['; break; +	case '/': +		c = '\\'; break; +	case ')': +		c = ']'; break; +	case '\'': +		c = '^'; break; +	case '<': +		c = '{'; break; +	case '!': +		c = '|'; break; +	case '>': +		c = '}'; break; +	case '-': +		c = '~'; break; +	} +	if (c) { +		*s->inp = c; +		memmove(s->inp+1, s->inp+3, s->inl-s->inp+2); +		s->inl -= 2; +	} +	return c; +} + +int +foldline(Source *s) +{ +	while (s->inp+1 >= s->inl && fillbuf(s)!=EOF) +		; +	if (s->inp[1] == '\n') { +		memmove(s->inp, s->inp+2, s->inl-s->inp+3); +		s->inl -= 2; +		return 1; +	} +	return 0; +} + +int +fillbuf(Source *s) +{ +	int n, nr; + +	nr = INS/8; +	if ((char *)s->inl+nr > (char *)s->inb+INS) +		error(FATAL, "Input buffer overflow"); +	if (s->fd<0 || (n=read(s->fd, (char *)s->inl, INS/8)) <= 0) +		n = 0; +	if ((*s->inp&0xff) == EOB) /* sentinel character appears in input */ +		*s->inp = EOFC; +	s->inl += n; +	s->inl[0] = s->inl[1]= s->inl[2]= s->inl[3] = EOB; +	if (n==0) { +		s->inl[0] = s->inl[1]= s->inl[2]= s->inl[3] = EOFC; +		return EOF; +	} +	return 0; +} + +/* + * Push down to new source of characters. + * If fd>0 and str==NULL, then from a file `name'; + * if fd==-1 and str, then from the string. + */ +Source * +setsource(char *name, int fd, char *str) +{ +	Source *s = new(Source); +	int len; + +	s->line = 1; +	s->lineinc = 0; +	s->fd = fd; +	s->filename = name; +	s->next = cursource; +	s->ifdepth = 0; +	cursource = s; +	/* slop at right for EOB */ +	if (str) { +		len = strlen(str); +		s->inb = domalloc(len+4); +		s->inp = s->inb; +		strncpy((char *)s->inp, str, len); +	} else { +		s->inb = domalloc(INS+4); +		s->inp = s->inb; +		len = 0; +	} +	s->inl = s->inp+len; +	s->inl[0] = s->inl[1] = EOB; +	return s; +} + +void +unsetsource(void) +{ +	Source *s = cursource; + +	if (s->fd>=0) { +		close(s->fd); +		dofree(s->inb); +	} +	cursource = s->next; +	dofree(s); +} diff --git a/src/tools/lcc/cpp/macro.c b/src/tools/lcc/cpp/macro.c new file mode 100644 index 0000000..49d1129 --- /dev/null +++ b/src/tools/lcc/cpp/macro.c @@ -0,0 +1,515 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "cpp.h" + +/* + * do a macro definition.  tp points to the name being defined in the line + */ +void +dodefine(Tokenrow *trp) +{ +	Token *tp; +	Nlist *np; +	Tokenrow *def, *args; + +	tp = trp->tp+1; +	if (tp>=trp->lp || tp->type!=NAME) { +		error(ERROR, "#defined token is not a name"); +		return; +	} +	np = lookup(tp, 1); +	if (np->flag&ISUNCHANGE) { +		error(ERROR, "#defined token %t can't be redefined", tp); +		return; +	} +	/* collect arguments */ +	tp += 1; +	args = NULL; +	if (tp<trp->lp && tp->type==LP && tp->wslen==0) { +		/* macro with args */ +		int narg = 0; +		tp += 1; +		args = new(Tokenrow); +		maketokenrow(2, args); +		if (tp->type!=RP) { +			int err = 0; +			for (;;) { +				Token *atp; +				if (tp->type!=NAME) { +					err++; +					break; +				} +				if (narg>=args->max) +					growtokenrow(args); +				for (atp=args->bp; atp<args->lp; atp++) +					if (atp->len==tp->len +					 && strncmp((char*)atp->t, (char*)tp->t, tp->len)==0) +						error(ERROR, "Duplicate macro argument"); +				*args->lp++ = *tp; +				narg++; +				tp += 1; +				if (tp->type==RP) +					break; +				if (tp->type!=COMMA) { +					err++; +					break; +				} +				tp += 1; +			} +			if (err) { +				error(ERROR, "Syntax error in macro parameters"); +				return; +			} +		} +		tp += 1; +	} +	trp->tp = tp; +	if (((trp->lp)-1)->type==NL) +		trp->lp -= 1; +	def = normtokenrow(trp); +	if (np->flag&ISDEFINED) { +		if (comparetokens(def, np->vp) +		 || (np->ap==NULL) != (args==NULL) +		 || (np->ap && comparetokens(args, np->ap))) +			error(ERROR, "Macro redefinition of %t", trp->bp+2); +	} +	if (args) { +		Tokenrow *tap; +		tap = normtokenrow(args); +		dofree(args->bp); +		args = tap; +	} +	np->ap = args; +	np->vp = def; +	np->flag |= ISDEFINED; +} + +/* + * Definition received via -D or -U + */ +void +doadefine(Tokenrow *trp, int type) +{ +	Nlist *np; +	static Token onetoken[1] = {{ NUMBER, 0, 0, 0, 1, (uchar*)"1" }}; +	static Tokenrow onetr = { onetoken, onetoken, onetoken+1, 1 }; + +	trp->tp = trp->bp; +	if (type=='U') { +		if (trp->lp-trp->tp != 2 || trp->tp->type!=NAME) +			goto syntax; +		if ((np = lookup(trp->tp, 0)) == NULL) +			return; +		np->flag &= ~ISDEFINED; +		return; +	} +	if (trp->tp >= trp->lp || trp->tp->type!=NAME) +		goto syntax; +	np = lookup(trp->tp, 1); +	np->flag |= ISDEFINED; +	trp->tp += 1; +	if (trp->tp >= trp->lp || trp->tp->type==END) { +		np->vp = &onetr; +		return; +	} +	if (trp->tp->type!=ASGN) +		goto syntax; +	trp->tp += 1; +	if ((trp->lp-1)->type == END) +		trp->lp -= 1; +	np->vp = normtokenrow(trp); +	return; +syntax: +	error(FATAL, "Illegal -D or -U argument %r", trp); +} +			 +/* + * Do macro expansion in a row of tokens. + * Flag is NULL if more input can be gathered. + */ +void +expandrow(Tokenrow *trp, char *flag) +{ +	Token *tp; +	Nlist *np; + +	if (flag) +		setsource(flag, -1, ""); +	for (tp = trp->tp; tp<trp->lp; ) { +		if (tp->type!=NAME +		 || quicklook(tp->t[0], tp->len>1?tp->t[1]:0)==0 +		 || (np = lookup(tp, 0))==NULL +		 || (np->flag&(ISDEFINED|ISMAC))==0 +		 || (tp->hideset && checkhideset(tp->hideset, np))) { +			tp++; +			continue; +		} +		trp->tp = tp; +		if (np->val==KDEFINED) { +			tp->type = DEFINED; +			if ((tp+1)<trp->lp && (tp+1)->type==NAME) +				(tp+1)->type = NAME1; +			else if ((tp+3)<trp->lp && (tp+1)->type==LP +			 && (tp+2)->type==NAME && (tp+3)->type==RP) +				(tp+2)->type = NAME1; +			else +				error(ERROR, "Incorrect syntax for `defined'"); +			tp++; +			continue; +		} +		if (np->flag&ISMAC) +			builtin(trp, np->val); +		else { +			expand(trp, np); +		} +		tp = trp->tp; +	} +	if (flag) +		unsetsource(); +} + +/* + * Expand the macro whose name is np, at token trp->tp, in the tokenrow. + * Return trp->tp at the first token next to be expanded + * (ordinarily the beginning of the expansion) + */ +void +expand(Tokenrow *trp, Nlist *np) +{ +	Tokenrow ntr; +	int ntokc, narg, i; +	Token *tp; +	Tokenrow *atr[NARG+1]; +	int hs; + +	copytokenrow(&ntr, np->vp);		/* copy macro value */ +	if (np->ap==NULL)			/* parameterless */ +		ntokc = 1; +	else { +		ntokc = gatherargs(trp, atr, &narg); +		if (narg<0) {			/* not actually a call (no '(') */ +			trp->tp++; +			return; +		} +		if (narg != rowlen(np->ap)) { +			error(ERROR, "Disagreement in number of macro arguments"); +			trp->tp->hideset = newhideset(trp->tp->hideset, np); +			trp->tp += ntokc; +			return; +		} +		substargs(np, &ntr, atr);	/* put args into replacement */ +		for (i=0; i<narg; i++) { +			dofree(atr[i]->bp); +			dofree(atr[i]); +		} +	} +	doconcat(&ntr);				/* execute ## operators */ +	hs = newhideset(trp->tp->hideset, np); +	for (tp=ntr.bp; tp<ntr.lp; tp++) {	/* distribute hidesets */ +		if (tp->type==NAME) { +			if (tp->hideset==0) +				tp->hideset = hs; +			else +				tp->hideset = unionhideset(tp->hideset, hs); +		} +	} +	ntr.tp = ntr.bp; +	insertrow(trp, ntokc, &ntr); +	trp->tp -= rowlen(&ntr); +	dofree(ntr.bp); +	return; +}	 + +/* + * Gather an arglist, starting in trp with tp pointing at the macro name. + * Return total number of tokens passed, stash number of args found. + * trp->tp is not changed relative to the tokenrow. + */ +int +gatherargs(Tokenrow *trp, Tokenrow **atr, int *narg) +{ +	int parens = 1; +	int ntok = 0; +	Token *bp, *lp; +	Tokenrow ttr; +	int ntokp; +	int needspace; + +	*narg = -1;			/* means that there is no macro call */ +	/* look for the ( */ +	for (;;) { +		trp->tp++; +		ntok++; +		if (trp->tp >= trp->lp) { +			gettokens(trp, 0); +			if ((trp->lp-1)->type==END) { +				trp->lp -= 1; +				trp->tp -= ntok; +				return ntok; +			} +		} +		if (trp->tp->type==LP) +			break; +		if (trp->tp->type!=NL) +			return ntok; +	} +	*narg = 0; +	ntok++; +	ntokp = ntok; +	trp->tp++; +	/* search for the terminating ), possibly extending the row */ +	needspace = 0; +	while (parens>0) { +		if (trp->tp >= trp->lp) +			gettokens(trp, 0); +		if (needspace) { +			needspace = 0; +			makespace(trp); +		} +		if (trp->tp->type==END) { +			trp->lp -= 1; +			trp->tp -= ntok; +			error(ERROR, "EOF in macro arglist"); +			return ntok; +		} +		if (trp->tp->type==NL) { +			trp->tp += 1; +			adjustrow(trp, -1); +			trp->tp -= 1; +			makespace(trp); +			needspace = 1; +			continue; +		} +		if (trp->tp->type==LP) +			parens++; +		else if (trp->tp->type==RP) +			parens--; +		trp->tp++; +		ntok++; +	} +	trp->tp -= ntok; +	/* Now trp->tp won't move underneath us */ +	lp = bp = trp->tp+ntokp; +	for (; parens>=0; lp++) { +		if (lp->type == LP) { +			parens++; +			continue; +		} +		if (lp->type==RP) +			parens--; +		if (lp->type==DSHARP) +			lp->type = DSHARP1;	/* ## not special in arg */ +		if ((lp->type==COMMA && parens==0) || (parens<0 && (lp-1)->type!=LP)) { +			if (*narg>=NARG-1) +				error(FATAL, "Sorry, too many macro arguments"); +			ttr.bp = ttr.tp = bp; +			ttr.lp = lp; +			atr[(*narg)++] = normtokenrow(&ttr); +			bp = lp+1; +		} +	} +	return ntok; +} + +/* + * substitute the argument list into the replacement string + *  This would be simple except for ## and # + */ +void +substargs(Nlist *np, Tokenrow *rtr, Tokenrow **atr) +{ +	Tokenrow tatr; +	Token *tp; +	int ntok, argno; + +	for (rtr->tp=rtr->bp; rtr->tp<rtr->lp; ) { +		if (rtr->tp->type==SHARP) {	/* string operator */ +			tp = rtr->tp; +			rtr->tp += 1; +			if ((argno = lookuparg(np, rtr->tp))<0) { +				error(ERROR, "# not followed by macro parameter"); +				continue; +			} +			ntok = 1 + (rtr->tp - tp); +			rtr->tp = tp; +			insertrow(rtr, ntok, stringify(atr[argno])); +			continue; +		} +		if (rtr->tp->type==NAME +		 && (argno = lookuparg(np, rtr->tp)) >= 0) { +			if ((rtr->tp+1)->type==DSHARP +			 || (rtr->tp!=rtr->bp && (rtr->tp-1)->type==DSHARP)) +				insertrow(rtr, 1, atr[argno]); +			else { +				copytokenrow(&tatr, atr[argno]); +				expandrow(&tatr, "<macro>"); +				insertrow(rtr, 1, &tatr); +				dofree(tatr.bp); +			} +			continue; +		} +		rtr->tp++; +	} +} + +/* + * Evaluate the ## operators in a tokenrow + */ +void +doconcat(Tokenrow *trp) +{ +	Token *ltp, *ntp; +	Tokenrow ntr; +	int len; + +	for (trp->tp=trp->bp; trp->tp<trp->lp; trp->tp++) { +		if (trp->tp->type==DSHARP1) +			trp->tp->type = DSHARP; +		else if (trp->tp->type==DSHARP) { +			char tt[128]; +			ltp = trp->tp-1; +			ntp = trp->tp+1; +			if (ltp<trp->bp || ntp>=trp->lp) { +				error(ERROR, "## occurs at border of replacement"); +				continue; +			} +			len = ltp->len + ntp->len; +			strncpy((char*)tt, (char*)ltp->t, ltp->len); +			strncpy((char*)tt+ltp->len, (char*)ntp->t, ntp->len); +			tt[len] = '\0'; +			setsource("<##>", -1, tt); +			maketokenrow(3, &ntr); +			gettokens(&ntr, 1); +			unsetsource(); +			if (ntr.lp-ntr.bp!=2 || ntr.bp->type==UNCLASS) +				error(WARNING, "Bad token %r produced by ##", &ntr); +			ntr.lp = ntr.bp+1; +			trp->tp = ltp; +			makespace(&ntr); +			insertrow(trp, (ntp-ltp)+1, &ntr); +			dofree(ntr.bp); +			trp->tp--; +		} +	} +} + +/* + * tp is a potential parameter name of macro mac; + * look it up in mac's arglist, and if found, return the + * corresponding index in the argname array.  Return -1 if not found. + */ +int +lookuparg(Nlist *mac, Token *tp) +{ +	Token *ap; + +	if (tp->type!=NAME || mac->ap==NULL) +		return -1; +	for (ap=mac->ap->bp; ap<mac->ap->lp; ap++) { +		if (ap->len==tp->len && strncmp((char*)ap->t,(char*)tp->t,ap->len)==0) +			return ap - mac->ap->bp; +	} +	return -1; +} + +/* + * Return a quoted version of the tokenrow (from # arg) + */ +#define	STRLEN	512 +Tokenrow * +stringify(Tokenrow *vp) +{ +	static Token t = { STRING }; +	static Tokenrow tr = { &t, &t, &t+1, 1 }; +	Token *tp; +	uchar s[STRLEN]; +	uchar *sp = s, *cp; +	int i, instring; + +	*sp++ = '"'; +	for (tp = vp->bp; tp < vp->lp; tp++) { +		instring = tp->type==STRING || tp->type==CCON; +		if (sp+2*tp->len >= &s[STRLEN-10]) { +			error(ERROR, "Stringified macro arg is too long"); +			break; +		} +		if (tp->wslen && (tp->flag&XPWS)==0) +			*sp++ = ' '; +		for (i=0, cp=tp->t; i<tp->len; i++) {	 +			if (instring && (*cp=='"' || *cp=='\\')) +				*sp++ = '\\'; +			*sp++ = *cp++; +		} +	} +	*sp++ = '"'; +	*sp = '\0'; +	sp = s; +	t.len = strlen((char*)sp); +	t.t = newstring(sp, t.len, 0); +	return &tr; +} + +/* + * expand a builtin name + */ +void +builtin(Tokenrow *trp, int biname) +{ +	char *op; +	Token *tp; +	Source *s; + +	tp = trp->tp; +	trp->tp++; +	/* need to find the real source */ +	s = cursource; +	while (s && s->fd==-1) +		s = s->next; +	if (s==NULL) +		s = cursource; +	/* most are strings */ +	tp->type = STRING; +	if (tp->wslen) { +		*outp++ = ' '; +		tp->wslen = 1; +	} +	op = outp; +	*op++ = '"'; +	switch (biname) { + +	case KLINENO: +		tp->type = NUMBER; +		op = outnum(op-1, s->line); +		break; + +	case KFILE: { +		char *src = s->filename; +		while ((*op++ = *src++) != 0) +			if (src[-1] == '\\') +				*op++ = '\\'; +		op--; +		break; +		} + +	case KDATE: +		strncpy(op, curtime+4, 7); +		strncpy(op+7, curtime+20, 4); +		op += 11; +		break; + +	case KTIME: +		strncpy(op, curtime+11, 8); +		op += 8; +		break; + +	default: +		error(ERROR, "cpp botch: unknown internal macro"); +		return; +	} +	if (tp->type==STRING) +		*op++ = '"'; +	tp->t = (uchar*)outp; +	tp->len = op - outp; +	outp = op; +} diff --git a/src/tools/lcc/cpp/nlist.c b/src/tools/lcc/cpp/nlist.c new file mode 100644 index 0000000..72089c4 --- /dev/null +++ b/src/tools/lcc/cpp/nlist.c @@ -0,0 +1,103 @@ +#include <stdio.h>
 +#include <stdlib.h>
 +#include <string.h>
 +#include "cpp.h"
 +
 +extern	char	*optarg;
 +extern	int	optind;
 +extern	int	verbose;
 +extern	int	Cplusplus;
 +Nlist	*kwdefined;
 +char	wd[128];
 +
 +#define	NLSIZE	128
 +
 +static Nlist	*nlist[NLSIZE];
 +
 +struct	kwtab {
 +	char	*kw;
 +	int	val;
 +	int	flag;
 +} kwtab[] = {
 +	{"if",		KIF,		ISKW},
 +	{"ifdef",	KIFDEF,		ISKW},
 +	{"ifndef",	KIFNDEF,	ISKW},
 +	{"elif",		KELIF,		ISKW},
 +	{"else",		KELSE,		ISKW},
 +	{"endif",	KENDIF,		ISKW},
 +	{"include",	KINCLUDE,	ISKW},
 +	{"define",	KDEFINE,	ISKW},
 +	{"undef",	KUNDEF,		ISKW},
 +	{"line",		KLINE,		ISKW},
 +	{"error",	KERROR,		ISKW},
 +	{"pragma",	KPRAGMA,	ISKW},
 +	{"eval",		KEVAL,		ISKW},
 +	{"defined",	KDEFINED,	ISDEFINED+ISUNCHANGE},
 +	{"__LINE__",	KLINENO,	ISMAC+ISUNCHANGE},
 +	{"__FILE__",	KFILE,		ISMAC+ISUNCHANGE},
 +	{"__DATE__",	KDATE,		ISMAC+ISUNCHANGE},
 +	{"__TIME__",	KTIME,		ISMAC+ISUNCHANGE},
 +	{"__STDC__",	KSTDC,		ISUNCHANGE},
 +	{NULL}
 +};
 +
 +unsigned long	namebit[077+1];
 +Nlist 	*np;
 +
 +void
 +setup_kwtab(void)
 +{
 +	struct kwtab *kp;
 +	Nlist *np;
 +	Token t;
 +	static Token deftoken[1] = {{ NAME, 0, 0, 0, 7, (uchar*)"defined" }};
 +	static Tokenrow deftr = { deftoken, deftoken, deftoken+1, 1 };
 +
 +	for (kp=kwtab; kp->kw; kp++) {
 +		t.t = (uchar*)kp->kw;
 +		t.len = strlen(kp->kw);
 +		np = lookup(&t, 1);
 +		np->flag = kp->flag;
 +		np->val = kp->val;
 +		if (np->val == KDEFINED) {
 +			kwdefined = np;
 +			np->val = NAME;
 +			np->vp = &deftr;
 +			np->ap = 0;
 +		}
 +	}
 +}
 +
 +Nlist *
 +lookup(Token *tp, int install)
 +{
 +	unsigned int h;
 +	Nlist *np;
 +	uchar *cp, *cpe;
 +
 +	h = 0;
 +	for (cp=tp->t, cpe=cp+tp->len; cp<cpe; )
 +		h += *cp++;
 +	h %= NLSIZE;
 +	np = nlist[h];
 +	while (np) {
 +		if (*tp->t==*np->name && tp->len==np->len 
 +		 && strncmp((char*)tp->t, (char*)np->name, tp->len)==0)
 +			return np;
 +		np = np->next;
 +	}
 +	if (install) {
 +		np = new(Nlist);
 +		np->vp = NULL;
 +		np->ap = NULL;
 +		np->flag = 0;
 +		np->val = 0;
 +		np->len = tp->len;
 +		np->name = newstring(tp->t, tp->len, 0);
 +		np->next = nlist[h];
 +		nlist[h] = np;
 +		quickset(tp->t[0], tp->len>1? tp->t[1]:0);
 +		return np;
 +	}
 +	return NULL;
 +}
 diff --git a/src/tools/lcc/cpp/tokens.c b/src/tools/lcc/cpp/tokens.c new file mode 100644 index 0000000..147569b --- /dev/null +++ b/src/tools/lcc/cpp/tokens.c @@ -0,0 +1,370 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "cpp.h" + +static char wbuf[2*OBS]; +static char *wbp = wbuf; + +/* + * 1 for tokens that don't need whitespace when they get inserted + * by macro expansion + */ +static const char wstab[] = { +	0,	/* END */ +	0,	/* UNCLASS */ +	0,	/* NAME */ +	0,	/* NUMBER */ +	0,	/* STRING */ +	0,	/* CCON */ +	1,	/* NL */ +	0,	/* WS */ +	0,	/* DSHARP */ +	0,	/* EQ */ +	0,	/* NEQ */ +	0,	/* LEQ */ +	0,	/* GEQ */ +	0,	/* LSH */ +	0,	/* RSH */ +	0,	/* LAND */ +	0,	/* LOR */ +	0,	/* PPLUS */ +	0,	/* MMINUS */ +	0,	/* ARROW */ +	1,	/* SBRA */ +	1,	/* SKET */ +	1,	/* LP */ +	1,	/* RP */ +	0,	/* DOT */ +	0,	/* AND */ +	0,	/* STAR */ +	0,	/* PLUS */ +	0,	/* MINUS */ +	0,	/* TILDE */ +	0,	/* NOT */ +	0,	/* SLASH */ +	0,	/* PCT */ +	0,	/* LT */ +	0,	/* GT */ +	0,	/* CIRC */ +	0,	/* OR */ +	0,	/* QUEST */ +	0,	/* COLON */ +	0,	/* ASGN */ +	1,	/* COMMA */ +	0,	/* SHARP */ +	1,	/* SEMIC */ +	1,	/* CBRA */ +	1,	/* CKET */ +	0,	/* ASPLUS */ + 	0,	/* ASMINUS */ + 	0,	/* ASSTAR */ + 	0,	/* ASSLASH */ + 	0,	/* ASPCT */ + 	0,	/* ASCIRC */ + 	0,	/* ASLSH */ +	0,	/* ASRSH */ + 	0,	/* ASOR */ + 	0,	/* ASAND */ +	0,	/* ELLIPS */ +	0,	/* DSHARP1 */ +	0,	/* NAME1 */ +	0,	/* DEFINED */ +	0,	/* UMINUS */ +}; + +void +maketokenrow(int size, Tokenrow *trp) +{ +	trp->max = size; +	if (size>0) +		trp->bp = (Token *)domalloc(size*sizeof(Token)); +	else +		trp->bp = NULL; +	trp->tp = trp->bp; +	trp->lp = trp->bp; +} + +Token * +growtokenrow(Tokenrow *trp) +{ +	int ncur = trp->tp - trp->bp; +	int nlast = trp->lp - trp->bp; + +	trp->max = 3*trp->max/2 + 1; +	trp->bp = (Token *)realloc(trp->bp, trp->max*sizeof(Token)); +	if (trp->bp == NULL) +		error(FATAL, "Out of memory from realloc"); +	trp->lp = &trp->bp[nlast]; +	trp->tp = &trp->bp[ncur]; +	return trp->lp; +} + +/* + * Compare a row of tokens, ignoring the content of WS; return !=0 if different + */ +int +comparetokens(Tokenrow *tr1, Tokenrow *tr2) +{ +	Token *tp1, *tp2; + +	tp1 = tr1->tp; +	tp2 = tr2->tp; +	if (tr1->lp-tp1 != tr2->lp-tp2) +		return 1; +	for (; tp1<tr1->lp ; tp1++, tp2++) { +		if (tp1->type != tp2->type +		 || (tp1->wslen==0) != (tp2->wslen==0) +		 || tp1->len != tp2->len +		 || strncmp((char*)tp1->t, (char*)tp2->t, tp1->len)!=0) +			return 1; +	} +	return 0; +} + +/* + * replace ntok tokens starting at dtr->tp with the contents of str. + * tp ends up pointing just beyond the replacement. + * Canonical whitespace is assured on each side. + */ +void +insertrow(Tokenrow *dtr, int ntok, Tokenrow *str) +{ +	int nrtok = rowlen(str); + +	dtr->tp += ntok; +	adjustrow(dtr, nrtok-ntok); +	dtr->tp -= ntok; +	movetokenrow(dtr, str); +	makespace(dtr); +	dtr->tp += nrtok; +	makespace(dtr); +} + +/* + * make sure there is WS before trp->tp, if tokens might merge in the output + */ +void +makespace(Tokenrow *trp) +{ +	uchar *tt; +	Token *tp = trp->tp; + +	if (tp >= trp->lp) +		return; +	if (tp->wslen) { +		if (tp->flag&XPWS +		 && (wstab[tp->type] || (trp->tp>trp->bp && wstab[(tp-1)->type]))) { +			tp->wslen = 0; +			return; +		} +		tp->t[-1] = ' '; +		return; +	} +	if (wstab[tp->type] || (trp->tp>trp->bp && wstab[(tp-1)->type])) +		return; +	tt = newstring(tp->t, tp->len, 1); +	*tt++ = ' '; +	tp->t = tt; +	tp->wslen = 1; +	tp->flag |= XPWS; +} + +/* + * Copy an entire tokenrow into another, at tp. + * It is assumed that there is enough space. + *  Not strictly conforming. + */ +void +movetokenrow(Tokenrow *dtr, Tokenrow *str) +{ +	int nby; + +	/* nby = sizeof(Token) * (str->lp - str->bp); */ +	nby = (char *)str->lp - (char *)str->bp; +	memmove(dtr->tp, str->bp, nby); +} + +/* + * Move the tokens in a row, starting at tr->tp, rightward by nt tokens; + * nt may be negative (left move). + * The row may need to be grown. + * Non-strictly conforming because of the (char *), but easily fixed + */ +void +adjustrow(Tokenrow *trp, int nt) +{ +	int nby, size; + +	if (nt==0) +		return; +	size = (trp->lp - trp->bp) + nt; +	while (size > trp->max) +		growtokenrow(trp); +	/* nby = sizeof(Token) * (trp->lp - trp->tp); */ +	nby = (char *)trp->lp - (char *)trp->tp; +	if (nby) +		memmove(trp->tp+nt, trp->tp, nby); +	trp->lp += nt; +} + +/* + * Copy a row of tokens into the destination holder, allocating + * the space for the contents.  Return the destination. + */ +Tokenrow * +copytokenrow(Tokenrow *dtr, Tokenrow *str) +{ +	int len = rowlen(str); + +	maketokenrow(len, dtr); +	movetokenrow(dtr, str); +	dtr->lp += len; +	return dtr; +} + +/* + * Produce a copy of a row of tokens.  Start at trp->tp. + * The value strings are copied as well.  The first token + * has WS available. + */ +Tokenrow * +normtokenrow(Tokenrow *trp) +{ +	Token *tp; +	Tokenrow *ntrp = new(Tokenrow); +	int len; + +	len = trp->lp - trp->tp; +	if (len<=0) +		len = 1; +	maketokenrow(len, ntrp); +	for (tp=trp->tp; tp < trp->lp; tp++) { +		*ntrp->lp = *tp; +		if (tp->len) { +			ntrp->lp->t = newstring(tp->t, tp->len, 1); +			*ntrp->lp->t++ = ' '; +			if (tp->wslen) +				ntrp->lp->wslen = 1; +		} +		ntrp->lp++; +	} +	if (ntrp->lp > ntrp->bp) +		ntrp->bp->wslen = 0; +	return ntrp; +} + +/* + * Debugging + */ +void +peektokens(Tokenrow *trp, char *str) +{ +	Token *tp; + +	tp = trp->tp; +	flushout(); +	if (str) +		fprintf(stderr, "%s ", str); +	if (tp<trp->bp || tp>trp->lp) +		fprintf(stderr, "(tp offset %d) ", tp-trp->bp); +	for (tp=trp->bp; tp<trp->lp && tp<trp->bp+32; tp++) { +		if (tp->type!=NL) { +			int c = tp->t[tp->len]; +			tp->t[tp->len] = 0; +			fprintf(stderr, "%s", tp->t); +			tp->t[tp->len] = c; +		} +		if (tp->type==NAME) { +			fprintf(stderr, tp==trp->tp?"{*":"{"); +			prhideset(tp->hideset); +			fprintf(stderr, "} "); +		} else +			fprintf(stderr, tp==trp->tp?"{%x*} ":"{%x} ", tp->type); +	} +	fprintf(stderr, "\n"); +	fflush(stderr); +} + +void +puttokens(Tokenrow *trp) +{ +	Token *tp; +	int len; +	uchar *p; + +	if (verbose) +		peektokens(trp, ""); +	tp = trp->bp; +	for (; tp<trp->lp; tp++) { +		len = tp->len+tp->wslen; +		p = tp->t-tp->wslen; +		while (tp<trp->lp-1 && p+len == (tp+1)->t - (tp+1)->wslen) { +			tp++; +			len += tp->wslen+tp->len; +		} +		if (len>OBS/2) {		/* handle giant token */ +			if (wbp > wbuf) +				write(1, wbuf, wbp-wbuf); +			write(1, (char *)p, len); +			wbp = wbuf; +		} else {	 +			memcpy(wbp, p, len); +			wbp += len; +		} +		if (wbp >= &wbuf[OBS]) { +			write(1, wbuf, OBS); +			if (wbp > &wbuf[OBS]) +				memcpy(wbuf, wbuf+OBS, wbp - &wbuf[OBS]); +			wbp -= OBS; +		} +	} +	trp->tp = tp; +	if (cursource->fd==0) +		flushout(); +} + +void +flushout(void) +{ +	if (wbp>wbuf) { +		write(1, wbuf, wbp-wbuf); +		wbp = wbuf; +	} +} + +/* + * turn a row into just a newline + */ +void +setempty(Tokenrow *trp) +{ +	trp->tp = trp->bp; +	trp->lp = trp->bp+1; +	*trp->bp = nltoken; +} + +/* + * generate a number + */ +char * +outnum(char *p, int n) +{ +	if (n>=10) +		p = outnum(p, n/10); +	*p++ = n%10 + '0'; +	return p; +} + +/* + * allocate and initialize a new string from s, of length l, at offset o + * Null terminated. + */ +uchar * +newstring(uchar *s, int l, int o) +{ +	uchar *ns = (uchar *)domalloc(l+o+1); + +	ns[l+o] = '\0'; +	return (uchar*)strncpy((char*)ns+o, (char*)s, l) - o; +} diff --git a/src/tools/lcc/cpp/unix.c b/src/tools/lcc/cpp/unix.c new file mode 100644 index 0000000..b7cf3af --- /dev/null +++ b/src/tools/lcc/cpp/unix.c @@ -0,0 +1,128 @@ +#include <stdio.h>
 +#include <stddef.h>
 +#include <stdlib.h>
 +#include <string.h>
 +#include "cpp.h"
 +
 +extern	int lcc_getopt(int, char *const *, const char *);
 +extern	char	*optarg, rcsid[];
 +extern	int	optind;
 +int	verbose;
 +int	Mflag;	/* only print active include files */
 +char	*objname; /* "src.$O: " */
 +int	Cplusplus = 1;
 +
 +void
 +setup(int argc, char **argv)
 +{
 +	int c, fd, i;
 +	char *fp, *dp;
 +	Tokenrow tr;
 +	extern void setup_kwtab(void);
 +	uchar *includeDirs[ NINCLUDE ] = { 0 };
 +	int   numIncludeDirs = 0;
 +
 +	setup_kwtab();
 +	while ((c = lcc_getopt(argc, argv, "MNOVv+I:D:U:F:lg")) != -1)
 +		switch (c) {
 +		case 'N':
 +			for (i=0; i<NINCLUDE; i++)
 +				if (includelist[i].always==1)
 +					includelist[i].deleted = 1;
 +			break;
 +		case 'I':
 +			includeDirs[ numIncludeDirs++ ] = newstring( (uchar *)optarg, strlen( optarg ), 0 );
 +			break;
 +		case 'D':
 +		case 'U':
 +			setsource("<cmdarg>", -1, optarg);
 +			maketokenrow(3, &tr);
 +			gettokens(&tr, 1);
 +			doadefine(&tr, c);
 +			unsetsource();
 +			break;
 +		case 'M':
 +			Mflag++;
 +			break;
 +		case 'v':
 +			fprintf(stderr, "%s %s\n", argv[0], rcsid);
 +			break;
 +		case 'V':
 +			verbose++;
 +			break;
 +		case '+':
 +			Cplusplus++;
 +			break;
 +		default:
 +			break;
 +		}
 +	dp = ".";
 +	fp = "<stdin>";
 +	fd = 0;
 +	if (optind<argc) {
 +		dp = basepath( argv[optind] );
 +		fp = (char*)newstring((uchar*)argv[optind], strlen(argv[optind]), 0);
 +		if ((fd = open(fp, 0)) <= 0)
 +			error(FATAL, "Can't open input file %s", fp);
 +	}
 +	if (optind+1<argc) {
 +		int fdo = creat(argv[optind+1], 0666);
 +		if (fdo<0)
 +			error(FATAL, "Can't open output file %s", argv[optind+1]);
 +		dup2(fdo, 1);
 +	}
 +	if(Mflag)
 +		setobjname(fp);
 +	includelist[NINCLUDE-1].always = 0;
 +	includelist[NINCLUDE-1].file = dp;
 +
 +	for( i = 0; i < numIncludeDirs; i++ )
 +		appendDirToIncludeList( (char *)includeDirs[ i ] );
 +
 +	setsource(fp, fd, NULL);
 +}
 +
 +
 +char *basepath( char *fname )
 +{
 +	char *dp = ".";
 +	char *p;
 +	if ((p = strrchr(fname, '/')) != NULL) {
 +		int dlen = p - fname;
 +		dp = (char*)newstring((uchar*)fname, dlen+1, 0);
 +		dp[dlen] = '\0';
 +	}
 +
 +	return dp;
 +}
 +
 +/* memmove is defined here because some vendors don't provide it at
 +   all and others do a terrible job (like calling malloc) */
 +// -- ouch, that hurts -- ln
 +#ifndef MACOS_X   /* always use the system memmove() on Mac OS X. --ryan. */
 +#ifdef memmove
 +#undef memmove
 +#endif
 +void *
 +memmove(void *dp, const void *sp, size_t n)
 +{
 +	unsigned char *cdp, *csp;
 +
 +	if (n<=0)
 +		return 0;
 +	cdp = dp;
 +	csp = (unsigned char *)sp;
 +	if (cdp < csp) {
 +		do {
 +			*cdp++ = *csp++;
 +		} while (--n);
 +	} else {
 +		cdp += n;
 +		csp += n;
 +		do {
 +			*--cdp = *--csp;
 +		} while (--n);
 +	}
 +	return 0;
 +}
 +#endif
 diff --git a/src/tools/lcc/doc/4.html b/src/tools/lcc/doc/4.html new file mode 100644 index 0000000..a2e1213 --- /dev/null +++ b/src/tools/lcc/doc/4.html @@ -0,0 +1,754 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<html> + +<head> +<link HREF="mailto:drh@microsoft.com" REV="made" TITLE="David R. Hanson"> +<title>The lcc 4.1 Code-Generation Interface</title> +</head> + +<body> + +<h1>The lcc 4.1 Code-Generation Interface</h1> + +<p ALIGN="LEFT"><strong><a HREF="http://www.research.microsoft.com/~cwfraser/">Christopher +W. Fraser</a> and <a HREF="http://www.research.microsoft.com/~drh/">David R. Hanson</a>, <a +HREF="http://www.research.microsoft.com/">Microsoft Research</a></strong></p> + +<h2>Contents</h2> + +<dir> +  <li><a HREF="#intro">Introduction</a> </li> +  <li><a HREF="#metrics">5.1 Type Metrics</a></li> +  <li><a HREF="#symbols">5.3 Symbols</a> </li> +  <li><a HREF="#operators">5.5 Dag Operators</a></li> +  <li><a HREF="#flags">5.6 Interface Flags</a></li> +  <li><a HREF="#definitions">5.8 Definitions</a></li> +  <li><a HREF="#constants">5.9 Constants</a></li> +  <li><a HREF="#upcalls">5.12 Upcalls</a></li> +</dir> + +<h2><a NAME="intro">Introduction</a></h2> + +<p>Version 4.1 is the latest release of <a +HREF="http://www.cs.princeton.edu/software/lcc/">lcc</a>, the ANSI C compiler described in +our book <cite>A Retargetable C Compiler: Design and Implementation</cite> +(Addison-Wesley, 1995, ISBN 0-8053-1670-1). This document summarizes the differences +between the 4.1 code-generation interface and the 3.x interface described in Chap. 5 of <cite>A +Retargetable C Compiler</cite>.</p> + +<p>Previous versions of lcc supported only three sizes of integers, two sizes of floats, +and insisted that pointers fit in unsigned integers (see Sec. 5.1 of <cite>A Retargetable +C Compiler</cite>). These assumptions simplified the compiler, and were suitable for +32-bit architectures. But on 64-bit architectures, such as the DEC ALPHA, it's natural to +have four sizes of integers and perhaps three sizes of floats, and on 16-bit +architectures, 32-bit pointers don't fit in unsigned integers. Also, the 3.x constaints +limited the use of lcc's back ends for other languages, such as Java.</p> + +<p>Version 4.x removes all of these restrictions: It supports any number of sizes for +integers and floats, and the size of pointers need not be related to the size of any of +the integer types. The major changes in the code-generation interface are:  + +<ul> +  <li>The number of type suffixes has been reduced to 6.</li> +  <li>Dag operators are composed of a generic operator, a type suffix, and a size.</li> +  <li>Unsigned variants of several operators have been added.</li> +  <li>Several interface functions have new signatures.</li> +</ul> + +<p>In addition, version 4.x is written in ANSI C and uses the standard I/O library and +other standard C functions.</p> + +<p>The sections below parallel the subsections of Chap. 5 of <cite>A Retargetable C +Compiler</cite> and summarize the differences between the 3.x and 4.x code-generation +interface. Unaffected subsections are omitted. Page citations refer to pages in <cite>A +Retargetable C Compiler</cite>.</p> + +<h2><a NAME="metrics">5.1 Type Metrics</a></h2> + +<p>There are now 10 metrics in an interface record:</p> + +<pre>Metrics charmetric; +Metrics shortmetric; +Metrics intmetric; +Metrics longmetric; +Metrics longlongmetric; +Metrics floatmetric; +Metrics doublemetric; +Metrics longdoublemetric; +Metrics ptrmetric; +Metrics structmetric;</pre> + +<p>Each of these specifies the size and alignment of the corresponding type. <code>ptrmetric</code> +describes all pointers.</p> + +<h2><a NAME="symbols">5.3 Symbols</a></h2> + +<p>The actual value of a constant is stored in the <code>u.c.v</code> field of a symbol, +which holds a <code>Value</code>:</p> + +<pre>typedef union value { +	long i; +	unsigned long u; +	long double d; +	void *p; +	void (*g)(void); +} Value;</pre> + +<p>The value is stored in the appropriate field according to its type, which is given by +the symbol's <code>type</code> field.</p> + +<h2><a NAME="operators">5.5 Dag Operators</a></h2> + +<p>The <code>op</code> field a of <code>node</code> structure holds a dag operator, which +consists of a generic operator, a type suffix, and a size indicator. The type suffixes +are:</p> + +<pre>enum { +	F=FLOAT, +	I=INT, +	U=UNSIGNED, +	P=POINTER, +	V=VOID, +	B=STRUCT +}; + +#define sizeop(n) ((n)<<10)</pre> + +<p>Given a generic operator <code>o</code>, a type suffix <code>t</code>, and a size <code>s</code>, +a type- and size-specific operator is formed by <code>o+t+sizeop(s)</code>. For example, <code>ADD+F+sizeop(4)</code> +forms the operator <code>ADDF4</code>, which denotes the sum of two 4-byte floats. +Similarly, <code>ADD+F+sizeop(8)</code> forms <code>ADDF8</code>, which denotes 8-byte +floating addition. In the 3.x code-generation interface, <code>ADDF</code> and <code>ADDD</code> +denoted these operations. There was no size indicator in the 3.x operators because the +type suffix supplied both a type and a size.</p> + +<p>Table 5.1 lists each generic operator, its valid type suffixes, and the number of <code>kids</code> +and <code>syms</code> that it uses; multiple values for <code>kids</code> indicate +type-specific variants. The notations in the <strong>syms</strong> column give the number +of <code>syms</code> values and a one-letter code that suggests their uses: 1V indicates +that <code>syms[0]</code> points to a symbol for a variable, 1C indicates that <code>syms[0]</code> +is a constant, and 1L indicates that <code>syms[0]</code> is a label. For 1S, <code>syms[0]</code> +is a constant whose value is a size in bytes; 2S adds <code>syms[1]</code>, which is a +constant whose value is an alignment. For most operators, the type suffix and size +indicator denote the type and size of operation to perform and the type and size of the +result.</p> + +<table WIDTH="100%" BORDER="0" CELLPADDING="0" CELLSPACING="0"> +  <tr> +    <td COLSPAN="6" ALIGN="CENTER"><strong>Table 5.1<img SRC="/~drh/resources/dot_clear.gif" +    ALT="|" WIDTH="18" HEIGHT="1">Node Operators.</strong></td> +  </tr> +  <tr> +    <td><strong>syms</strong></td> +    <td><strong>kids</strong></td> +    <td><strong>Operator</strong></td> +    <td><strong>Type Suffixes</strong></td> +    <td><strong>Sizes</strong></td> +    <td><strong>Operation</strong></td> +  </tr> +  <tr> +    <td>1V</td> +    <td>0</td> +    <td><code>ADDRF</code></td> +    <td><code>...P..</code></td> +    <td>p</td> +    <td>address of a parameter</td> +  </tr> +  <tr> +    <td>1V</td> +    <td>0</td> +    <td><code>ADDRG</code></td> +    <td><code>...P..</code></td> +    <td>p</td> +    <td>address of a global</td> +  </tr> +  <tr> +    <td>1V</td> +    <td>0</td> +    <td><code>ADDRL</code></td> +    <td><code>...P..</code></td> +    <td>p</td> +    <td>address of a local</td> +  </tr> +  <tr> +    <td>1C</td> +    <td>0</td> +    <td><code>CNST</code></td> +    <td><code>FIUP..</code></td> +    <td>fdx csilh p</td> +    <td>constant</td> +  </tr> +  <tr ALIGN="LEFT" VALIGN="TOP"> +    <td><img SRC="/~drh/resources/dot_clear.gif" ALT="|" WIDTH="1" HEIGHT="12"></td> +    <td></td> +    <td></td> +    <td></td> +    <td></td> +    <td></td> +  </tr> +  <tr> +    <td></td> +    <td>1</td> +    <td><code>BCOM</code></td> +    <td><code>.IU...</code></td> +    <td>ilh</td> +    <td>bitwise complement</td> +  </tr> +  <tr> +    <td>1S</td> +    <td>1</td> +    <td><code>CVF</code></td> +    <td><code>FI....</code></td> +    <td>fdx ilh</td> +    <td>convert from float</td> +  </tr> +  <tr> +    <td>1S</td> +    <td>1</td> +    <td><code>CVI</code></td> +    <td><code>FIU...</code></td> +    <td>fdx csilh csilhp</td> +    <td>convert from signed integer</td> +  </tr> +  <tr> +    <td>1S</td> +    <td>1</td> +    <td><code>CVP</code></td> +    <td><code>..U..</code></td> +    <td>p</td> +    <td>convert from pointer</td> +  </tr> +  <tr> +    <td>1S</td> +    <td>1</td> +    <td><code>CVU</code></td> +    <td><code>.IUP..</code></td> +    <td>csilh p</td> +    <td>convert from unsigned integer</td> +  </tr> +  <tr> +    <td></td> +    <td>1</td> +    <td><code>INDIR</code></td> +    <td><code>FIUP.B</code></td> +    <td>fdx csilh p</td> +    <td>fetch</td> +  </tr> +  <tr> +    <td></td> +    <td>1</td> +    <td><code>NEG</code></td> +    <td><code>FI....</code></td> +    <td>fdx ilh</td> +    <td>negation</td> +  </tr> +  <tr> +    <td><img SRC="/~drh/resources/dot_clear.gif" ALT="|" WIDTH="1" HEIGHT="12"></td> +    <td></td> +    <td></td> +    <td></td> +    <td></td> +    <td></td> +  </tr> +  <tr> +    <td></td> +    <td>2</td> +    <td><code>ADD</code></td> +    <td><code>FIUP..</code></td> +    <td>fdx ilh ilhp p</td> +    <td>addition</td> +  </tr> +  <tr> +    <td></td> +    <td>2</td> +    <td><code>BAND</code></td> +    <td><code>.IU...</code></td> +    <td>ilh</td> +    <td>bitwise AND</td> +  </tr> +  <tr> +    <td></td> +    <td>2</td> +    <td><code>BOR</code></td> +    <td><code>.IU...</code></td> +    <td>ilh</td> +    <td>bitwise inclusive OR</td> +  </tr> +  <tr> +    <td></td> +    <td>2</td> +    <td><code>BXOR</code></td> +    <td><code>.IU...</code></td> +    <td>ilh</td> +    <td>bitwise exclusive OR</td> +  </tr> +  <tr> +    <td></td> +    <td>2</td> +    <td><code>DIV</code></td> +    <td><code>FIU...</code></td> +    <td>fdx ilh</td> +    <td>division</td> +  </tr> +  <tr> +    <td></td> +    <td>2</td> +    <td><code>LSH</code></td> +    <td><code>.IU...</code></td> +    <td>ilh</td> +    <td>left shift</td> +  </tr> +  <tr> +    <td></td> +    <td>2</td> +    <td><code>MOD</code></td> +    <td><code>.IU...</code></td> +    <td>ilh</td> +    <td>modulus</td> +  </tr> +  <tr> +    <td></td> +    <td>2</td> +    <td><code>MUL</code></td> +    <td><code>FIU...</code></td> +    <td>fdx ilh</td> +    <td>multiplication</td> +  </tr> +  <tr> +    <td></td> +    <td>2</td> +    <td><code>RSH</code></td> +    <td><code>.IU...</code></td> +    <td>ilh</td> +    <td>right shift</td> +  </tr> +  <tr> +    <td></td> +    <td>2</td> +    <td><code>SUB</code></td> +    <td><code>FIUP..</code></td> +    <td>fdx ilh ilhp p</td> +    <td>subtraction</td> +  </tr> +  <tr> +    <td><img SRC="/~drh/resources/dot_clear.gif" ALT="|" WIDTH="1" HEIGHT="12"></td> +    <td></td> +    <td></td> +    <td></td> +    <td></td> +    <td></td> +  </tr> +  <tr> +    <td>2S</td> +    <td>2</td> +    <td><code>ASGN</code></td> +    <td><code>FIUP.B</code></td> +    <td>fdx csilh p</td> +    <td>assignment</td> +  </tr> +  <tr> +    <td>1L</td> +    <td>2</td> +    <td><code>EQ</code></td> +    <td><code>FIU...</code></td> +    <td>fdx ilh ilhp</td> +    <td>jump if equal</td> +  </tr> +  <tr> +    <td>1L</td> +    <td>2</td> +    <td><code>GE</code></td> +    <td><code>FIU...</code></td> +    <td>fdx ilh ilhp</td> +    <td>jump if greater than or equal</td> +  </tr> +  <tr> +    <td>1L</td> +    <td>2</td> +    <td><code>GT</code></td> +    <td><code>FIU...</code></td> +    <td>fdx ilh ilhp</td> +    <td>jump if greater than</td> +  </tr> +  <tr> +    <td>1L</td> +    <td>2</td> +    <td><code>LE</code></td> +    <td><code>FIU...</code></td> +    <td>fdx ilh ilhp</td> +    <td>jump if less than or equal</td> +  </tr> +  <tr> +    <td>1L</td> +    <td>2</td> +    <td><code>LT</code></td> +    <td><code>FIU...</code></td> +    <td>fdx ilh ilhp</td> +    <td>jump if less than</td> +  </tr> +  <tr> +    <td>1L</td> +    <td>2</td> +    <td><code>NE</code></td> +    <td><code>FIU...</code></td> +    <td>fdx ilh ilhp</td> +    <td>jump if not equal</td> +  </tr> +  <tr> +    <td></td> +    <td></td> +    <td></td> +    <td></td> +    <td></td> +    <td></td> +  </tr> +  <tr> +    <td>2S</td> +    <td>1</td> +    <td><code>ARG</code></td> +    <td><code>FIUP.B</code></td> +    <td>fdx ilh p</td> +    <td>argument</td> +  </tr> +  <tr> +    <td>1</td> +    <td>1 or 2</td> +    <td><code>CALL</code></td> +    <td><code>FIUPVB</code></td> +    <td>fdx ilh p</td> +    <td>function call</td> +  </tr> +  <tr> +    <td></td> +    <td>1</td> +    <td><code>RET</code></td> +    <td><code>FIUPV.</code></td> +    <td>fdx ilh p</td> +    <td>return from function</td> +  </tr> +  <tr> +    <td><img SRC="/~drh/resources/dot_clear.gif" ALT="|" WIDTH="1" HEIGHT="12"></td> +    <td></td> +    <td></td> +    <td></td> +    <td></td> +    <td></td> +  </tr> +  <tr> +    <td></td> +    <td>1</td> +    <td><code>JUMP</code></td> +    <td><code>....V.</code></td> +    <td></td> +    <td>unconditional jump</td> +  </tr> +  <tr> +    <td>1L</td> +    <td>0</td> +    <td><code>LABEL</code></td> +    <td><code>....V.</code></td> +    <td></td> +    <td>label definition</td> +  </tr> +</table> + +<p>The entries in the <strong>Sizes</strong> column indicate sizes of the operators that +back ends must implement. Letters denote the size of float (f), double (d), long double +(x), character (c), short integer (s), integer (i), long integer (l), "long +long" integer (h) , and pointer (p). These sizes are separated into sets for each +type suffix, except that a single set is used for both I and U when the set for I is +identical to the set for U.</p> + +<p>The actual values for the size indicators, fdxcsilhp, depend on the target. A +specification like <code>ADDF</code>f denotes the operator <code>ADD+F+sizeop(</code>f<code>)</code>, +where "f" is replaced by a target-dependent value, e.g., <code>ADDF4</code> and <code>ADDF8</code>. +For example, back ends must implement the following <code>CVI</code> and <code>MUL</code> +operators.</p> + +<blockquote> +  <p><code>CVIF</code>f <code>CVIF</code>d <code>CVIF</code>x<br> +  <code>CVII</code>c <code>CVII</code>s <code>CVII</code>i <code>CVII</code>l <code>CVII</code>h<br> +  <code>CVIU</code>c <code>CVIU</code>s <code>CVIU</code>i <code>CVIU</code>l <code>CVIU</code>h +  <code>CVIU</code>p<br> +  <br> +  <code>MULF</code>f <code>MULF</code>d <code>MULF</code>x<br> +  <code>MULI</code>i <code>MULI</code>l <code>MULI</code>h<br> +  <code>MULU</code>i <code>MULU</code>l <code>MULU</code>h</p> +</blockquote> + +<p>On most platforms, there are fewer than three sizes of floats and six sizes of +integers, and pointers are usually the same size as one of the integers. And lcc doesn't +support the "long long" type, so h is not currently used. So the set of +platform-specific operators is usually smaller than the list above suggests. For example, +the X86, SPARC, and MIPS back ends implement the following <code>CVI</code> and <code>MUL</code> +operators.</p> + +<blockquote> +  <p><code>CVIF</code>4 <code>CVIF</code>8<br> +  <code>CVII</code>1 <code>CVII</code>2 <code>CVII</code>4<br> +  <code>CVIU</code>1 <code>CVIU</code>2 <code>CVIU</code>4 <br> +  <br> +  <code>MULF</code>4 <code>MULF</code>8<br> +  <code>MULI</code>4<br> +  <code>MULU</code>4</p> +</blockquote> + +<p>The set of operators is thus target-dependent; for example, <code>ADDI8</code> appears +only if the target supports an 8-byte integer type. <a +HREF="ftp://ftp.cs.princeton.edu/pub/packages/lcc/contrib/ops.c"><code>ops.c</code></a> is +a program that, given a set of sizes, prints the required operators and their values, +e.g.,</p> + +<blockquote> +  <pre>% <em>ops c=1 s=2 i=4 l=4 h=4 f=4 d=8 x=8 p=4</em> +... + CVIF4=4225 CVIF8=8321 + CVII1=1157 CVII2=2181 CVII4=4229 + CVIU1=1158 CVIU2=2182 CVIU4=4230 +... + MULF4=4561 MULF8=8657 + MULI4=4565 + MULU4=4566 +... +131 operators</pre> +</blockquote> + +<p>The type suffix for a conversion operator denotes the type of the result and the size +indicator gives the size of the result. For example, <code>CVUI4</code> converts an +unsigned (<code>U</code>) to a 4-byte signed integer (<code>I4</code>). The <code>syms[0]</code> +field points to a symbol-table entry for a integer constant that gives the size of the +source operand. For example, if <code>syms[0]</code> in a <code>CVUI4</code> points to a +symbol-table entry for 2, the conversion widens a 2-byte unsigned integer to a 4-byte +signed integer. Conversions that widen unsigned integers zero-extend; those that widen +signed integers sign-extend.</p> + +<p>The front end composes conversions between types <em>T</em><sub>1</sub> and <em>T</em><sub>2</sub> +by widening <em>T</em><sub>1</sub> to it's "supertype", if necessary, converting +that result to <em>T</em><sub>2</sub>'s supertype, then narrowing the result to <em>T</em><sub>2</sub>, +if necessary. The following table lists the supertypes; omitted entries are their own +supertypes.</p> + +<blockquote> +  <table BORDER="0" CELLPADDING="0" CELLSPACING="0"> +    <tr> +      <td><strong>Type</strong></td> +      <td><img SRC="/~drh/resources/dot_clear.gif" ALT="|" WIDTH="24" HEIGHT="1"></td> +      <td><strong>Supertype</strong></td> +    </tr> +    <tr> +      <td>signed char</td> +      <td></td> +      <td>int</td> +    </tr> +    <tr> +      <td>signed short</td> +      <td></td> +      <td>int</td> +    </tr> +    <tr ALIGN="LEFT" VALIGN="TOP"> +      <td>unsigned char</td> +      <td></td> +      <td>int, if sizeof (char) < sizeof (int)<br> +      unsigned, otherwise</td> +    </tr> +    <tr ALIGN="LEFT" VALIGN="TOP"> +      <td>unsigned short</td> +      <td></td> +      <td>int, if sizeof (short) < sizeof (int)<br> +      unsigned, otherwise</td> +    </tr> +    <tr ALIGN="LEFT" VALIGN="TOP"> +      <td>void *</td> +      <td></td> +      <td>an unsigned type as large as a pointer</td> +    </tr> +  </table> +</blockquote> + +<p>Pointers are converted to an unsigned type of the same size, even when that type is not +one of the integer types.</p> + +<p>For example, the front end converts a signed short to a float by first converting it to +an int and then to a float. It converts an unsigned short to an int with a single <code>CVUI</code>i +conversion, when shorts are smaller than ints.</p> + +<p>There are now signed and unsigned variants of <code>ASGN</code>, <code>INDIR</code>, <code>BCOM</code>, +<code>BOR</code>, <code>BXOR</code>, <code>BAND</code>, <code>ARG</code>, <code>CALL</code>, +and <code>RET</code> to simplify code generation on platforms that use different +instructions or register set for signed and unsigned operations. Likewise there are now +pointer variants of <code>ASGN</code>, <code>INDIR</code>, <code>ARG</code>, <code>CALL</code>, +and <code>RET</code>.</p> + +<h2><a NAME="flags">5.6 Interface Flags</a></h2> + +<pre>unsigned unsigned_char:1;</pre> + +<p>tells the front end whether plain characters are signed or unsigned. If it's zero, char +is a signed type; otherwise, char is an unsigned type.</p> + +<p>All the interface flags can be set by command-line options, e.g., <code>-Wf-unsigned_char=1</code> +causes plain characters to be unsigned.</p> + +<h2><a NAME="definitions">5.8 Definitions</a></h2> + +<p>The front end announces local variables by calling</p> + +<pre>void (*local)(Symbol);</pre> + +<p>It announces temporaries likewise; these have the symbol's <code>temporary</code> flag +set, which indicates that the symbol will be used only in the next call to <code>gen</code>. +If a temporary's <code>u.t.cse</code> field is nonnull, it points to the node that +computes the value assigned to the temporary; see page 346.</p> + +<p>The front end calls</p> + +<pre>void (*address)(Symbol p, Symbol q, long n);</pre> + +<p>to initialize <code>q</code> to a symbol that represents an address of the form <em>x</em>+<code>n</code>, +where <em>x</em> is the address represented by <code>p</code> and the long integer <code>n</code> +is positive or negative.</p> + +<h2><a NAME="constants">5.9 Constants</a></h2> + +<p>The interface function</p> + +<pre>void (*defconst)(int suffix, int size, Value v);</pre> + +<p>initializes constants. defconst emits directives to define a cell and initialize it to +a constant value. v is the constant value, suffix identifies the type of the value, and +size is the size of the value in bytes. The value of suffix indicates which field of v +holds the value, as shown in the following table.</p> + +<blockquote> +  <table BORDER="0" CELLPADDING="1" CELLSPACING="1"> +    <tr> +      <td><strong>suffix</strong></td> +      <td><img SRC="/~drh/resources/dot_clear.gif" ALT="|" WIDTH="24" HEIGHT="1"></td> +      <td><strong>v Field</strong></td> +      <td><img SRC="/~drh/resources/dot_clear.gif" ALT="|" WIDTH="24" HEIGHT="1"></td> +      <td><strong>size</strong></td> +    </tr> +    <tr> +      <td><code>F</code></td> +      <td></td> +      <td><code>v.d</code></td> +      <td></td> +      <td>float, double, long double</td> +    </tr> +    <tr> +      <td><code>I</code></td> +      <td></td> +      <td><code>v.i</code></td> +      <td></td> +      <td>signed char, signed short, signed int, signed long</td> +    </tr> +    <tr> +      <td><code>U</code></td> +      <td></td> +      <td><code>v.u</code></td> +      <td></td> +      <td>unsigned char, unsigned short, unsigned int, unsigned long</td> +    </tr> +    <tr> +      <td><code>P</code></td> +      <td></td> +      <td><code>v.p</code></td> +      <td></td> +      <td>void *</td> +    </tr> +  </table> +</blockquote> + +<p><code>defconst</code> must narrow <code>v.</code>x when <code>size</code> is less than <code>sizeof</code> +<code>v.</code>x; e.g., to emit an unsigned char, <code>defconst</code> should emit <code>(unsigned +char)v.i</code>.</p> + +<h2><a NAME="upcalls">5.12 Upcalls</a></h2> + +<p>lcc 4.x uses standard I/O and its I/O functions have been changed accordingly. lcc +reads input from the standard input, emits code to the standard output, and writes +diagnostics to the standard error output. It uses <code>freopen</code> to redirect these +streams to explicit files, when necessary.</p> + +<p><code>bp</code>, <code>outflush</code>, and <code>outs</code> have been eliminated.</p> + +<pre>extern void fprint(FILE *f, const char *fmt, ...); +extern void  print(const char *fmt, ...);</pre> + +<p>print formatted data to file <code>f</code> (<code>fprint</code>) or the standard +output (<code>print</code>). These functions are like standard C's <code>printf</code> and +<code>fprintf</code>, but support only some of the standard conversion specifiers and do +not support flags, precision, and field-width specifications. They support the following +new conversion specifiers in addition to those described on page 99.</p> + +<blockquote> +  <table BORDER="0" CELLPADDING="0" CELLSPACING="0"> +    <tr> +      <td><strong>Specifiers</strong></td> +      <td><img SRC="/~drh/resources/dot_clear.gif" ALT="|" WIDTH="24" HEIGHT="1"></td> +      <td><strong>Corresponding printf Specifiers</strong></td> +    </tr> +    <tr> +      <td><code>%c</code></td> +      <td></td> +      <td><code>%c</code></td> +    </tr> +    <tr> +      <td><code>%d %D</code></td> +      <td></td> +      <td><code>%d %ld</code></td> +    </tr> +    <tr> +      <td><code>%u %U</code></td> +      <td></td> +      <td><code>%u %lu</code></td> +    </tr> +    <tr> +      <td><code>%x %X</code></td> +      <td></td> +      <td><code>%x %lx</code></td> +    </tr> +    <tr> +      <td><code>%f %e %g</code></td> +      <td></td> +      <td><code>%e %f %g</code></td> +    </tr> +    <tr ALIGN="LEFT" VALIGN="TOP"> +      <td><code>%p</code></td> +      <td></td> +      <td>Converts the corresponding void * argument to unsigned long and prints it with the <code>printf</code> +      <code>%#x</code> specifier or just <code>%x</code> when the argument is null.</td> +    </tr> +    <tr ALIGN="LEFT" VALIGN="TOP"> +      <td><code>%I</code></td> +      <td></td> +      <td>Prints the number of spaces given by the corresponding argument.</td> +    </tr> +  </table> +</blockquote> + +<pre>#define generic(op)  ((op)&0x3F0) +#define specific(op) ((op)&0x3FF)</pre> + +<p><code>generic(op)</code> returns the generic variant of <code>op</code>; that is, +without its type suffix and size indicator. <code>specific(op)</code> returns the +type-specific variant of <code>op</code>; that is, without its size indicator.</p> + +<p><code>newconst</code> has been replaced by</p> + +<pre>extern Symbol intconst(int n);</pre> + +<p>which installs the integer constant <code>n</code> in the symbol table, if necessary, +and returns a pointer to the symbol-table entry.</p> + +<hr> + +<address> +  <a HREF="http://www.research.microsoft.com/~cwfraser/">Chris Fraser</a> / <a +  HREF="mailto:cwfraser@microsoft.com">cwfraser@microsoft.com</a><br> +  <a HREF="http://www.research.microsoft.com/~drh/">David Hanson</a> / <a +  HREF="mailto:drh@microsoft.com">drh@microsoft.com</a><br> +  $Revision: 145 $ $Date: 2001-10-17 16:53:10 -0500 (Wed, 17 Oct 2001) $  +</address> +</body> +</html> diff --git a/src/tools/lcc/doc/bprint.1 b/src/tools/lcc/doc/bprint.1 new file mode 100644 index 0000000..8cf9971 --- /dev/null +++ b/src/tools/lcc/doc/bprint.1 @@ -0,0 +1,83 @@ +.\" $Id: bprint.1 145 2001-10-17 21:53:10Z timo $ +.TH BPRINT 1 "local \- $Date: 2001-10-17 16:53:10 -0500 (Wed, 17 Oct 2001) $" +.SH NAME +bprint \- expression profiler +.SH SYNOPSIS +.B bprint +[ +.I option ... +] +[ +.I file ... +] +.SH DESCRIPTION +.I bprint +produces on the standard output a listing of the programs compiled by +.I lcc +with the +.B \-b +option. +Executing an +.B a.out +so compiled appends profiling data to +.BR prof.out . +The first token of each expression in the listing is preceded +by the number of times it was executed +enclosed in angle brackets as determined from the data in +.BR prof.out . +.I bprint +interprets the following options. +.TP +.B \-c +Compress the +.B prof.out +file, which otherwise grows with every execution of +.BR a.out . +.TP +.B \-b +Print an annotated listing as described above. +.TP +.B \-n +Include line numbers in the listing. +.TP +.B \-f +Print only the number of invocations of each function. +A second +.B \-f +summarizes call sites instead of callers. +.TP +.BI \-I \*Sdir +specifies additional directories in which to seek +files given in +.B prof.out +that do not begin with `/'. +.PP +If any file names are given, only the requested data for those files are printed +in the order presented. +If no options are given, +.B \-b +is assumed. +.SH FILES +.PP +.ta \w'$LCCDIR/liblcc.{a,lib}XX'u +.nf +prof.out	profiling data +$LCCDIR/liblcc.{a,lib}	\fIlcc\fP-specific library +.SH "SEE ALSO" +.IR lcc (1),  +.IR prof (1) +.SH BUGS +Macros and comments can confuse +.I bprint +because it uses post-expansion source coordinates +to annotate pre-expansion source files. +If +.I bprint +sees that it's about to print a statement count +.I inside +a number or identifier, it moves the count to just +.I before +the token. +.PP +Can't cope with an ill-formed +.BR prof.out . diff --git a/src/tools/lcc/doc/bprint.pdf b/src/tools/lcc/doc/bprint.pdf Binary files differnew file mode 100644 index 0000000..1b11963 --- /dev/null +++ b/src/tools/lcc/doc/bprint.pdf diff --git a/src/tools/lcc/doc/install.html b/src/tools/lcc/doc/install.html new file mode 100644 index 0000000..3cc59a8 --- /dev/null +++ b/src/tools/lcc/doc/install.html @@ -0,0 +1,796 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<html> + +<head> +<link HREF="mailto:drh@cs.princeton.edu" REV="made" TITLE="David R. Hanson"> +<title>Installing lcc</title> +</head> + +<body> + +<h1>Installing lcc</h1> + +<p ALIGN="LEFT"><strong><a HREF="http://www.research.microsoft.com/~cwfraser/">Christopher +W. Fraser</a> and <a HREF="http://www.research.microsoft.com/~drh/">David R. Hanson</a>, <a +HREF="http://www.research.microsoft.com/">Microsoft Research</a></strong></p> + +<h2>Contents</h2> + +<dir> +  <li><a HREF="#intro">Introduction</a></li> +  <li><a HREF="#unix">Installation on UNIX</a></li> +  <li><a HREF="#driver">Building the Driver</a></li> +  <li><a HREF="#rcc">Building the Compiler and Accessories</a></li> +  <li><a HREF="#win32">Installation on Windows NT 4.0 and Windows 95/98</a></li> +  <li><a HREF="#bugs">Reporting Bugs</a></li> +  <li><a HREF="#mailinglist">Keeping in Touch</a></li> +</dir> + +<h2><a NAME="intro">Introduction</a></h2> + +<p><a HREF="http://www.cs.princeton.edu/software/lcc/">lcc</a> is the ANSI C compiler +described in our book <cite>A Retargetable C Compiler: Design and Implementation</cite> +(Addison-Wesley, 1995, ISBN 0-8053-1670-1).</p> + +<p>If you're installing lcc on a UNIX system, read the remainder of this section and +continue with the next section. If you're installing lcc on a Windows NT 4.0 or Windows +95/98 system, and you intend only to <u>use</u> lcc, you can run the <a +href="ftp://ftp.cs.princeton.edu/pub/packages/lcc/lcc41.exe">InstallShield executable</a>, +which installs the binaries and the documentation. If you want to <u>modify</u> lcc or <u>rebuild</u> +it from the source files, you need the <a +href="ftp://ftp.cs.princeton.edu/packages/lcc/lcc41.zip">complete distribution</a>, and +you should read the rest of the section, the following three sections, and the <a +HREF="#win32">Windows NT/95/98</a> section.</p> + +<p>Extract the distribution into its own directory. All non-absolute paths below are +relative to this directory. The distribution holds the following subdirectories.</p> + +<blockquote> +  <table BORDER="0" CELLPADDING="1" CELLSPACING="1" WIDTH="80%"> +    <tr> +      <td><a HREF="../src"><code>src</code></a></td> +      <td></td> +      <td>source code</td> +    </tr> +    <tr> +      <td><a HREF="../etc"><code>etc</code></a></td> +      <td></td> +      <td>driver, accessories</td> +    </tr> +    <tr> +      <td><a HREF="../lib"><code>lib</code></a></td> +      <td></td> +      <td>runtime library source code</td> +    </tr> +    <tr> +      <td><a HREF="../cpp"><code>cpp</code></a></td> +      <td></td> +      <td>preprocessor source code</td> +    </tr> +    <tr> +      <td><a HREF="../lburg"><code>lburg</code></a></td> +      <td></td> +      <td>code-generator generator source code</td> +    </tr> +    <tr> +      <td><a HREF="../doc"><code>doc</code></a></td> +      <td></td> +      <td>this document, man pages</td> +    </tr> +    <tr> +      <td><code><a HREF="../include">include</a>/*/*</code></td> +      <td></td> +      <td>include files</td> +    </tr> +    <tr> +      <td><a HREF="../tst"><code>tst</code></a></td> +      <td></td> +      <td>test suite</td> +    </tr> +    <tr> +      <td><code><a HREF="../alpha">alpha</a>/*/tst</code></td> +      <td></td> +      <td>ALPHA test outputs</td> +    </tr> +    <tr> +      <td><code><a HREF="../mips">mips</a>/*/tst</code></td> +      <td></td> +      <td>MIPS test outputs</td> +    </tr> +    <tr> +      <td><code><a HREF="../sparc">sparc</a>/*/tst</code></td> +      <td></td> +      <td>SPARC test outputs</td> +    </tr> +    <tr> +      <td><code><a HREF="../x86">x86</a>/*/tst</code></td> +      <td></td> +      <td>X86 test outputs</td> +    </tr> +  </table> +</blockquote> + +<p><code>doc/install.html</code> is the HTML file for this document. <a HREF="4.html"><code>doc/4.html</code></a> +describes the internal differences between lcc 3.x and 4.1.</p> + +<p>The installation makefile is designed so that lcc can be installed from a read-only +file system or directory, which is common in networked environments, so the distribution +can be unloaded on a central file server. <strong>You will need an existing ANSI/ISO C +compiler to build and install lcc.</strong></p> + +<h2><a NAME="unix">Installation on UNIX</a></h2> + +<p>The compilation components (the preprocessor, include files, and compiler proper, etc.) +are installed in a single <em>build directory</em>. On multi-platform systems supported by +a central file server, it's common to store the build directory in a location specific to +the platform and to the version of lcc, and to point a symbolic link to this location. For +example,</p> + +<blockquote> +  <pre>% ln -s /usr/local/lib/lcc-4.1/sparc-solaris /usr/local/lib/lcc</pre> +</blockquote> + +<p>points <code>/usr/local/lib/lcc</code> to a build directory for lcc version 4.1 on the +SPARC under Solaris. Links into <code>/usr/local/lib</code> are created for the programs <code>lcc</code> +and <code>bprint</code>. Thus, a new distribution can be installed by building it in its +own build directory and changing one symbolic link to point to that directory. If these +conventions or their equivalents are followed, the host-specific parts of the driver +program, <code>lcc</code>, can be used unmodified.</p> + +<p>Installation on a UNIX system involves the following steps. Below, the build directory +is referred to as <code>BUILDDIR</code>.  + +<ol> +  <li>Create the build directory, using a version- and platform-specific naming convention as +    suggested above, and record the name of this directory in the <code>BUILDDIR</code> +    environment variable:<blockquote> +      <pre>% setenv BUILDDIR /usr/local/lib/lcc-4.1/sparc-solaris +% mkdir -p $BUILDDIR</pre> +    </blockquote> +    <p>Here and below, commands assume the C shell. Also, you'll need a version of <code>mkdir</code> +    that supports the <code>-p</code> option, which creates intermediate directories as +    necessary.</p> +  </li> +  <li>Copy the man pages to the repository for local man pages, e.g.,<blockquote> +      <pre>% cp doc/*.1 /usr/local/man/man1</pre> +    </blockquote> +    <p>Some users copy the man pages to the build directory and create the appropriate +    symbolic links, e.g., </p> +    <blockquote> +      <pre>% cp doc/*.1 $BUILDDIR +% ln -s $BUILDDIR/*.1 /usr/local/man/man1</pre> +    </blockquote> +  </li> +  <li>Platform-specific include files are in directories named <code>include/</code><em>target</em><code>/</code><em>os</em>. +    Create the include directory in the build directory, and copy the include hierarchy for +    your platform to this directory, e.g.,<blockquote> +      <pre>% mkdir $BUILDDIR/include +% cp -p -R include/sparc/solaris/* $BUILDDIR/include</pre> +    </blockquote> +    <p>Again, some users create a symbolic link to the appropriate directory in the +    distribution instead of copying the include files. For example, at Princeton, the +    distributions are stored under <code>/proj/pkg/lcc</code>, so the included files are +    "installed" by creating one symbolic link: </p> +    <blockquote> +      <pre>% ln -s /proj/pkg/lcc/4.1/include/sparc/solaris $BUILDDIR/include</pre> +    </blockquote> +    <p>If you're installing lcc on Linux, you <em>must</em> also plant a symbolic link named <code>gcc</code> +    to gcc's library directory, because lcc uses gcc's C preprocessor and most of gcc's header +    files:</p> +    <blockquote> +      <pre>% ln -s /usr/lib/gcc-lib/i486-linux/2.7.2.2 $BUILDDIR/gcc</pre> +    </blockquote> +    <p>The library directory shown above may be different on your Linux machine; to determine +    the correct directory, browse <code>/usr/lib/gcc-lib</code>, or execute</p> +    <blockquote> +      <pre>% cc -v tst/8q.c</pre> +    </blockquote> +    <p>and examine the diagnostic output. Make sure that <code>$BUILDDIR/gcc/cpp</code> and <code>$BUILDDIR/gcc/include</code> +    point to, respectively, gcc's C preprocessor and header files. On Linux, lcc looks for +    include files in <code>$BUILDDIR/include</code>, <code>$BUILDDIR/gcc/include</code>, and <code>/usr/include</code>, +    in that order; see <a HREF="#driver"><em>Building the Driver</em></a> and <a +    href="../etc/linux.c"><code>etc/linux.c</code></a> for details.</p> +  </li> +  <li>The <a HREF="../makefile"><code>makefile</code></a> includes the file named by the <code>CUSTOM</code> +    macro; the default is <code>custom.mk</code>, and an empty <code>custom.mk</code> is +    included in the distribution. If desired, prepare a site-specification customization file +    and define <code>CUSTOM</code> to the path of that file when invoking make in steps 5 and +    6, e.g.,<blockquote> +      <pre>make CUSTOM=/users/drh/solaris.mk</pre> +    </blockquote> +    <p>You can, for example, use customization files to record site-specific values for macros +    instead of using environment variables, and to record targets for the steps in this list.</p> +  </li> +  <li>Build the host-specific driver, creating a custom host-specific part, if necessary. See <a +    HREF="#driver"><em>Building the Driver</em></a>.</li> +  <li>Build the preprocessor, compiler proper, library, and other accessories. See <a +    HREF="#rcc"><em>Building the Compiler</em></a>.</li> +  <li>Plant symbolic links to the build directory and to the installed programs, e.g.,<blockquote> +      <pre>% ln -s $BUILDDIR /usr/local/lib/lcc +% ln -s /usr/local/lib/{lcc,bprint} /usr/local/bin</pre> +    </blockquote> +    <p>Some users copy <code>bprint</code> and <code>lcc</code> into <code>/usr/local/bin</code> +    instead of creating symbolic links. The advantange of creating the links for <code>lcc</code> +    and <code>bprint</code> as shown is that, once established, they point indirectly to +    whatever <code>/usr/local/lib/lcc</code> points to; installing a new version of lcc, say, +    4.2, can be done by changing <code>/usr/local/lib/lcc</code> to point to the 4.2 build +    directory.</p> +  </li> +</ol> + +<h2><a NAME="driver">Building the Driver</a></h2> + +<p>The preprocessor, compiler, assembler, and loader are invoked by a driver program, <code>lcc</code>, +which is similar to <code>cc</code> on most systems. It's described in the man page <code>doc/lcc.1</code>. +The driver is built by combining the host-independent part, <a href="../etc/lcc.c"><code>etc/lcc.c</code></a>, +with a small host-specific part. Distributed host-specific parts are named <code>etc/</code><em>os</em><code>.c</code>, +where <em>os</em> is the name of the operating system for the host on which <code>lcc</code> +is being installed. If you're following the installations conventions described above, you +can probably use one of the host-specific parts unmodified; otherwise, pick one that is +closely related to your platform, copy it to <em>whatever</em><code>.c</code>, and edit it +as described below. You should not have to edit <code>etc/lcc.c</code>.</p> + +<p>We'll use <a HREF="../etc/solaris.c"><code>etc/solaris.c</code></a> as an example in +describing how the host-specific part works. This example illustrates all the important +features. Make sure you have the environment variable <code>BUILDDIR</code> set correctly, +and build the driver with a <code>make</code> command, e.g.,</p> + +<blockquote> +  <pre>% make HOSTFILE=etc/solaris.c lcc +cc -g -c -DTEMPDIR=\"/tmp\" -o /usr/local/lib/lcc-4.1/sparc-solaris/lcc.o etc/lcc.c +cc -g -c -o /usr/local/lib/lcc-4.1/sparc-solaris/host.o etc/solaris.c +cc -g -o /usr/local/lib/lcc-4.1/sparc-solaris/lcc /usr/local/lib/lcc-4.1/sparc-solaris/lcc.o /usr/local/lib/lcc-4.1/sparc-solaris/host.o</pre> +</blockquote> + +<p>The symbolic name <code>HOSTFILE</code> specifies the path to the host-specific part, +either one in the distribution or <em>whatever</em><code>.c</code>. Some versions of make +may require the <code>-e</code> option in order to read the environment.</p> + +<p>Here's <code>etc/solaris.c</code>:</p> + +<blockquote> +  <pre>/* Sparcs running Solaris 2.5.1 at CS Dept., Princeton University */ + +#include <string.h> + +static char rcsid[] = "$ Id: solaris.c,v 1.10 1998/09/14 20:36:33 drh Exp $"; + +#ifndef LCCDIR +#define LCCDIR "/usr/local/lib/lcc/" +#endif +#ifndef SUNDIR +#define SUNDIR "/opt/SUNWspro/SC4.2/lib/" +#endif + +char *suffixes[] = { ".c", ".i", ".s", ".o", ".out", 0 }; +char inputs[256] = ""; +char *cpp[] = { LCCDIR "cpp", +	"-D__STDC__=1", "-Dsparc", "-D__sparc__", "-Dsun", "-D__sun__", "-Dunix", +	"$1", "$2", "$3", 0 }; +char *include[] = { "-I" LCCDIR "include", "-I/usr/local/include", +	"-I/usr/include", 0 }; +char *com[] = { LCCDIR "rcc", "-target=sparc/solaris", +	"$1", "$2", "$3", 0 }; +char *as[] = { "/usr/ccs/bin/as", "-Qy", "-s", "-o", "$3", "$1", "$2", 0 }; +char *ld[] = { "/usr/ccs/bin/ld", "-o", "$3", "$1", +	SUNDIR "crti.o", SUNDIR "crt1.o", +	SUNDIR "values-xa.o", "$2", "", +	"-Y", "P," SUNDIR ":/usr/ccs/lib:/usr/lib", "-Qy", +	"-L" LCCDIR, "-llcc", "-lm", "-lc", SUNDIR "crtn.o", 0 }; + +extern char *concat(char *, char *); + +int option(char *arg) { +	if (strncmp(arg, "-lccdir=", 8) == 0) { +		cpp[0] = concat(&arg[8], "/cpp"); +		include[0] = concat("-I", concat(&arg[8], "/include")); +		ld[12] = concat("-L", &arg[8]); +		com[0] = concat(&arg[8], "/rcc"); +	} else if (strcmp(arg, "-p") == 0) { +		ld[5] = SUNDIR "mcrt1.o"; +		ld[10] = "P," SUNDIR "libp:/usr/ccs/lib/libp:/usr/lib/libp:" +			 SUNDIR ":/usr/ccs/lib:/usr/lib"; +	} else if (strcmp(arg, "-b") == 0) +		; +	else if (strncmp(arg, "-ld=", 4) == 0) +		ld[0] = &arg[4]; +	else +		return 0; +	return 1; +}</pre> +</blockquote> + +<p><code>LCCDIR</code> defaults to <code>"/usr/local/lib/lcc/"</code> unless +it's defined by a <code>-D</code> option as part of <code>CFLAGS</code> in the make +command, e.g.,</p> + +<blockquote> +  <pre>% make HOSTFILE=etc/solaris.c CFLAGS='-DLCCDIR=\"/v/lib/lcc/\"' lcc</pre> +</blockquote> + +<p>Note the trailing slash; <code>SUNDIR</code> is provided so you can use <code>etc/solaris.c</code> +even if you have a different version of the Sun Pro compiler suite. If you're using the +gcc compiler tools instead of the Sun Pro tools, see <a HREF="../etc/gcc-solaris.c"><code>etc/gcc-solaris.c</code></a>.</p> + +<p>Most of the host-specific code is platform-specific data and templates for the commands +that invoke the preprocessor, compiler, assembler, and loader. The <code>suffixes</code> +array lists the file name suffixes for C source files, preprocessed source files, assembly +language source files, object files, and executable files. <code>suffixes</code> must be +terminated with a null pointer, as shown above. The initialization of <code>suffixes</code> +in <code><a HREF="../etc/solaris.c">etc/solaris.c</a></code> are the typical ones for UNIX +systems. Each element of <code>suffixes</code> is actually a list of suffixes, separated +by semicolons; <code><a HREF="../etc/win32.c">etc/win32.c</a></code> holds an example:</p> + +<blockquote> +  <pre>char *suffixes[] = { ".c;.C", ".i;.I", ".asm;.ASM;.s;.S", ".obj;.OBJ", ".exe", 0 };</pre> +</blockquote> + +<p>When a list is given, the first suffix is used whenever lcc needs to generate a file +name. For example, with <code><a HREF="../etc/win32.c">etc/win32.c</a></code>, lcc emits +the generated assembly code into <code>.asm</code> files.</p> + +<p>The <code>inputs</code> array holds a null-terminated string of directories separated +by colons or semicolons. These are used as the default value of <code>LCCINPUTS</code>, if +the environment variable <code>LCCINPUTS</code> is not set; see the <a HREF="lcc.pdf">man +page</a>.</p> + +<p>Each command template is an array of pointers to strings terminated with a null +pointer; the strings are full path names of commands, arguments, or argument placeholders, +which are described below. Commands are executed in a child process, and templates can +contain multiple commands by separating commands with newlines. The driver runs each +command in a new process.</p> + +<p>The <code>cpp</code> array gives the command for running lcc's preprocessor, <code>cpp</code>. +Literal arguments specified in templates, e.g., <code>"-Dsparc"</code> in the <code>cpp</code> +command above, are passed to the command as given.</p> + +<p>The strings <code>"$1"</code>, <code>"$2"</code>, and <code>"$3"</code> +in templates are placeholders for <em>lists</em> of arguments that are substituted in a +copy of the template before the command is executed. <code>$1</code> is replaced by the <em>options</em> +specified by the user; for the preprocessor, this list always contains at least <code>-D__LCC__</code>. +<code>$2</code> is replaced by the <em>input</em> files, and <code>$3</code> is replaced +by the <em>output</em> file.</p> + +<p>Zero-length arguments after replacement are removed from the argument list before the +command is invoked. So, for example, if the preprocessor is invoked without an output +file, <code>"$3"</code> becomes <code>""</code>, which is removed from +the final argument list.</p> + +<p>The <code>include</code> array is a list of <code>-I</code> options that specify which +directives should be searched to satisfy include directives. These directories are +searched in the order given. The first directory should be the one to which the ANSI +header files were copied as described in <a HREF="#unix">UNIX</a> or <a HREF="#win32">Windows</a> +installation instructions. The driver adds these options to <code>cpp</code>'s arguments +when it invokes the preprocessor, except when <code>-N</code> is specified.</p> + +<p><code>com</code> gives the command for invoking the compiler. This template can appear +as shown above in a custom host-specific part, but the option <code>-target=sparc/solaris</code> +should be edited to the <em>target</em><code>/</code><em>os</em> for your platform. If <code>com[1]</code> +includes the string "<code>win32</code>", the driver assumes it's running on +Windows. lcc can generate code for <em>all</em> of the <em>target</em><code>/</code><em>os</em> +combinations listed in the file <code>src/bind.c</code>. The <code>-target</code> option +specifies the default combination. The driver's <code>-Wf</code> option can be used to +specify other combinations; the <a HREF="lcc.pdf">man page</a> elaborates.</p> + +<p><code>as</code> gives the command for invoking the assembler. On Linux, you must be +running at least version 2.8.1 of the GNU assembler; earlier versions mis-assemble some +instructions emitted by lcc.</p> + +<p><code>ld</code> gives the command for invoking the loader. For the other commands, the +list <code>$2</code> contains a single file; for <code>ld</code>, <code>$2</code> contains +all ".o" files and libraries, and <code>$3</code> is <code>a.out</code>, unless +the <code>-o</code> option is specified. As suggested in the code above, <code>ld</code> +must also specify the appropriate startup code and default libraries, including the lcc +library, <code>liblcc.a</code>.</p> + +<p>The <code>option</code> function is described below; the minimal <code>option</code> +function just returns 0.</p> + +<p>You can test <code>lcc</code> with the options <code>-v -v</code> to display the +commands that would be executed, e.g.,</p> + +<blockquote> +  <pre>% $BUILDDIR/lcc -v -v foo.c baz.c mylib.a -lX11 +/usr/local/lib/lcc-4.1/lcc $ Id: solaris.c,v 1.10 1998/09/14 20:36:33 drh Exp $ +foo.c: +/usr/local/lib/lcc/cpp -D__STDC__=1 -Dsparc -D__sparc__ -Dsun -D__sun__ -Dunix -D__LCC__ -I/usr/local/lib/lcc/include -I/usr/local/include -I/usr/include foo.c /tmp/lcc266290.i +/usr/local/lib/lcc/rcc -target=sparc/solaris -v /tmp/lcc266290.i /tmp/lcc266291. +s +/usr/ccs/bin/as -Qy -s -o /tmp/lcc266292.o /tmp/lcc266291.s +baz.c: +/usr/local/lib/lcc/cpp -D__STDC__=1 -Dsparc -D__sparc__ -Dsun -D__sun__ -Dunix -D__LCC__ -I/usr/local/lib/lcc/include -I/usr/local/include -I/usr/include baz.c /tmp/lcc266290.i +/usr/local/lib/lcc/rcc -target=sparc/solaris -v /tmp/lcc266290.i /tmp/lcc266291.s +/usr/ccs/bin/as -Qy -s -o /tmp/lcc266293.o /tmp/lcc266291.s +/usr/ccs/bin/ld -o a.out /opt/SUNWspro/SC4.2/lib/crti.o /opt/SUNWspro/SC4.2/lib/crt1.o /opt/SUNWspro/SC4.2/lib/values-xa.o /tmp/lcc266292.o /tmp/lcc266293.o mylib.a -lX11 -Y P,/opt/SUNWspro/SC4.2/lib/:/usr/ccs/lib:/usr/lib -Qy -L/usr/local/lib/lcc/ -llcc -lm -lc /opt/SUNWspro/SC4.2/lib/crtn.o +rm /tmp/lcc266293.o /tmp/lcc266290.i /tmp/lcc266291.s /tmp/lcc266292.o</pre> +</blockquote> + +<p>As the output shows, <code>lcc</code> places temporary files in <code>/tmp</code>; if +any of the environment variables <code>TMP</code>, <code>TEMP</code>, and <code>TMPDIR</code> +are set, they override this default (in the order shown) as does the <code>-tempdir=</code><em>dir</em> +option. The default can be changed by defining <code>TEMPDIR</code> in <code>CFLAGS</code> +when building the driver.</p> + +<p>The <code>option</code> function is called for the options <code>-Wo</code>, <code>-g</code>, +<code>-p</code>, <code>-pg</code>, and <code>-b</code> because these compiler options +might also affect the loader's arguments. For these options, the driver calls <code>option(arg)</code> +to give the host-specific code an opportunity to edit the <code>ld</code> command, if +necessary. <code>option</code> can change <code>ld</code>, if necessary, and return 1 to +announce its acceptance of the option. If the option is unsupported, <code>option</code> +should return 0.</p> + +<p>For example, in response to <code>-g</code>, the <code>option</code> function shown +above accepts the option but does nothing else, because the <code>ld</code> and <code>as</code> +commands don't need to be modified on the SPARC. <code>-g</code> will also be added to the +compiler's options by the host-independent part of the driver. The <code>-p</code> causes <code>option</code> +to change the name of the startup code and changed the list of libraries. The <code>-b</code> +option turns on <code>lcc</code>'s per-expression profiling, the code for which is in <code>liblcc.a</code>, +so <code>option</code> need no nothing.</p> + +<p>On SPARCs, the driver also recognizes <code>-Bstatic</code> and <code>-Bdynamic</code> +as linker options. The driver recognizes but ignores "<code>-target</code> <em>name</em>" +option.</p> + +<p>The option <code>-Wo</code><em>arg</em> causes the driver to pass <em>arg</em> to <code>option</code>. +Such options have no other effect; this mechanism is provided to support system-specific +options that affect the commands executed by the driver. As illustrated above, +host-specific parts should support the <code>-Wo-lccdir=</code><em>dir</em> option, which +causes lcc's compilation components to be found in <em>dir</em>, because this option is +used by the test scripts, and because the driver simulates a <code>-Wo-lccdir</code> +option with the value of the environment variable <code>LCCDIR</code>, if it's defined. +The code above rebuilds the paths to the include files, preprocessor, compiler, and +library by calling <code>concat</code>, which is defined in <code>etc/lcc.c</code>.</p> + +<h2><a NAME="rcc">Building the Compiler and Accessories</a></h2> + +<p>To build the rest of compilation components make sure <code>BUILDDIR</code> is set +appropriately and type "<code>make all</code>". This command builds <code>librcc.a</code> +(the compiler's private library), <code>rcc</code> (the compiler proper), <code>lburg</code> +(the code-generator generator), <code>cpp</code> (the preprocessor), <code>liblcc.a</code> +(the runtime library), and <code>bprint</code> (the profile printer), all in <code>BUILDDIR</code>. +There may be warnings, but there should be no errors. If you're using an ANSI/ISO compiler +other than <code>cc</code>, specify its name with the <code>CC=</code> option, e.g., +"<code>make CC=gcc all</code>". If you're running on a DEC ALPHA, use "<code>make +CC='cc -std1' all</code>"; the <code>-std1</code> option is essential on the ALPHA. +If you're on a DEC 5000 running Ultrix 4.3, use "<code>make CC=c89 all</code>".</p> + +<p>Once <code>rcc</code> is built with the host C compiler, run the test suite to verify +that <code>rcc</code> is working correctly. If any of the steps below fail, contact us +(see <a HREF="#bugs"><em>Reporting Bugs</em></a>). The commands in the makefile run the +shell script <code>src/run.sh</code> on each C program in the test suite, <code>tst/*.c</code>. +It uses the driver, <code>$BUILDDIR/lcc</code>, so you must have the driver in the build +directory before testing <code>rcc</code>. The <em>target</em><code>/</code><em>os</em> +combination is read from the variable <code>TARGET</code>, which must be specified when +invoking <code>make</code>:</p> + +<blockquote> +  <pre>% make TARGET=sparc/solaris test +mkdir -p /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst +/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/8q.s: +/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/array.s: +/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/cf.s: +/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/cq.s: +/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/cvt.s: +/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/fields.s: +/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/front.s: +/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/incr.s: +/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/init.s: +/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/limits.s: +/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/paranoia.s: +/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/sort.s: +/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/spill.s: +/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/stdarg.s: +/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/struct.s: +/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/switch.s: +/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/wf1.s: +/usr/local/lib/lcc-4.1/sparc-solaris/rcc -target=sparc/solaris /usr/local/lib/lcc-4.1/sparc-solaris/sparc/solaris/tst/yacc.s:</pre> +</blockquote> + +<p>Each line in the output above is of the form</p> + +<blockquote> +  <p><code>$BUILDDIR/rcc -target=</code><em>target</em><code>/</code><em>os</em><code>$BUILDDIR/</code><em>target</em><code>/</code><em>os</em><code>/</code><em>X</em><code>.s:</code></p> +</blockquote> + +<p>where <em>X</em> is the base name of the C program <em>X</em><code>.c</code> in the +test suite. This output identifies the compiler and the target, e.g., "<code>$BUILDDIR/rcc</code> +is generating code for a <code>sparc</code> running the <code>solaris</code> operating +system."</p> + +<p>For each program in the test suite, <code>src/run.sh</code> compiles the program, drops +the generated assembly language code in <code>BUILDDIR</code>/<em>target</em><code>/</code><em>os</em>, +and uses <code>diff</code> to compare the generated assembly code with the expected code +(the code expected for <code>tst/8q.c</code> on the SPARC under Solaris is in <code>sparc/solaris/tst/8q.sbk</code>, +etc.). If there are differences, the script executes the generated code with the input +given in <code>tst</code> (the input for <code>tst/8q.c</code> is in <code>tst/8q.0</code>, +etc.) and compares the output with the expected output (the expected output from <code>tst/8q.c</code> +on the SPARC under Solaris is in <code>sparc/solaris/tst/8q.1bk</code>, etc.). The script +also compares the diagnostics from the compiler with the expected diagnostics.</p> + +<p>On some systems, there may be a few differences between the generated code and the +expected code. These differences occur because the expected code is generated by cross +compilation and the least significant bits of some floating-point constants differ from +those bits in constants generated on your system. On Linux, there may be differences +because of differences in the header files between our system and yours. There should be +no differences in the output from executing the test programs.</p> + +<p>Next, run the "triple test", which builds <code>rcc</code> using itself:</p> + +<blockquote> +  <pre>% make triple +/usr/local/lib/lcc-4.1/sparc-solaris/lcc -o /usr/local/lib/lcc-4.1/sparc-solaris/1rcc -d0.6 -Wo-lccdir=/usr/local/lib/lcc-4.1/sparc-solaris -B/usr/local/lib/lcc-4.1/sparc-solaris/  -Isrc src/*.c +src/alloc.c: +... +src/x86.c: +/usr/local/lib/lcc-4.1/sparc-solaris/lcc -o /usr/local/lib/lcc-4.1/sparc-solaris/1rcc -d0.6 -Wo-lccdir=/usr/local/lib/lcc-4.1/sparc-solaris -B/usr/local/lib/lcc-4.1/sparc-solaris/  -Isrc src/*.c +src/alloc.c: +... +src/x86.c: +strip /usr/local/lib/lcc-4.1/sparc-solaris/[12]rcc +dd if=/usr/local/lib/lcc-4.1/sparc-solaris/1rcc of=/usr/local/lib/lcc-4.1/sparc-solaris/rcc1 bs=512 skip=1 +769+1 records in +769+1 records out +dd if=/usr/local/lib/lcc-4.1/sparc-solaris/2rcc of=/usr/local/lib/lcc-4.1/sparc-solaris/rcc2 bs=512 skip=1 +769+1 records in +769+1 records out +if cmp /usr/local/lib/lcc-4.1/sparc-solaris/rcc[12]; then \ +        mv /usr/local/lib/lcc-4.1/sparc-solaris/2rcc /usr/local/lib/lcc-4.1/sparc-solaris/rcc; \ +        rm -f /usr/local/lib/lcc-4.1/sparc-solaris/1rcc /usr/local/lib/lcc-4.1/sparc-solaris/rcc[12]; fi</pre> +</blockquote> + +<p>This command builds <code>rcc</code> twice; once using the <code>rcc</code> built by <code>cc</code> +and again using the <code>rcc</code> built by <code>lcc</code>. The resulting binaries are +compared. They should be identical, as shown at the end of the output above. If they +aren't, our compiler is generating incorrect code; <a HREF="#bugs">contact</a> us.</p> + +<p>The final version of <code>rcc</code> should also pass the test suite; that is, the +output from</p> + +<blockquote> +  <pre>% make TARGET=sparc/solaris test</pre> +</blockquote> + +<p>should be identical to that from the previous <code>make test</code>.</p> + +<p>The command "<code>make clean</code>" cleans up, but does not remove <code>rcc</code>, +etc., and "<code>make clobber</code>" cleans up and removes <code>lcc</code>, <code>rcc</code>, +and the other accessories. Test directories under <code>BUILDDIR</code> are <em>not</em> +removed; you'll need to remove these by hand, e.g.,</p> + +<blockquote> +  <pre>% rm -fr $BUILDDIR/sparc</pre> +</blockquote> + +<p>The code generators for the other targets can be tested by specifying the desired <em>target</em><code>/</code><em>os</em> +and setting an environment variable that controls what <code>src/run.sh</code> does. For +example, to test the MIPS code generator, type</p> + +<blockquote> +  <pre>% setenv REMOTEHOST noexecute +% make TARGET=mips/irix test</pre> +</blockquote> + +<p>As above, <code>src/run.sh</code> compares the MIPS code generated with what's +expected. There should be no differences. Setting <code>REMOTEHOST</code> to <code>noexecute</code> +suppresses the assembly and execution of the generated code. If you set <code>REMOTEHOST</code> +to the name of a MIPS machine to which you can <code>rlogin</code>, <code>src/run.sh</code> +will <code>rcp</code> the generated code to that machine and execute it there, if +necessary. See <code>src/run.sh</code> for the details.</p> + +<p>You can use lcc as a cross compiler. The options <code>-S</code> and <code>-Wf-target=</code><em>target/os</em> +generate assembly code for the specified target, which is any of those listed in the file <code>src/bind.c</code>. +For example, </p> + +<blockquote> +  <pre>% lcc -Wf-target=mips/irix -S tst/8q.c</pre> +</blockquote> + +<p>generates MIPS code for <code>tst/8q.c</code> in <code>8q.s</code>.</p> + +<p>lcc can also generate code for a "symbolic" target. This target is used +routinely in front-end development, and its output is a printable representation of the +input program, e.g., the dags constructed by the front end are printed, and other +interface functions print their arguments. You can specify this target with the option <code>-Wf-target=symbolic</code>. +For example,</p> + +<blockquote> +  <pre>% lcc -Wf-target=symbolic -S tst/8q.c</pre> +</blockquote> + +<p>generates symbolic output for <code>tst/8q.c</code> in <code>8q.s</code>. Adding <code>-Wf-html</code> +causes the symbolic target to emit HTML instead of plain text. Finally, the option <code>-Wf-target=null</code> +specifies the "null" target for which lcc emits nothing and thus only checks the +syntax and semantics of its input files.</p> + +<h2><a NAME="win32">Installation on Windows NT 4.0 or Windows 95/98</a></h2> + +<p>On Windows NT 4.0 and Windows 95/98, lcc is designed to work with Microsoft's Visual +C++ 5.0 (VC) and Microsoft's Assembler, MASM 6.11d. It uses the VC header files, +libraries, and command-line tools, and it uses MASM to assemble the code it generates. If +you have MASM 6.11, make sure you <a +HREF="http://support.microsoft.com/support/kb/articles/Q138/9/83.asp">upgrade to 6.11d</a>, +because earlier 6.11 releases do not generate correct COFF object files.</p> + +<p>Building the distribution components from the ground up requires Microsoft's Visual +C/C++ 5.0 compiler, Microsoft's make, <code>nmake</code>, and the standard Windows command +interpreter. <a HREF="../makefile.nt"><code>makefile.nt</code></a> is written to use only <code>nmake</code>. +As on UNIX systems, the compilation components are installed in a single <em>build +directory</em>, and the top-level programs, <code>lcc.exe</code> and <code>bprint.exe</code>, +are installed in a directory on the PATH. If the conventions used below are followed, the +Windows-specific parts of the driver program, <code>lcc.exe</code>, can be used +unmodified.</p> + +<p>Building from the source distribution on a Windows system involves the following steps. +Below, the build directory is referred to as <code>BUILDDIR</code>, and the distribution +is in <code>\dist\lcc\4.1</code>.  + +<ol> +  <li>Create the build directory, perhaps using a version- and platform-specific naming +    convention as suggested in <a HREF="#unix"><em>Installation on UNIX</em></a>, and record +    the name of this directory in the <code>BUILDDIR</code> environment variable:<blockquote> +      <pre>C:\dist\lcc\4.1>set BUILDDIR=\progra~1\lcc\4.1\bin +C:\dist\lcc\4.1>mkdir %BUILDDIR%</pre> +    </blockquote> +    <p>The default build, or installation, directory is <code>\Program Files\lcc\4.1\bin</code>, +    but the <code>nmake</code> commands require that you use the corresponding 8.3 file name, <code>progra~1</code>, +    instead of <code>Program Files</code>.</p> +  </li> +  <li><a HREF="../etc/win32.c"><code>etc\win32.c</code></a> is the Windows-specific part of +    the driver. It assumes that environment variable <code>include</code> gives the locations +    of the VC header files and that the linker (<code>link.exe</code>) and the assembler (<code>ml.exe</code>) +    are on the PATH. It also assumes that the macro <code>LCCDIR</code> gives the build +    directory. If necessary, revise a copy of <a HREF="../etc/win32.c"><code>etc\win32.c</code></a> +    to reflect the conventions on your computer (see <a HREF="#driver"><em>Building the Driver</em></a>), +    then build the driver, specifying the default temporary directory, if necessary:<blockquote> +      <pre>C:\dist\lcc\4.1>nmake -f makefile.nt TEMPDIR=\\temp HOSTFILE=etc/win32.c lcc +... +        cl -nologo -Zi -MLd -Fd\progra~1\lcc\4.1\bin\ -c -DTEMPDIR=\"\\temp\" -Fo\progra~1\lcc\4.1\bin\lcc.obj etc/lcc.c +lcc.c +        cl -nologo -Zi -MLd -Fd\progra~1\lcc\4.1\bin\ -c -Fo\progra~1\lcc\4.1\bin\host.obj etc/win32.c +win32.c +        cl -nologo -Zi -MLd -Fd\progra~1\lcc\4.1\bin\ -Fe\progra~1\lcc\4.1\bin\lcc.exe \progra~1\lcc\4.1\bin\lcc.obj \progra~1\lcc\4.1\bin\host.obj</pre> +    </blockquote> +    <p>If you make a copy of <code>etc\win32.c</code>, specify the path of the copy as the +    value of <code>HOSTFILE</code>. For example, if you copy <code>etc\win32.c</code> to <code>BUILDDIR</code> +    and edit it, use the command</p> +    <blockquote> +      <pre>C:\dist\lcc\4.1>nmake -f makefile.nt TEMPDIR=\\temp HOSTFILE=%BUILDDIR%\win32.c lcc</pre> +    </blockquote> +  </li> +  <li>Build the preprocessor, compiler proper, library, and other accessories (see <a +    HREF="#rcc"><em>Building the Compiler</em></a>):<blockquote> +      <pre>C:\dist\lcc\4.1>nmake -f makefile.nt all</pre> +    </blockquote> +    <p>This command uses the VC command-line tools <code>cl</code> and <code>lib</code> to +    build <code>bprint.exe</code>, <code>cpp.exe</code>, <code>lburg.exe</code>, <code>liblcc.lib</code>, +    <code>librcc.lib</code>, and <code>rcc.exe</code>, all in <code>BUILDDIR</code>. There may +    be some warnings, but there should be no warnings.</p> +  </li> +  <li>Create a test directory and run the test suite:<blockquote> +      <pre>C:\dist\lcc\4.1>mkdir %BUILDDIR%\x86\win32\tst +C:\dist\lcc\4.1>nmake -f makefile.nt test</pre> +    </blockquote> +    <p>This command compiles each program in <a HREF="../tst">tst</a>, compares the generated +    assembly code and diagnostics with the expected assembly code and diagnostics, executes +    the program, and compares the output with the expected output (using <code>fc</code>). For +    example, when the nmake command compiles <a HREF="../tst/8q.c"><code>tst\8q.c</code></a>, +    it leaves the generated assembly code and diagnostic output in <code>%BUILDDIR%\x86\win32\tst\8q.s</code> +    and <code>%BUILDDIR%\x86\win32\tst\8q.2</code>, and it compares them with the expected +    results in <code>x86\win32\tst\8q.sbk</code>. It builds the executable program in <code>%BUILDDIR%\x86\win32\tst\8q.exe</code>, +    runs it, and redirects the output to <code>%BUILDDIR%\x86\win32\tst\8q.1</code>, which it +    compares with <code>x86\win32\tst\8q.1bk</code>. The output from this step is voluminous, +    but there should be no differences and no errors.</p> +  </li> +  <li>Run the "triple" test, which compiles <code>rcc</code> with itself and +    verifies the results:<blockquote> +      <pre>C:\dist\lcc\4.1>nmake -f makefile.nt triple +... +\progra~1\lcc\4.1\bin\x86.c: + Assembling: C:/TEMP/lcc2001.asm +        fc /b \progra~1\lcc\4.1\bin\1rcc.exe \progra~1\lcc\4.1\bin\2rcc.exe +Comparing files \progra~1\lcc\4.1\bin\1rcc.exe and \progra~1\lcc\4.1\bin\2RCC.EXE +00000088: B4 D5</pre> +    </blockquote> +    <p>This command builds <code>rcc</code> twice; once using the <code>rcc</code> built by VC +    and again using the <code>rcc</code> built by <code>lcc</code>. The resulting binaries are +    compared using <code>fc</code>. They should be identical, except for one or two bytes of +    timestamp data, as shown at the end of the output above. If they aren't, our compiler is +    generating incorrect code; <a HREF="#bugs">contact</a> us.</p> +  </li> +  <li>Copy <code>lcc.exe</code> and <code>bprint.exe</code> to a directory on your PATH, e.g.,<blockquote> +      <pre>C:\dist\lcc\4.1>copy %BUILDDIR%\lcc.exe \bin +        1 file(s) copied. + +C:\dist\lcc\4.1>copy %BUILDDIR%\bprint.exe \bin +        1 file(s) copied.</pre> +    </blockquote> +  </li> +  <li>Finally, clean up:<blockquote> +      <pre>C:\dist\lcc\4.1>nmake -f makefile.nt clean</pre> +    </blockquote> +    <p>This command removes the derived files in <code>BUILDDIR</code>, but does not remove <code>rcc.exe</code>, +    etc.; "<code>nmake -f makefile.nt clobber</code>" cleans up and removes all +    executables and libraries. Test directories under <code>BUILDDIR</code> are <em>not</em> +    removed; you'll need to remove these by hand, e.g.,</p> +    <blockquote> +      <pre>C:\dist\lcc\4.1>rmdir %BUILDDIR%\x86 /s +\progra~1\lcc\4.1\bin\x86, Are you sure (Y/N)? y</pre> +    </blockquote> +  </li> +</ol> + +<h2><a NAME="bugs">Reporting Bugs</a></h2> + +<p>lcc is a large, complex program. We find and repair errors routinely. If you think that +you've found a error, follow the steps below, which are adapted from the instructions in +Chapter 1 of <cite>A Retargetable C Compiler: Design and Implementation</cite>.  + +<ol> +  <li>If you don't have a source file that displays the error, create one. Most errors are +    exposed when programmers try to compile a program they think is valid, so you probably +    have a demonstration program already.</li> +  <li>Preprocess the source file and capture the preprocessor output. Discard the original +    code.</li> +  <li>Prune your source code until it can be pruned no more without sending the error into +    hiding. We prune most error demonstrations to fewer than five lines.</li> +  <li>Confirm that the source file displays the error with the <em>distributed</em> version of +    lcc. If you've changed lcc and the error appears only in your version, then you'll have to +    chase the error yourself, even if it turns out to be our fault, because we can't work on +    your code.</li> +  <li>Annotate your code with comments that explain why you think that lcc is wrong. If lcc +    dies with an assertion failure, please tell us where it died. If lcc crashes, please +    report the last part of the call chain if you can. If lcc is rejecting a program you think +    is valid, please tell us why you think it's valid, and include supporting page numbers in +    the ANSI Standard, Appendix A in <cite>The C Programming Language</cite>, or the +    appropriate section in <cite>C: A Reference Manual</cite>, 4th edition by S. B. Harbison +    and G. L. Steele, Jr. (Prentice Hall, 1995). If lcc silently generates incorrect code for +    some construct, please include the corrupt assembly code in the comments and flag the +    incorrect instructions if you can.</li> +  <li>Confirm that your error hasn't been fixed already. The latest version of lcc is always +    available for anonymous <code>ftp</code> from <code>ftp.cs.princeton.edu</code> in <a +    HREF="ftp://ftp.cs.princeton.edu/pub/lcc"><code>pub/lcc</code></a>. A <a +    HREF="ftp://ftp.cs.princeton.edu/pub/lcc/README"><code>README</code></a> file there gives +    acquistion details, and the <a HREF="../LOG"><code>LOG</code></a> file reports what errors +    were fixed and when they were fixed. If you report a error that's been fixed, you might +    get a canned reply.</li> +  <li>Send your program by electronic mail to <code>lcc-bugs@cs.princeton.edu</code>. Please +    send only valid C programs; put all remarks in C comments so that we can process reports +    semiautomatically.</li> +</ol> + +<h2><a NAME="mailinglist">Keeping in Touch</a></h2> + +<p>There is an lcc mailing list for general information about lcc. To be added to the +list, send a message with the 1-line body</p> + +<blockquote> +  <pre>subscribe lcc</pre> +</blockquote> + +<p>to <code>majordomo@cs.princeton.edu</code>. This line must appear in the message body; +"Subject:" lines are ignored. To learn more about mailing lists served by <code>majordomo</code>, +send a message with the 1-word body "<code>help</code>" to <code>majordomo@cs.princeton.edu</code>. +Mail sent to <code>lcc@cs.princeton.edu</code> is forwarded to everyone on the mailing +list.</p> + +<p>There is also an <code>lcc-bugs</code> mailing list for reporting bugs; subscribe to it +by sending a message with the 1-line body </p> + +<blockquote> +  <pre>subscribe lcc-bugs</pre> +</blockquote> + +<p>to <code>majordomo@cs.princeton.edu</code>. Mail addressed to <var>lcc-bugs@cs.princeton.edu</var> +is forwarded to everyone on this list.</p> + +<hr> + +<address> +  <a HREF="http://www.research.microsoft.com/~cwfraser/">Chris Fraser</a> / <a +  HREF="mailto:cwfraser@microsoft.com">cwfraser@microsoft.com</a><br> +  <a HREF="http://www.research.microsoft.com/~drh/">David Hanson</a> / <a +  HREF="mailto:drh@microsoft.com">drh@microsoft.com</a><br> +  $Revision: 145 $ $Date: 2001-10-17 16:53:10 -0500 (Wed, 17 Oct 2001) $  +</address> +</body> +</html> diff --git a/src/tools/lcc/doc/lcc.1 b/src/tools/lcc/doc/lcc.1 new file mode 100644 index 0000000..fe91bca --- /dev/null +++ b/src/tools/lcc/doc/lcc.1 @@ -0,0 +1,605 @@ +.\" $Id: lcc.1 145 2001-10-17 21:53:10Z timo $ +.TH LCC 1 "local \- $Date: 2001-10-17 16:53:10 -0500 (Wed, 17 Oct 2001) $" +.SH NAME +lcc \- ANSI C compiler +.SH SYNOPSIS +.B lcc +[ +.I option +| +.I file +]... +.br +.SH DESCRIPTION +.PP +.I lcc +is an ANSI C compiler for a variety of platforms. +.PP +Arguments whose names end with `.c' (plus `.C' under Windows) are taken to be +C source programs; they are preprocessed, compiled, and +each object program is left on the file +whose name is that of the source with `.o' (UNIX) or `.obj' (Windows) +substituted for the extension. +Arguments whose names end with `.i' are treated similarly, +except they are not preprocessed. +In the same way, +arguments ending with `.s' (plus `.S', `.asm', and `.ASM', under Windows) +are taken to be assembly source programs +and are assembled, producing an object file. +If there are no arguments, +.I lcc +summarizes its options on the standard error. +.PP +.I lcc +deletes an object file if and only if exactly one +source file is mentioned and no other file +(source, object, library) or +.B \-l +option is mentioned. +.PP +If the environment variable +.B LCCINPUTS +is set, +.I lcc +assumes it gives a semicolon- or colon-separated list of directories in which to +look for source and object files whose names do not begin with `/'. +These directories are also added to the list of directories +searched for libraries. +If +.B LCCINPUTS +is defined, it must contain `.' in order for the current directory +to be searched for input files. +.PP +.I lcc +uses ANSI standard header files (see `FILES' below). +Include files not found in the ANSI header files +are taken from the normal default include areas, +which usually includes +.BR /usr/include . +Under Windows, if the environment variable +.B include +is defined, it gives a semicolon-separated list of directories in which to search for +header files. +.PP +.I lcc +interprets the following options; unrecognized options are +taken as loader options (see +.IR ld (1)) +unless +.BR \-c , +.BR \-S , +or +.B \-E +precedes them. +Except for +.BR \-l , +all options are processed before any of the files +and apply to all of the files. +Applicable options are passed to each compilation phase in the order given. +.TP +.B \-c +Suppress the loading phase of the compilation, and force +an object file to be produced even if only one program is compiled. +.TP +.B \-g +Produce additional symbol table information for the local debuggers. +.I lcc +warns when +.B \-g +is unsupported. +.TP +.BI \-Wf\-g n , x +Set the debugging level to +.I n +and emit source code as comments into the generated assembly code; +.I x +must be the assembly language comment character. +If +.I n +is omitted, it defaults to 1, which is similar to +.BR \-g . +Omitting +.BI , x +just sets the debugging level to +.IR n . +.TP +.B \-w +Suppress warning diagnostics, such as those +announcing unreferenced statics, locals, and parameters. +The line +.I +#pragma ref id +simulates a reference to the variable  +.IR id . +.TP +.BI \-d n +Generate jump tables for switches whose density is at least +.IR n , +a floating point constant between zero and one. +The default is 0.5. +.TP +.B \-A +Warns about +declarations and casts of function types without prototypes, +assignments between pointers to ints and pointers to enums, and +conversions from pointers to smaller integral types. +A second +.B \-A +warns about +unrecognized control lines, +nonANSI language extensions and source characters in literals, +unreferenced variables and static functions, +declaring arrays of incomplete types, +and exceeding +.I some +ANSI environmental limits, like more than 257 cases in switches. +It also arranges for duplicate global definitions in separately compiled +files to cause loader errors. +.TP +.B \-P +Writes declarations for all defined globals on standard error. +Function declarations include prototypes; +editing this output can simplify conversion to ANSI C. +This output may not correspond to the input when +there are several typedefs for the same type. +.TP +.B \-n +Arrange for the compiler to produce code +that tests for dereferencing zero pointers. +The code reports the offending file and line number and calls +.IR abort (3). +.TP +.B \-O +is ignored. +.TP +.B \-S +Compile the named C programs, and leave the +assembler-language output on corresponding files suffixed `.s' or `.asm'. +.TP +.B \-E +Run only the preprocessor on the named C programs +and unsuffixed file arguments, +and send the result to the standard output. +.TP +.BI \-o "  output" +Name the output file +.IR output . +If +.B \-c +or +.B \-S +is specified and there is exactly one source file, +this option names the object or assembly file, respectively. +Otherwise, this option names the final executable +file generated by the loader, and `a.out' (UNIX) or `a.exe' (Windows) is left undisturbed. +.I lcc +warns if +.B \-o +and +.B \-c +or +.B \-S +are given with more than one source file and ignores the +.B \-o +option. +.TP +.BI \-D name=def +Define the +.I name +to the preprocessor, as if by `#define'. +If +.I =def +is omitted, the name is defined as "1". +.TP +.BI \-U name +Remove any initial definition of +.IR name . +.TP +.BI \-I dir +`#include' files +whose names do not begin with `/' are always +sought first in the directory of the +.I file +arguments, then in directories named in +.B \-I +options, then in directories on a standard list. +.TP +.B \-N +Do not search +.I any +of the standard directories for `#include' files. +Only those directories specified by subsequent explicit +.B \-I +options will be searched, in the order given. +.TP +.BI \-B str +Use the compiler +.BI "" str rcc +instead of the default version. +Note that +.I str +often requires a trailing slash. +On Sparcs only, +.B \-Bstatic +and +.BI \-Bdynamic +are passed to the loader; see +.IR ld (1). +.TP +.BI \-Wo\-lccdir= dir +Find the preprocessor, compiler proper, and include directory +in the directory +.I dir/ +or +.I +dir\\. +If the environment variable +.B LCCDIR +is defined, it gives this directory. +.I lcc +warns when this option is unsupported. +.TP +.B \-Wf-unsigned_char=1 +.br +.ns +.TP +.B \-Wf-unsigned_char=0  +makes plain +.B char +an unsigned (1) or signed (0) type; by default, +.B char +is signed. +.TP +.B \-Wf\-wchar_t=unsigned_char +.br +.ns +.TP +.B \-Wf\-wchar_t=unsigned_short +.br +.ns +.TP +.B \-Wf\-wchar_t=unsigned_int +Makes wide characters the type indicated; by default, +wide characters are unsigned short ints, and +.B wchar_t +is a typedef for unsigned short defined in stddef.h. +The definition for +.B wchar_t +in stddef.h must correspond to the type specified. +.TP +.B \-v +Print commands as they are executed; some of the executed +programs are directed to print their version numbers. +More than one occurrence of +.B \-v +causes the commands to be printed, but +.I not +executed. +.TP +.BR \-help " or " \-? +Print a message on the standard error summarizing +.IR lcc 's +options and giving the values of the environment variables +.B LCCINPUTS +and +.BR LCCDIR , +if they are defined. +Under Windows, the values of +.B include +and +.B lib +are also given, if they are defined. +.TP +.B \-b +Produce code that counts the number of times each expression is executed. +If loading takes place, arrange for a +.B prof.out +file to be written when the object program terminates. +A listing annotated with execution counts can then be generated with +.IR bprint (1). +.I lcc +warns when +.B \-b +is unsupported. +.B \-Wf\-C +is similar, but counts only the number of function calls. +.TP +.B \-p +Produce code that counts the number of times each function is called. +If loading takes place, replace the standard startup +function by one that automatically calls +.IR monitor (3) +at the start and arranges to write a +.B mon.out +file when the object program terminates normally. +An execution profile can then be generated with +.IR prof (1). +.I lcc +warns when +.B \-p +is unsupported. +.TP +.B \-pg +Causes the compiler to produce counting code like +.BR \-p , +but invokes a run-time recording mechanism that keeps more +extensive statistics and produces a  +.B gmon.out +file at normal termination. +Also, a profiling library is searched, in lieu of the standard C library. +An execution profile can then be generated with +.IR gprof (1). +.I lcc +warns when +.B \-pg +is unsupported. +.TP +.BI \-t name +.br +.ns +.TP +.BI \-t +Produce code to print the name of the function, an activation number, +and the name and value of each argument at function entry. +At function exit, produce code to print +the name of the function, the activation number, and the return value. +By default, +.I printf +does the printing; if +.I name +appears, it does. +For null +.I char* +values, "(null)" is printed.  +.BI \-target +.I name +is accepted, but ignored. +.TP +.BI \-tempdir= dir +Store temporary files in the directory +.I dir/ +or +.I +dir\\. +The default is usually +.BR /tmp . +.TP +.BI \-W xarg +pass argument +.I arg +to the program indicated by +.IR x ; +.I x +can be one of +.BR p , +.BR f , +.BR a , +or +.BR l , +which refer, respectively, to the preprocessor, the compiler proper, +the assembler, and the loader. +.I arg +is passed as given; if a +.B \- +is expected, it must be given explicitly. +.BI \-Wo arg +specifies a system-specific option, +.IR arg . +.PP +Other arguments +are taken to be either loader option arguments, or C-compatible +object programs, typically produced by an earlier +.I lcc +run, or perhaps libraries of C-compatible routines. +Duplicate object files are ignored. +These programs, together with the results of any +compilations specified, are loaded (in the order +given) to produce an executable program with name +.BR a.out +(UNIX) or +.BR a.exe +(Windows). +.PP +.I lcc +assigns the most frequently referenced scalar parameters and +locals to registers whenever possible. +For each block, +explicit register declarations are obeyed first; +remaining registers are assigned to automatic locals if they +are `referenced' at least 3 times. +Each top-level occurrence of an identifier +counts as 1 reference. Occurrences in a loop, +either of the then/else arms of an if statement, or a case +in a switch statement each count, respectively, as 10, 1/2, or 1/10 references. +These values are adjusted accordingly for nested control structures. +.B \-Wf\-a +causes +.I lcc +to read a +.B prof.out +file from a previous execution and to use the data therein +to compute reference counts (see +.BR \-b ). +.PP +.I lcc +is a cross compiler; +.BI \-Wf\-target= target/os +causes +.I lcc +to generate code for +.I target +running the operating system denoted by +.IR os . +The supported +.I target/os +combinations may include +.PP +.RS +.ta \w'sparc/solarisxx'u +.nf +alpha/osf	ALPHA, OSF 3.2 +mips/irix	big-endian MIPS, IRIX 5.2 +mips/ultrix	little-endian MIPS, ULTRIX 4.3 +sparc/solaris	SPARC, Solaris 2.3 +x86/win32	x86, Windows NT 4.0/Windows 95/98 +x86/linux	x86, Linux +symbolic	text rendition of the generated code +null		no output +.fi +.RE +.PP +For +.BR \-Wf\-target=symbolic , +the option +.B \-Wf-html +causes the text rendition to be emitted as HTML. +.B  +.SH LIMITATIONS +.PP +.I lcc +accepts the C programming language +as described in the ANSI standard. +If +.I lcc +is used with the GNU C preprocessor, the +.B \-Wp\-trigraphs +option is required to enable trigraph sequences. +.PP +Plain int bit fields are signed. +Bit fields are aligned like unsigned integers but are otherwise laid out +as by most standard C compilers. +Some compilers, such as the GNU C compiler, +may choose other, incompatible layouts. +.PP +Likewise, calling conventions are intended to be compatible with +the host C compiler, +except possibly for passing and returning structures. +Specifically, +.I lcc +passes and returns structures like host ANSI C compilers +on most targets, but some older host C compilers use different conventions. +Consequently, calls to/from such functions compiled with +older C compilers may not work. +Calling a function that returns +a structure without declaring it as such violates +the ANSI standard and may cause a fault. +.SH FILES +.PP +The file names listed below are +.IR typical , +but vary among installations; installation-dependent variants +can be displayed by running +.I lcc +with the +.B \-v +option. +.PP +.RS +.ta \w'$LCCDIR/liblcc.{a,lib}XX'u +.nf +file.{c,C}	input file +file.{s,asm}	assembly-language file +file.{o,obj}	object file +a.{out,exe}	loaded output +/tmp/lcc*	temporary files +$LCCDIR/cpp	preprocessor +$LCCDIR/rcc	compiler +$LCCDIR/liblcc.{a,lib}	\fIlcc\fP-specific library +/lib/crt0.o	runtime startup (UNIX) +/lib/[gm]crt0.o	startups for profiling (UNIX) +/lib/libc.a	standard library (UNIX) +$LCCDIR/include	ANSI standard headers +/usr/local/include	local headers +/usr/include	traditional headers +prof.out	file produced for \fIbprint\fR(1) +mon.out	file produced for \fIprof\fR(1) +gmon.out	file produced for \fIgprof\fR(1) +.fi +.RE +.PP +.I lcc +predefines the macro +.B __LCC__ +on all systems. +It may also predefine some installation-dependent symbols; option +.B \-v +exposes them. +.SH "SEE ALSO" +.PP +C. W. Fraser and D. R. Hanson, +.I A Retargetable C Compiler: Design and Implementation, +Addison-Wesley, 1995. ISBN 0-8053-1670-1. +.PP +The World-Wide Web page at http://www.cs.princeton.edu/software/lcc/. +.PP +S. P. Harbison and G. L. Steele, Jr., +.I C: A Reference Manual, +4th ed., Prentice-Hall, 1995. +.PP +B. W. Kernighan and D. M. Ritchie, +.I The C Programming Language, +2nd ed., Prentice-Hall, 1988. +.PP +American National Standards Inst., +.I American National Standard for Information Systems\(emProgramming +.IR Language\(emC , +ANSI X3.159-1989, New York, 1990. +.br +.SH BUGS +Mail bug reports along with the shortest preprocessed program +that exposes them and the details reported by +.IR lcc 's +.B \-v +option to lcc-bugs@princeton.edu. The WWW page at +URL http://www.cs.princeton.edu/software/lcc/ +includes detailed instructions for reporting bugs. +.PP +The ANSI standard headers conform to the specifications in +the Standard, which may be too restrictive for some applications, +but necessary for portability. +Functions given in the ANSI headers may be missing from +some local C libraries (e.g., wide-character functions) +or may not correspond exactly to the local versions; +for example, the ANSI standard +stdio.h +specifies that +.IR printf , +.IR fprintf , +and +.I sprintf +return the number of characters written to the file or array, +but some existing libraries don't implement this convention. +.PP +On the MIPS and SPARC, old-style variadic functions must use +varargs.h +from MIPS or Sun. New-style is recommended. +.PP +With +.BR \-b , +files compiled +.I without +.B \-b +may cause +.I bprint +to print erroneous call graphs. +For example, if +.B f +calls +.B g +calls +.B h +and +.B f +and +.B h +are compiled with +.BR \-b , +but +.B g +is not, +.B bprint +will report that +.B f +called +.BR h . +The total number of calls is correct, however. diff --git a/src/tools/lcc/doc/lcc.pdf b/src/tools/lcc/doc/lcc.pdf Binary files differnew file mode 100644 index 0000000..6134de6 --- /dev/null +++ b/src/tools/lcc/doc/lcc.pdf diff --git a/src/tools/lcc/etc/bytecode.c b/src/tools/lcc/etc/bytecode.c new file mode 100644 index 0000000..fe4178f --- /dev/null +++ b/src/tools/lcc/etc/bytecode.c @@ -0,0 +1,66 @@ +/* quake3 bytecode target */ + +#include <string.h> +#include <stdio.h> +#include "../../../qcommon/q_platform.h" + +#ifdef _WIN32 +#define BINEXT ".exe" +#else +#define BINEXT "" +#endif + +char *suffixes[] = { ".c", ".i", ".asm", ".o", ".out", 0 }; +char inputs[256] = ""; +char *cpp[] = { "q3cpp" BINEXT, +	"-D__STDC__=1", "-D__STRICT_ANSI__", "-D__signed__=signed", "-DQ3_VM", +	"$1", "$2", "$3", 0 }; +char *include[] = { 0 }; +char *com[] = { "q3rcc" BINEXT, "-target=bytecode", "$1", "$2", "$3", 0 }; +char *ld[] = { 0 }; +char *as[] = { 0 }; + +extern char *concat(char *, char *); + +/* +=============== +UpdatePaths + +Updates the paths to q3cpp and q3rcc based on +the directory that contains q3lcc +=============== +*/ +void UpdatePaths( const char *lccBinary ) +{ +	char basepath[ 1024 ]; +	char *p; + +	strncpy( basepath, lccBinary, 1024 ); +	p = strrchr( basepath, PATH_SEP ); + +	if( p ) +	{ +		*( p + 1 ) = '\0'; + +		cpp[ 0 ] = concat( basepath, "q3cpp" BINEXT ); +		com[ 0 ] = concat( basepath, "q3rcc" BINEXT ); +	} +} + +int option(char *arg) { +	if (strncmp(arg, "-lccdir=", 8) == 0) { +		cpp[0] = concat(&arg[8], "/q3cpp" BINEXT); +		include[0] = concat("-I", concat(&arg[8], "/include")); +		com[0] = concat(&arg[8], "/q3rcc" BINEXT); +	} else if (strcmp(arg, "-p") == 0 || strcmp(arg, "-pg") == 0) { +		fprintf( stderr, "no profiling supported, %s ignored.\n", arg); +	} else if (strcmp(arg, "-b") == 0) +		; +	else if (strcmp(arg, "-g") == 0) +		fprintf( stderr, "no debugging supported, %s ignored.\n", arg); +	else if (strncmp(arg, "-ld=", 4) == 0 || strcmp(arg, "-static") == 0) { +		fprintf( stderr, "no linking supported, %s ignored.\n", arg); +	} else +		return 0; +	return 1; +} diff --git a/src/tools/lcc/etc/lcc.c b/src/tools/lcc/etc/lcc.c new file mode 100644 index 0000000..cac01b9 --- /dev/null +++ b/src/tools/lcc/etc/lcc.c @@ -0,0 +1,811 @@ +/* + * lcc [ option ]... [ file | -llib ]... + * front end for the ANSI C compiler + */ +static char rcsid[] = "Id: dummy rcsid"; + +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <ctype.h> +#include <signal.h> +#include <unistd.h> + +#ifndef TEMPDIR +#define TEMPDIR "/tmp" +#endif + +typedef struct list *List; +struct list {		/* circular list nodes: */ +	char *str;		/* option or file name */ +	List link;		/* next list element */ +}; + +static void *alloc(int); +static List append(char *,List); +extern char *basename(char *); +static int callsys(char *[]); +extern char *concat(char *, char *); +static int compile(char *, char *); +static void compose(char *[], List, List, List); +static void error(char *, char *); +static char *exists(char *); +static char *first(char *); +static int filename(char *, char *); +static List find(char *, List); +static void help(void); +static void initinputs(void); +static void interrupt(int); +static void opt(char *); +static List path2list(const char *); +extern int main(int, char *[]); +extern char *replace(const char *, int, int); +static void rm(List); +extern char *strsave(const char *); +extern char *stringf(const char *, ...); +extern int suffix(char *, char *[], int); +extern char *tempname(char *); + +#ifndef __sun +extern int getpid(void); +#endif + +extern char *cpp[], *include[], *com[], *as[],*ld[], inputs[], *suffixes[]; +extern int option(char *); + +static int errcnt;		/* number of errors */ +static int Eflag;		/* -E specified */ +static int Sflag = 1;		/* -S specified */ //for Q3 we always generate asm +static int cflag;		/* -c specified */ +static int verbose;		/* incremented for each -v */ +static List llist[2];		/* loader files, flags */ +static List alist;		/* assembler flags */ +static List clist;		/* compiler flags */ +static List plist;		/* preprocessor flags */ +static List ilist;		/* list of additional includes from LCCINPUTS */ +static List rmlist;		/* list of files to remove */ +static char *outfile;		/* ld output file or -[cS] object file */ +static int ac;			/* argument count */ +static char **av;		/* argument vector */ +char *tempdir = TEMPDIR;	/* directory for temporary files */ +static char *progname; +static List lccinputs;		/* list of input directories */ + +extern void UpdatePaths( const char *lccBinary ); + +int main(int argc, char *argv[]) { +	int i, j, nf; + +	progname = argv[0]; + +	UpdatePaths( progname ); + +	ac = argc + 50; +	av = alloc(ac*sizeof(char *)); +	if (signal(SIGINT, SIG_IGN) != SIG_IGN) +		signal(SIGINT, interrupt); +	if (signal(SIGTERM, SIG_IGN) != SIG_IGN) +		signal(SIGTERM, interrupt); +#ifdef SIGHUP +	if (signal(SIGHUP, SIG_IGN) != SIG_IGN) +		signal(SIGHUP, interrupt); +#endif +	if (getenv("TMP")) +		tempdir = getenv("TMP"); +	else if (getenv("TEMP")) +		tempdir = getenv("TEMP"); +	else if (getenv("TMPDIR")) +		tempdir = getenv("TMPDIR"); +	assert(tempdir); +	i = strlen(tempdir); +	for (; (i > 0 && tempdir[i-1] == '/') || tempdir[i-1] == '\\'; i--) +		tempdir[i-1] = '\0'; +	if (argc <= 1) { +		help(); +		exit(0); +	} +	plist = append("-D__LCC__", 0); +	initinputs(); +	if (getenv("LCCDIR")) +		option(stringf("-lccdir=%s", getenv("LCCDIR"))); +	for (nf = 0, i = j = 1; i < argc; i++) { +		if (strcmp(argv[i], "-o") == 0) { +			if (++i < argc) { +				if (suffix(argv[i], suffixes, 2) >= 0) { +					error("-o would overwrite %s", argv[i]); +					exit(8); +				} +				outfile = argv[i]; +				continue; +			} else { +				error("unrecognized option `%s'", argv[i-1]); +				exit(8); +			} +		} else if (strcmp(argv[i], "-target") == 0) { +			if (argv[i+1] && *argv[i+1] != '-') +				i++; +			continue; +		} else if (*argv[i] == '-' && argv[i][1] != 'l') { +			opt(argv[i]); +			continue; +		} else if (*argv[i] != '-' && suffix(argv[i], suffixes, 3) >= 0) +			nf++; +		argv[j++] = argv[i]; +	} +	if ((cflag || Sflag) && outfile && nf != 1) { +		fprintf(stderr, "%s: -o %s ignored\n", progname, outfile); +		outfile = 0; +	} +	argv[j] = 0; +	for (i = 0; include[i]; i++) +		plist = append(include[i], plist); +	if (ilist) { +		List b = ilist; +		do { +			b = b->link; +			plist = append(b->str, plist); +		} while (b != ilist); +	} +	ilist = 0; +	for (i = 1; argv[i]; i++) +		if (*argv[i] == '-') +			opt(argv[i]); +		else { +			char *name = exists(argv[i]); +			if (name) { +				if (strcmp(name, argv[i]) != 0 +				|| (nf > 1 && suffix(name, suffixes, 3) >= 0)) +					fprintf(stderr, "%s:\n", name); +				filename(name, 0); +			} else +				error("can't find `%s'", argv[i]); +		} +	if (errcnt == 0 && !Eflag && !Sflag && !cflag && llist[1]) { +		compose(ld, llist[0], llist[1], +			append(outfile ? outfile : concat("a", first(suffixes[4])), 0)); +		if (callsys(av)) +			errcnt++; +	} +	rm(rmlist);	 +	return errcnt ? EXIT_FAILURE : EXIT_SUCCESS; +} + +/* alloc - allocate n bytes or die */ +static void *alloc(int n) { +	static char *avail, *limit; +	 +	n = (n + sizeof(char *) - 1)&~(sizeof(char *) - 1); +	if (n >= limit - avail) { +		avail = malloc(n + 4*1024); +		assert(avail); +		limit = avail + n + 4*1024; +	} +	avail += n; +	return avail - n; +} + +/* append - append a node with string str onto list, return new list */	 +static List append(char *str, List list) { +	List p = alloc(sizeof *p); + +	p->str = str; +	if (list) { +		p->link = list->link; +		list->link = p; +	} else +		p->link = p; +	return p; +} + +/* basename - return base name for name, e.g. /usr/drh/foo.c => foo */ +char *basename(char *name) { +	char *s, *b, *t = 0; + +	for (b = s = name; *s; s++) +		if (*s == '/' || *s == '\\') { +			b = s + 1; +			t = 0; +		} else if (*s == '.') +			t = s; +	s = strsave(b); +	if (t) +		s[t-b] = 0; +	return s; +} + +#ifdef WIN32 +#include <process.h> +#else +#define _P_WAIT 0 +#ifndef __sun +extern int fork(void); +#endif +extern int wait(int *); + +static int _spawnvp(int mode, const char *cmdname, char *argv[]) { +	int pid, n, status; + +	switch (pid = fork()) { +	case -1: +		fprintf(stderr, "%s: no more processes\n", progname); +		return 100; +	case 0: +		// TTimo removing hardcoded paths, searching in $PATH +		execvp(cmdname, argv); +		fprintf(stderr, "%s: ", progname); +		perror(cmdname); +		fflush(stdout); +		exit(100); +	} +	while ((n = wait(&status)) != pid && n != -1) +		; +	if (n == -1) +		status = -1; +	if (status&0377) { +		fprintf(stderr, "%s: fatal error in %s\n", progname, cmdname); +		status |= 0400; +	} +	return (status>>8)&0377; +} +#endif + +/* callsys - execute the command described by av[0...], return status */ +static int callsys(char **av) { +	int i, status = 0; +	static char **argv; +	static int argc; +	char *executable; + +	for (i = 0; av[i] != NULL; i++) +		; +	if (i + 1 > argc) { +		argc = i + 1; +		if (argv == NULL) +			argv = malloc(argc*sizeof *argv); +		else +			argv = realloc(argv, argc*sizeof *argv); +		assert(argv); +	} +	for (i = 0; status == 0 && av[i] != NULL; ) { +		int j = 0; +		char *s = NULL; +		for ( ; av[i] != NULL && (s = strchr(av[i], '\n')) == NULL; i++) +			argv[j++] = av[i]; +		if (s != NULL) { +			if (s > av[i]) +				argv[j++] = stringf("%.*s", s - av[i], av[i]); +			if (s[1] != '\0') +				av[i] = s + 1; +			else +				i++; +		} +		argv[j] = NULL; +		executable = strsave( argv[0] ); +		argv[0] = stringf( "\"%s\"", argv[0] ); +		if (verbose > 0) { +			int k; +			fprintf(stderr, "%s", argv[0]); +			for (k = 1; argv[k] != NULL; k++) +				fprintf(stderr, " %s", argv[k]); +			fprintf(stderr, "\n"); +		} +		if (verbose < 2) +#ifndef WIN32 +			status = _spawnvp(_P_WAIT, executable, argv); +#else +			status = _spawnvp(_P_WAIT, executable, (const char* const*)argv); +#endif +		if (status == -1) { +			fprintf(stderr, "%s: ", progname); +			perror(argv[0]); +		} +	} +	return status; +} + +/* concat - return concatenation of strings s1 and s2 */ +char *concat(char *s1, char *s2) { +	int n = strlen(s1); +	char *s = alloc(n + strlen(s2) + 1); + +	strcpy(s, s1); +	strcpy(s + n, s2); +	return s; +} + +/* compile - compile src into dst, return status */ +static int compile(char *src, char *dst) { +	compose(com, clist, append(src, 0), append(dst, 0)); +	return callsys(av); +} + +/* compose - compose cmd into av substituting a, b, c for $1, $2, $3, resp. */ +static void compose(char *cmd[], List a, List b, List c) { +	int i, j; +	List lists[3]; + +	lists[0] = a; +	lists[1] = b; +	lists[2] = c; +	for (i = j = 0; cmd[i]; i++) { +		char *s = strchr(cmd[i], '$'); +		if (s && isdigit(s[1])) { +			int k = s[1] - '0'; +			assert(k >=1 && k <= 3); +			if ((b = lists[k-1])) { +				b = b->link; +				av[j] = alloc(strlen(cmd[i]) + strlen(b->str) - 1); +				strncpy(av[j], cmd[i], s - cmd[i]); +				av[j][s-cmd[i]] = '\0'; +				strcat(av[j], b->str); +				strcat(av[j++], s + 2); +				while (b != lists[k-1]) { +					b = b->link; +					assert(j < ac); +					av[j++] = b->str; +				}; +			} +		} else if (*cmd[i]) { +			assert(j < ac); +			av[j++] = cmd[i]; +		} +	} +	av[j] = NULL; +} + +/* error - issue error msg according to fmt, bump error count */ +static void error(char *fmt, char *msg) { +	fprintf(stderr, "%s: ", progname); +	fprintf(stderr, fmt, msg); +	fprintf(stderr, "\n"); +	errcnt++; +} + +/* exists - if `name' readable return its path name or return null */ +static char *exists(char *name) { +	List b; + +	if ( (name[0] == '/' || name[0] == '\\' || name[2] == ':') +	&& access(name, 4) == 0) +		return name; +	if (!(name[0] == '/' || name[0] == '\\' || name[2] == ':') +	&& (b = lccinputs))		 +		do { +			b = b->link; +			if (b->str[0]) { +				char buf[1024]; +				sprintf(buf, "%s/%s", b->str, name); +				if (access(buf, 4) == 0) +					return strsave(buf); +			} else if (access(name, 4) == 0) +				return name; +		} while (b != lccinputs); +	if (verbose > 1) +		return name; +	return 0; +} + +/* first - return first component in semicolon separated list */ +static char *first(char *list) { +	char *s = strchr(list, ';'); + +	if (s) { +		char buf[1024]; +		strncpy(buf, list, s-list); +		buf[s-list] = '\0'; +		return strsave(buf); +	} else +		return list; +} + +/* filename - process file name argument `name', return status */ +static int filename(char *name, char *base) { +	int status = 0; +	static char *stemp, *itemp; + +	if (base == 0) +		base = basename(name); +	switch (suffix(name, suffixes, 4)) { +	case 0:	/* C source files */ +		compose(cpp, plist, append(name, 0), 0); +		if (Eflag) { +			status = callsys(av); +			break; +		} +		if (itemp == NULL) +			itemp = tempname(first(suffixes[1])); +		compose(cpp, plist, append(name, 0), append(itemp, 0)); +		status = callsys(av); +		if (status == 0) +			return filename(itemp, base); +		break; +	case 1:	/* preprocessed source files */ +		if (Eflag) +			break; +		if (Sflag) +			status = compile(name, outfile ? outfile : concat(base, first(suffixes[2]))); +		else if ((status = compile(name, stemp?stemp:(stemp=tempname(first(suffixes[2]))))) == 0) +			return filename(stemp, base); +		break; +	case 2:	/* assembly language files */ +		if (Eflag) +			break; +		if (!Sflag) { +			char *ofile; +			if (cflag && outfile) +				ofile = outfile; +			else if (cflag) +				ofile = concat(base, first(suffixes[3])); +			else +				ofile = tempname(first(suffixes[3])); +			compose(as, alist, append(name, 0), append(ofile, 0)); +			status = callsys(av); +			if (!find(ofile, llist[1])) +				llist[1] = append(ofile, llist[1]); +		} +		break; +	case 3:	/* object files */ +		if (!find(name, llist[1])) +			llist[1] = append(name, llist[1]); +		break; +	default: +		if (Eflag) { +			compose(cpp, plist, append(name, 0), 0); +			status = callsys(av); +		} +		llist[1] = append(name, llist[1]); +		break; +	} +	if (status) +		errcnt++; +	return status; +} + +/* find - find 1st occurrence of str in list, return list node or 0 */ +static List find(char *str, List list) { +	List b; +	 +	if ((b = list)) +		do { +			if (strcmp(str, b->str) == 0) +				return b; +		} while ((b = b->link) != list); +	return 0; +} + +/* help - print help message */ +static void help(void) { +	static char *msgs[] = { +"", " [ option | file ]...\n", +"	except for -l, options are processed left-to-right before files\n", +"	unrecognized options are taken to be linker options\n", +"-A	warn about nonANSI usage; 2nd -A warns more\n", +"-b	emit expression-level profiling code; see bprint(1)\n", +#ifdef sparc +"-Bstatic -Bdynamic	specify static or dynamic libraries\n", +#endif +"-Bdir/	use the compiler named `dir/rcc'\n", +"-c	compile only\n", +"-dn	set switch statement density to `n'\n", +"-Dname -Dname=def	define the preprocessor symbol `name'\n", +"-E	run only the preprocessor on the named C programs and unsuffixed files\n", +"-g	produce symbol table information for debuggers\n", +"-help or -?	print this message\n", +"-Idir	add `dir' to the beginning of the list of #include directories\n",	 +"-lx	search library `x'\n", +"-N	do not search the standard directories for #include files\n", +"-n	emit code to check for dereferencing zero pointers\n", +"-O	is ignored\n", +"-o file	leave the output in `file'\n", +"-P	print ANSI-style declarations for globals\n", +"-p -pg	emit profiling code; see prof(1) and gprof(1)\n", +"-S	compile to assembly language\n", +#ifdef linux +"-static	specify static libraries (default is dynamic)\n", +#endif +"-t -tname	emit function tracing calls to printf or to `name'\n", +"-target name	is ignored\n", +"-tempdir=dir	place temporary files in `dir/'", "\n" +"-Uname	undefine the preprocessor symbol `name'\n", +"-v	show commands as they are executed; 2nd -v suppresses execution\n", +"-w	suppress warnings\n", +"-Woarg	specify system-specific `arg'\n", +"-W[pfal]arg	pass `arg' to the preprocessor, compiler, assembler, or linker\n", +	0 }; +	int i; +	char *s; + +	msgs[0] = progname; +	for (i = 0; msgs[i]; i++) { +		fprintf(stderr, "%s", msgs[i]); +		if (strncmp("-tempdir", msgs[i], 8) == 0 && tempdir) +			fprintf(stderr, "; default=%s", tempdir); +	} +#define xx(v) if ((s = getenv(#v))) fprintf(stderr, #v "=%s\n", s) +	xx(LCCINPUTS); +	xx(LCCDIR); +#ifdef WIN32 +	xx(include); +	xx(lib); +#endif +#undef xx +} + +/* initinputs - if LCCINPUTS or include is defined, use them to initialize various lists */ +static void initinputs(void) { +	char *s = getenv("LCCINPUTS"); +	List b; +#ifdef WIN32 +	List list; +#endif + +	if (s == 0 || (s = inputs)[0] == 0) +		s = "."; +	if (s) { +		lccinputs = path2list(s); +		if ((b = lccinputs)) +			do { +				b = b->link; +				if (strcmp(b->str, ".") != 0) { +					ilist = append(concat("-I", b->str), ilist); +					if (strstr(com[1], "win32") == NULL) +						llist[0] = append(concat("-L", b->str), llist[0]); +				} else +					b->str = ""; +			} while (b != lccinputs); +	} +#ifdef WIN32 +	if ((list = b = path2list(getenv("include")))) +		do { +			b = b->link; +			ilist = append(stringf("-I\"%s\"", b->str), ilist); +		} while (b != list); +#endif +} + +/* interrupt - catch interrupt signals */ +static void interrupt(int n) { +	rm(rmlist); +	exit(n = 100); +} + +/* opt - process option in arg */ +static void opt(char *arg) { +	switch (arg[1]) {	/* multi-character options */ +	case 'W':	/* -Wxarg */ +		if (arg[2] && arg[3]) +			switch (arg[2]) { +			case 'o': +				if (option(&arg[3])) +					return; +				break; +			case 'p': +				plist = append(&arg[3], plist); +				return; +			case 'f': +				if (strcmp(&arg[3], "-C") || option("-b")) { +					clist = append(&arg[3], clist); +					return; +				} +				break; /* and fall thru */ +			case 'a': +				alist = append(&arg[3], alist); +				return; +			case 'l': +				llist[0] = append(&arg[3], llist[0]); +				return; +			} +		fprintf(stderr, "%s: %s ignored\n", progname, arg); +		return; +	case 'd':	/* -dn */ +		arg[1] = 's'; +		clist = append(arg, clist); +		return; +	case 't':	/* -t -tname -tempdir=dir */ +		if (strncmp(arg, "-tempdir=", 9) == 0) +			tempdir = arg + 9; +		else +			clist = append(arg, clist); +		return; +	case 'p':	/* -p -pg */ +		if (option(arg)) +			clist = append(arg, clist); +		else +			fprintf(stderr, "%s: %s ignored\n", progname, arg); +		return; +	case 'D':	/* -Dname -Dname=def */ +	case 'U':	/* -Uname */ +	case 'I':	/* -Idir */ +		plist = append(arg, plist); +		return; +	case 'B':	/* -Bdir -Bstatic -Bdynamic */ +#ifdef sparc +		if (strcmp(arg, "-Bstatic") == 0 || strcmp(arg, "-Bdynamic") == 0) +			llist[1] = append(arg, llist[1]); +		else +#endif	 +		{ +		static char *path; +		if (path) +			error("-B overwrites earlier option", 0); +		path = arg + 2; +		if (strstr(com[1], "win32") != NULL) +			com[0] = concat(replace(path, '/', '\\'), concat("rcc", first(suffixes[4]))); +		else +			com[0] = concat(path, "rcc"); +		if (path[0] == 0) +			error("missing directory in -B option", 0); +		} +		return; +	case 'h': +		if (strcmp(arg, "-help") == 0) { +			static int printed = 0; +	case '?': +			if (!printed) +				help(); +			printed = 1; +			return; +		} +#ifdef linux +	case 's': +		if (strcmp(arg,"-static") == 0) { +			if (!option(arg)) +				fprintf(stderr, "%s: %s ignored\n", progname, arg); +			return; +		} +#endif          +	} +	if (arg[2] == 0) +		switch (arg[1]) {	/* single-character options */ +		case 'S': +			Sflag++; +			return; +		case 'O': +			fprintf(stderr, "%s: %s ignored\n", progname, arg); +			return; +		case 'A': case 'n': case 'w': case 'P': +			clist = append(arg, clist); +			return; +		case 'g': case 'b': +			if (option(arg)) +				clist = append(arg[1] == 'g' ? "-g2" : arg, clist); +			else +				fprintf(stderr, "%s: %s ignored\n", progname, arg); +			return; +		case 'G': +			if (option(arg)) { +				clist = append("-g3", clist); +				llist[0] = append("-N", llist[0]); +			} else +				fprintf(stderr, "%s: %s ignored\n", progname, arg); +			return; +		case 'E': +			Eflag++; +			return; +		case 'c': +			cflag++; +			return; +		case 'N': +			if (strcmp(basename(cpp[0]), "gcc-cpp") == 0) +				plist = append("-nostdinc", plist); +			include[0] = 0; +			ilist = 0; +			return; +		case 'v': +			if (verbose++ == 0) { +				if (strcmp(basename(cpp[0]), "gcc-cpp") == 0) +					plist = append(arg, plist); +				clist = append(arg, clist); +				fprintf(stderr, "%s %s\n", progname, rcsid); +			} +			return; +		} +	if (cflag || Sflag || Eflag) +		fprintf(stderr, "%s: %s ignored\n", progname, arg); +	else +		llist[1] = append(arg, llist[1]); +} + +/* path2list - convert a colon- or semicolon-separated list to a list */ +static List path2list(const char *path) { +	List list = NULL; +	char sep = ':'; + +	if (path == NULL) +		return NULL; +	if (strchr(path, ';')) +		sep = ';'; +	while (*path) { +		char *p, buf[512]; +		if ((p = strchr(path, sep))) { +			assert(p - path < sizeof buf); +			strncpy(buf, path, p - path); +			buf[p-path] = '\0'; +		} else { +			assert(strlen(path) < sizeof buf); +			strcpy(buf, path); +		} +		if (!find(buf, list)) +			list = append(strsave(buf), list); +		if (p == 0) +			break; +		path = p + 1; +	} +	return list; +} + +/* replace - copy str, then replace occurrences of from with to, return the copy */ +char *replace(const char *str, int from, int to) { +	char *s = strsave(str), *p = s; + +	for ( ; (p = strchr(p, from)) != NULL; p++) +		*p = to; +	return s; +} + +/* rm - remove files in list */ +static void rm(List list) { +	if (list) { +		List b = list; +		if (verbose) +			fprintf(stderr, "rm"); +		do { +			if (verbose) +				fprintf(stderr, " %s", b->str); +			if (verbose < 2) +				remove(b->str); +		} while ((b = b->link) != list); +		if (verbose) +			fprintf(stderr, "\n"); +	} +} + +/* strsave - return a saved copy of string str */ +char *strsave(const char *str) { +	return strcpy(alloc(strlen(str)+1), str); +} + +/* stringf - format and return a string */ +char *stringf(const char *fmt, ...) { +	char buf[1024]; +	va_list ap; +	int n; + +	va_start(ap, fmt); +	n = vsprintf(buf, fmt, ap); +	va_end(ap); +	return strsave(buf); +} + +/* suffix - if one of tails[0..n-1] holds a proper suffix of name, return its index */ +int suffix(char *name, char *tails[], int n) { +	int i, len = strlen(name); + +	for (i = 0; i < n; i++) { +		char *s = tails[i], *t; +		for ( ; (t = strchr(s, ';')); s = t + 1) { +			int m = t - s; +			if (len > m && strncmp(&name[len-m], s, m) == 0) +				return i; +		} +		if (*s) { +			int m = strlen(s); +			if (len > m && strncmp(&name[len-m], s, m) == 0) +				return i; +		} +	} +	return -1; +} + +/* tempname - generate a temporary file name in tempdir with given suffix */ +char *tempname(char *suffix) { +	static int n; +	char *name = stringf("%s/lcc%d%d%s", tempdir, getpid(), n++, suffix); + +	if (strstr(com[1], "win32") != NULL) +		name = replace(name, '/', '\\'); +	rmlist = append(name, rmlist); +	return name; +} diff --git a/src/tools/lcc/lburg/gram.c b/src/tools/lcc/lburg/gram.c new file mode 100644 index 0000000..a1cc890 --- /dev/null +++ b/src/tools/lcc/lburg/gram.c @@ -0,0 +1,682 @@ +#if defined(__STDC__) || defined(__cplusplus) +#define YYCONST const +#define YYPARAMS(x) x +#define YYDEFUN(name, arglist, args) name(args) +#define YYAND , +#define YYPTR void * +#else +#define YYCONST +#define YYPARAMS(x) () +#define YYDEFUN(name, arglist, args) name arglist args; +#define YYAND ; +#define YYPTR char * +#endif +#ifndef lint +YYCONST static char yysccsid[] = "@(#)yaccpar	1.8 (Berkeley +Cygnus.28) 01/20/91"; +#endif +#define YYBYACC 1 +#ifndef YYDONT_INCLUDE_STDIO +#include <stdio.h> +#endif +//#ifdef __cplusplus TA <tim@ngus.net> stdlib.h applies to C too +#include <stdlib.h> /* for malloc/realloc/free */ +//#endif +#line 2 "lburg/gram.y" +#include <stdio.h> +#include "lburg.h" +/*lint -e616 -e527 -e652 -esym(552,yynerrs) -esym(563,yynewstate,yyerrlab) */ +static int yylineno = 0; +#line 8 "lburg/gram.y" +typedef union { +	int n; +	char *string; +	Tree tree; +} YYSTYPE; +#line 37 "y.tab.c" +#define TERMINAL 257 +#define START 258 +#define PPERCENT 259 +#define ID 260 +#define TEMPLATE 261 +#define CODE 262 +#define INT 263 +#define YYERRCODE 256 +static YYCONST short yylhs[] = {                                        -1, +    0,    0,    4,    4,    6,    6,    6,    6,    7,    7, +    5,    5,    5,    5,    1,    3,    3,    3,    2, +}; +static YYCONST short yylen[] = {                                         2, +    3,    1,    0,    2,    3,    3,    1,    2,    0,    4, +    0,    7,    2,    3,    1,    1,    4,    6,    1, +}; +static YYCONST short yydefred[] = {                                      3, +    0,    0,    0,    9,    0,   11,    7,    4,    8,    0, +   15,    0,    0,    0,    5,    6,    0,   13,    0,    0, +   14,    0,   10,    0,    0,    0,    0,    0,   19,    0, +   17,    0,   12,    0,   18, +}; +static YYCONST short yydgoto[] = {                                       1, +   12,   30,   25,    2,   13,    8,   10, +}; +static YYCONST short yysindex[] = {                                      0, +    0,   -4,   -2,    0, -250,    0,    0,    0,    0,   -9, +    0,    1,  -10,  -49,    0,    0,    3,    0,  -44, -248, +    0, -244,    0,  -22, -242, -244, -245,  -37,    0,   10, +    0, -244,    0,  -20,    0, +}; +static YYCONST short yyrindex[] = {                                      0, +    0,   22,    0,    0,    0,    0,    0,    0,    0,    0, +    0,    0,   23,    0,    0,    0,    0,    0,    0,    0, +    0,    0,    0,  -39,    0,    0,    0,    0,    0,    0, +    0,    0,    0,    0,    0, +}; +static YYCONST short yygindex[] = {                                      0, +   11,    0,  -23,    0,    0,    0,    0, +}; +#define YYTABLESIZE 255 +static YYCONST short yytable[] = {                                      18, +   15,   16,   28,   31,   16,    7,   32,    9,   34,   11, +   16,   20,   21,   22,   23,   24,   29,   26,   27,   33, +   35,    2,    1,   19,    0,    0,    0,    0,    0,    0, +    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, +    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, +    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, +    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, +    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, +    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, +    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, +    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, +    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, +    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, +    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, +    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, +    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, +    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, +    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, +    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, +    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, +    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, +    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, +    0,   16,    0,    0,    0,    0,    0,    0,    0,    0, +    0,    0,    0,    0,    0,    0,    0,    0,    0,    0, +    0,    0,    0,    0,    0,   17,    0,    0,    0,   11, +   14,    3,    4,    5,    6, +}; +static YYCONST short yycheck[] = {                                      10, +   10,   41,   26,   41,   44,   10,   44,   10,   32,  260, +   10,   61,   10,   58,  263,  260,  262,   40,  261,   10, +   41,    0,    0,   13,   -1,   -1,   -1,   -1,   -1,   -1, +   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +   -1,  261,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1, +   -1,   -1,   -1,   -1,   -1,  256,   -1,   -1,   -1,  260, +  260,  256,  257,  258,  259, +}; +#define YYFINAL 1 +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif +#define YYMAXTOKEN 263 +#if YYDEBUG +static YYCONST char *YYCONST yyname[] = { +"end-of-file",0,0,0,0,0,0,0,0,0,"'\\n'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,"'('","')'",0,0,"','",0,0,0,0,0,0,0,0,0,0,0,0,0,"':'",0,0, +"'='",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +"TERMINAL","START","PPERCENT","ID","TEMPLATE","CODE","INT", +}; +static YYCONST char *YYCONST yyrule[] = { +"$accept : spec", +"spec : decls PPERCENT rules", +"spec : decls", +"decls :", +"decls : decls decl", +"decl : TERMINAL blist '\\n'", +"decl : START nonterm '\\n'", +"decl : '\\n'", +"decl : error '\\n'", +"blist :", +"blist : blist ID '=' INT", +"rules :", +"rules : rules nonterm ':' tree TEMPLATE cost '\\n'", +"rules : rules '\\n'", +"rules : rules error '\\n'", +"nonterm : ID", +"tree : ID", +"tree : ID '(' tree ')'", +"tree : ID '(' tree ',' tree ')'", +"cost : CODE", +}; +#endif +#define YYLEX yylex() +#define YYEMPTY -1 +#define yyclearin (yychar=(YYEMPTY)) +#define yyerrok (yyerrflag=0) +#ifndef YYINITDEPTH +#define YYINITDEPTH 200 +#endif +#ifdef YYSTACKSIZE +#ifndef YYMAXDEPTH +#define YYMAXDEPTH YYSTACKSIZE +#endif +#else +#ifdef YYMAXDEPTH +#define YYSTACKSIZE YYMAXDEPTH +#else +#define YYSTACKSIZE 500 +#define YYMAXDEPTH 500 +#endif +#endif +#ifndef YYMAXSTACKSIZE +#define YYMAXSTACKSIZE 10000 +#endif +int yydebug; +int yynerrs; +int yyerrflag; +int yychar; +YYSTYPE yyval; +YYSTYPE yylval; +static short *yyss; +static YYSTYPE *yyvs; +static int yystacksize; +#define yyfree(x) free(x) +extern int yylex(); + +static YYPTR +YYDEFUN (yymalloc, (bytes), unsigned bytes) +{ +    YYPTR ptr = (YYPTR) malloc (bytes); +    if (ptr != 0) return (ptr); +    yyerror ("yyparse: memory exhausted"); +    return (0); +} + +static YYPTR +YYDEFUN (yyrealloc, (old, bytes), YYPTR old YYAND unsigned bytes) +{ +    YYPTR ptr = (YYPTR) realloc (old, bytes); +    if (ptr != 0) return (ptr); +    yyerror ("yyparse: memory exhausted"); +    return (0); +} + +static int +#ifdef __GNUC__ +inline +#endif +yygrow () +{ +#if YYDEBUG +    int old_stacksize = yystacksize; +#endif +    short *new_yyss; +    YYSTYPE *new_yyvs; + +    if (yystacksize == YYMAXSTACKSIZE) +        return (1); +    yystacksize += (yystacksize + 1 ) / 2; +    if (yystacksize > YYMAXSTACKSIZE) +        yystacksize = YYMAXSTACKSIZE; +#if YYDEBUG +    if (yydebug) +        printf("yydebug: growing stack size from %d to %d\n", +               old_stacksize, yystacksize); +#endif +    new_yyss = (short *) yyrealloc ((char *)yyss, yystacksize * sizeof (short)); +    if (new_yyss == 0) +        return (1); +    new_yyvs = (YYSTYPE *) yyrealloc ((char *)yyvs, yystacksize * sizeof (YYSTYPE)); +    if (new_yyvs == 0) +    { +        yyfree (new_yyss); +        return (1); +    } +    yyss = new_yyss; +    yyvs = new_yyvs; +    return (0); +} +#line 60 "lburg/gram.y" +#include <assert.h> +#include <stdarg.h> +#include <ctype.h> +#include <string.h> +#include <limits.h> + +int errcnt = 0; +FILE *infp = NULL; +FILE *outfp = NULL; +static char buf[BUFSIZ], *bp = buf; +static int ppercent = 0; +static int code = 0; + +static int get(void) { +	if (*bp == 0) { +		bp = buf; +		*bp = 0; +		if (fgets(buf, sizeof buf, infp) == NULL) +			return EOF; +		yylineno++; +		while (buf[0] == '%' && buf[1] == '{' && buf[2] == '\n') { +			for (;;) { +				if (fgets(buf, sizeof buf, infp) == NULL) { +					yywarn("unterminated %{...%}\n"); +					return EOF; +				} +				yylineno++; +				if (strcmp(buf, "%}\n") == 0) +					break; +				fputs(buf, outfp); +			} +			if (fgets(buf, sizeof buf, infp) == NULL) +				return EOF; +			yylineno++; +		} +	} +	return *bp++; +} + +void yyerror(char *fmt, ...) { +	va_list ap; + +	va_start(ap, fmt); +	if (yylineno > 0) +		fprintf(stderr, "line %d: ", yylineno); +	vfprintf(stderr, fmt, ap); +	if (fmt[strlen(fmt)-1] != '\n') +		 fprintf(stderr, "\n"); +	errcnt++; +	va_end(ap); +} + +int yylex(void) { +	int c; + +	if (code) { +		char *p; +		bp += strspn(bp, " \t\f"); +		p = strchr(bp, '\n'); +		if (p == NULL) +			p = strchr(bp, '\n'); +		while (p > bp && isspace(p[-1])) +			p--; +		yylval.string = alloc(p - bp + 1); +		strncpy(yylval.string, bp, p - bp); +		yylval.string[p - bp] = 0; +		bp = p; +		code--; +		return CODE; +	} +	while ((c = get()) != EOF) { +		switch (c) { +		case ' ': case '\f': case '\t': +			continue; +		case '\n': +		case '(': case ')': case ',': +		case ':': case '=': +			return c; +		} +		if (c == '%' && *bp == '%') { +			bp++; +			return ppercent++ ? 0 : PPERCENT; +		} else if (c == '%' && strncmp(bp, "term", 4) == 0 +		&& isspace(bp[4])) { +			bp += 4; +			return TERMINAL; +		} else if (c == '%' && strncmp(bp, "start", 5) == 0 +		&& isspace(bp[5])) { +			bp += 5; +			return START; +		} else if (c == '"') { +			char *p = strchr(bp, '"'); +			if (p == NULL) { +				yyerror("missing \" in assembler template\n"); +				p = strchr(bp, '\n'); +				if (p == NULL) +					p = strchr(bp, '\0'); +			} +			assert(p); +			yylval.string = alloc(p - bp + 1); +			strncpy(yylval.string, bp, p - bp); +			yylval.string[p - bp] = 0; +			bp = *p == '"' ? p + 1 : p; +			code++; +			return TEMPLATE; +		} else if (isdigit(c)) { +			int n = 0; +			do { +				int d = c - '0'; +				if (n > (INT_MAX - d)/10) +					yyerror("integer greater than %d\n", INT_MAX); +				else +					n = 10*n + d; +				c = get(); +			} while (c != EOF && isdigit(c)); +			bp--; +			yylval.n = n; +			return INT; +		} else if (isalpha(c)) { +			char *p = bp - 1; +			while (isalpha(*bp) || isdigit(*bp) || *bp == '_') +				bp++; +			yylval.string = alloc(bp - p + 1); +			strncpy(yylval.string, p, bp - p); +			yylval.string[bp - p] = 0; +			return ID; +		} else if (isprint(c)) +			yyerror("invalid character `%c'\n", c); +		else +			yyerror("invalid character `\\%03o'\n", (unsigned char)c); +	} +	return 0; +} + +void yywarn(char *fmt, ...) { +	va_list ap; + +	va_start(ap, fmt); +	if (yylineno > 0) +		fprintf(stderr, "line %d: ", yylineno); +	fprintf(stderr, "warning: "); +	vfprintf(stderr, fmt, ap); +} +#line 403 "y.tab.c" +#define YYABORT goto yyabort +#define YYACCEPT goto yyaccept +#define YYERROR goto yyerrlab + +#if YYDEBUG +#ifdef __cplusplus +extern "C" char *getenv(); +#else +extern char *getenv(); +#endif +#endif + +int +yyparse() +{ +    register int yym, yyn, yystate; +    register YYSTYPE *yyvsp; +    register short *yyssp; +    short *yysse; +#if YYDEBUG +    register YYCONST char *yys; + +    if (yys = getenv("YYDEBUG")) +    { +        yyn = *yys; +        if (yyn >= '0' && yyn <= '9') +            yydebug = yyn - '0'; +    } +#endif + +    yynerrs = 0; +    yyerrflag = 0; +    yychar = (-1); + +    if (yyss == 0) +    { +        yyss = (short *) yymalloc (YYSTACKSIZE * sizeof (short)); +        if (yyss == 0) +          goto yyabort; +        yyvs = (YYSTYPE *) yymalloc (YYSTACKSIZE * sizeof (YYSTYPE)); +        if (yyvs == 0) +        { +            yyfree (yyss); +            goto yyabort; +        } +        yystacksize = YYSTACKSIZE; +    } +    yysse = yyss + yystacksize - 1; +    yyssp = yyss; +    yyvsp = yyvs; +    *yyssp = yystate = 0; +    goto yyloop; + +yypush_lex: +    yyval = yylval; +    yystate = yytable[yyn]; +yypush: +    if (yyssp >= yysse) +    { +        int depth = yyssp - yyss; +        if (yygrow() != 0) +             goto yyoverflow; +        yysse = yyss + yystacksize -1; +        yyssp = depth + yyss; +        yyvsp = depth + yyvs; +    } +    *++yyssp = yystate; +    *++yyvsp = yyval; + +yyloop: +    if ((yyn = yydefred[yystate])) goto yyreduce; +    yyn = yysindex[yystate]; +    if (yychar < 0) +    { +        if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG +        if (yydebug) +        { +            yys = 0; +            if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; +            if (!yys) yys = "illegal-symbol"; +            printf("yydebug: state %d, reading %d (%s)\n", yystate, +                    yychar, yys); +        } +#endif +    } +    if (yyn != 0 +        && ((yyn += yychar), ((unsigned)yyn <= (unsigned)YYTABLESIZE)) +        && yycheck[yyn] == yychar) +    { +#if YYDEBUG +        if (yydebug) +            printf("yydebug: state %d, shifting to state %d\n", +                    yystate, yytable[yyn]); +#endif +        if (yyerrflag > 0)  --yyerrflag; +        yychar = (-1); +        goto yypush_lex; +    } +    yyn = yyrindex[yystate]; +    if (yyn != 0 +        && ((yyn += yychar), ((unsigned)yyn <= (unsigned)YYTABLESIZE)) +        && yycheck[yyn] == yychar) +    { +        yyn = yytable[yyn]; +        goto yyreduce; +    } +    if (yyerrflag) goto yyinrecovery; +#ifdef lint +    goto yynewerror; +yynewerror: +#endif +    yyerror("syntax error"); +#ifdef lint +    goto yyerrlab; +yyerrlab: +#endif +    ++yynerrs; +yyinrecovery: +    if (yyerrflag < 3) +    { +        yyerrflag = 3; +        for (;;) +        { +            yyn = yysindex[*yyssp]; +            if (yyn != 0 +                && ((yyn += YYERRCODE), ((unsigned)yyn <= (unsigned)YYTABLESIZE)) +                && yycheck[yyn] == YYERRCODE) +            { +#if YYDEBUG +                if (yydebug) +                    printf("yydebug: state %d, error recovery shifting\ + to state %d\n", *yyssp, yytable[yyn]); +#endif +                goto yypush_lex; +            } +            else +            { +#if YYDEBUG +                if (yydebug) +                    printf("yydebug: error recovery discarding state %d\n", +                            *yyssp); +#endif +                if (yyssp <= yyss) goto yyabort; +                --yyssp; +                --yyvsp; +            } +        } +    } +    else +    { +        if (yychar == 0) goto yyabort; +#if YYDEBUG +        if (yydebug) +        { +            yys = 0; +            if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; +            if (!yys) yys = "illegal-symbol"; +            printf("yydebug: state %d, error recovery discards token %d (%s)\n", +                    yystate, yychar, yys); +        } +#endif +        yychar = (-1); +        goto yyloop; +    } +yyreduce: +#if YYDEBUG +    if (yydebug) +        printf("yydebug: state %d, reducing by rule %d (%s)\n", +                yystate, yyn, yyrule[yyn]); +#endif +    yym = yylen[yyn]; +    yyval = yyvsp[1-yym]; +    switch (yyn) +    { +case 1: +#line 22 "lburg/gram.y" +{ yylineno = 0; } +break; +case 2: +#line 23 "lburg/gram.y" +{ yylineno = 0; } +break; +case 6: +#line 31 "lburg/gram.y" +{ +		if (nonterm(yyvsp[-1].string)->number != 1) +			yyerror("redeclaration of the start symbol\n"); +		} +break; +case 8: +#line 36 "lburg/gram.y" +{ yyerrok; } +break; +case 10: +#line 40 "lburg/gram.y" +{ term(yyvsp[-2].string, yyvsp[0].n); } +break; +case 12: +#line 44 "lburg/gram.y" +{ rule(yyvsp[-5].string, yyvsp[-3].tree, yyvsp[-2].string, yyvsp[-1].string); } +break; +case 14: +#line 46 "lburg/gram.y" +{ yyerrok; } +break; +case 15: +#line 49 "lburg/gram.y" +{ nonterm(yyval.string = yyvsp[0].string); } +break; +case 16: +#line 52 "lburg/gram.y" +{ yyval.tree = tree(yyvsp[0].string,  0,  0); } +break; +case 17: +#line 53 "lburg/gram.y" +{ yyval.tree = tree(yyvsp[-3].string, yyvsp[-1].tree,  0); } +break; +case 18: +#line 54 "lburg/gram.y" +{ yyval.tree = tree(yyvsp[-5].string, yyvsp[-3].tree, yyvsp[-1].tree); } +break; +case 19: +#line 57 "lburg/gram.y" +{ if (*yyvsp[0].string == 0) yyval.string = "0"; } +break; +#line 630 "y.tab.c" +    } +    yyssp -= yym; +    yyvsp -= yym; +    yym = yylhs[yyn]; +    yystate = *yyssp; +    if (yystate == 0 && yym == 0) +    { +#if YYDEBUG +        if (yydebug) +            printf("yydebug: after reduction, shifting from state 0 to\ + state %d\n", YYFINAL); +#endif +        yystate = YYFINAL; +        *++yyssp = YYFINAL; +        *++yyvsp = yyval; +        if (yychar < 0) +        { +            if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG +            if (yydebug) +            { +                yys = 0; +                if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; +                if (!yys) yys = "illegal-symbol"; +                printf("yydebug: state %d, reading %d (%s)\n", +                        YYFINAL, yychar, yys); +            } +#endif +        } +        if (yychar == 0) goto yyaccept; +        goto yyloop; +    } +    yyn = yygindex[yym]; +	 if (yyn != 0 +        && ((yyn += yystate), ((unsigned)yyn <= (unsigned)YYTABLESIZE)) +        && yycheck[yyn] == yystate) +        yystate = yytable[yyn]; +    else +        yystate = yydgoto[yym]; +#if YYDEBUG +    if (yydebug) +        printf("yydebug: after reduction, shifting from state %d \ +to state %d\n", *yyssp, yystate); +#endif +    goto yypush; +yyoverflow: +    yyerror("yacc stack overflow"); +yyabort: +    return (1); +yyaccept: +    return (0); +} diff --git a/src/tools/lcc/lburg/gram.y b/src/tools/lcc/lburg/gram.y new file mode 100644 index 0000000..1ecd8a9 --- /dev/null +++ b/src/tools/lcc/lburg/gram.y @@ -0,0 +1,202 @@ +%{ +#include <stdio.h> +#include "lburg.h" +static char rcsid[] = "$Id: gram.y 145 2001-10-17 21:53:10Z timo $"; +/*lint -e616 -e527 -e652 -esym(552,yynerrs) -esym(563,yynewstate,yyerrlab) */ +static int yylineno = 0; +%} +%union { +	int n; +	char *string; +	Tree tree; +} +%term TERMINAL +%term START +%term PPERCENT + +%token  <string>        ID TEMPLATE CODE +%token  <n>             INT +%type	<string>	nonterm cost +%type   <tree>          tree +%% +spec	: decls PPERCENT rules		{ yylineno = 0; } +	| decls				{ yylineno = 0; } +	; + +decls	: /* lambda */ +	| decls decl +	; + +decl	: TERMINAL  blist '\n' +	| START nonterm '\n'		{ +		if (nonterm($2)->number != 1) +			yyerror("redeclaration of the start symbol\n"); +		} +	| '\n' +	| error '\n'			{ yyerrok; } +	; + +blist	: /* lambda */ +	| blist ID '=' INT      	{ term($2, $4); } +	; + +rules	: /* lambda */ +	| rules nonterm ':' tree TEMPLATE cost '\n'	{ rule($2, $4, $5, $6); } +	| rules '\n' +	| rules error '\n'		{ yyerrok; } +	; + +nonterm	: ID				{ nonterm($$ = $1); } +	; + +tree	: ID                            { $$ = tree($1,  0,  0); } +	| ID '(' tree ')'               { $$ = tree($1, $3,  0); } +	| ID '(' tree ',' tree ')'      { $$ = tree($1, $3, $5); } +	; + +cost	: CODE				{ if (*$1 == 0) $$ = "0"; } +	; +%% +#include <assert.h> +#include <stdarg.h> +#include <ctype.h> +#include <string.h> +#include <limits.h> + +int errcnt = 0; +FILE *infp = NULL; +FILE *outfp = NULL; +static char buf[BUFSIZ], *bp = buf; +static int ppercent = 0; +static int code = 0; + +static int get(void) { +	if (*bp == 0) { +		bp = buf; +		*bp = 0; +		if (fgets(buf, sizeof buf, infp) == NULL) +			return EOF; +		yylineno++; +		while (buf[0] == '%' && buf[1] == '{' && buf[2] == '\n') { +			for (;;) { +				if (fgets(buf, sizeof buf, infp) == NULL) { +					yywarn("unterminated %{...%}\n"); +					return EOF; +				} +				yylineno++; +				if (strcmp(buf, "%}\n") == 0) +					break; +				fputs(buf, outfp); +			} +			if (fgets(buf, sizeof buf, infp) == NULL) +				return EOF; +			yylineno++; +		} +	} +	return *bp++; +} + +void yyerror(char *fmt, ...) { +	va_list ap; + +	va_start(ap, fmt); +	if (yylineno > 0) +		fprintf(stderr, "line %d: ", yylineno); +	vfprintf(stderr, fmt, ap); +	if (fmt[strlen(fmt)-1] != '\n') +		 fprintf(stderr, "\n"); +	errcnt++; +	va_end(ap); +} + +int yylex(void) { +	int c; + +	if (code) { +		char *p; +		bp += strspn(bp, " \t\f"); +		p = strchr(bp, '\n'); +		if (p == NULL) +			p = strchr(bp, '\n'); +		while (p > bp && isspace(p[-1])) +			p--; +		yylval.string = alloc(p - bp + 1); +		strncpy(yylval.string, bp, p - bp); +		yylval.string[p - bp] = 0; +		bp = p; +		code--; +		return CODE; +	} +	while ((c = get()) != EOF) { +		switch (c) { +		case ' ': case '\f': case '\t': +			continue; +		case '\n': +		case '(': case ')': case ',': +		case ':': case '=': +			return c; +		} +		if (c == '%' && *bp == '%') { +			bp++; +			return ppercent++ ? 0 : PPERCENT; +		} else if (c == '%' && strncmp(bp, "term", 4) == 0 +		&& isspace(bp[4])) { +			bp += 4; +			return TERMINAL; +		} else if (c == '%' && strncmp(bp, "start", 5) == 0 +		&& isspace(bp[5])) { +			bp += 5; +			return START; +		} else if (c == '"') { +			char *p = strchr(bp, '"'); +			if (p == NULL) { +				yyerror("missing \" in assembler template\n"); +				p = strchr(bp, '\n'); +				if (p == NULL) +					p = strchr(bp, '\0'); +			} +			assert(p); +			yylval.string = alloc(p - bp + 1); +			strncpy(yylval.string, bp, p - bp); +			yylval.string[p - bp] = 0; +			bp = *p == '"' ? p + 1 : p; +			code++; +			return TEMPLATE; +		} else if (isdigit(c)) { +			int n = 0; +			do { +				int d = c - '0'; +				if (n > (INT_MAX - d)/10) +					yyerror("integer greater than %d\n", INT_MAX); +				else +					n = 10*n + d; +				c = get(); +			} while (c != EOF && isdigit(c)); +			bp--; +			yylval.n = n; +			return INT; +		} else if (isalpha(c)) { +			char *p = bp - 1; +			while (isalpha(*bp) || isdigit(*bp) || *bp == '_') +				bp++; +			yylval.string = alloc(bp - p + 1); +			strncpy(yylval.string, p, bp - p); +			yylval.string[bp - p] = 0; +			return ID; +		} else if (isprint(c)) +			yyerror("invalid character `%c'\n", c); +		else +			yyerror("invalid character `\\%03o'\n", (unsigned char)c); +	} +	return 0; +} + +void yywarn(char *fmt, ...) { +	va_list ap; + +	va_start(ap, fmt); +	if (yylineno > 0) +		fprintf(stderr, "line %d: ", yylineno); +	fprintf(stderr, "warning: "); +	vfprintf(stderr, fmt, ap); +} diff --git a/src/tools/lcc/lburg/lburg.1 b/src/tools/lcc/lburg/lburg.1 new file mode 100644 index 0000000..8cf7250 --- /dev/null +++ b/src/tools/lcc/lburg/lburg.1 @@ -0,0 +1,179 @@ +.TH LBURG 1 "local \- 11/30/94" +.\" $Id: lburg.1 145 2001-10-17 21:53:10Z timo $ +.SH NAME +lburg \- lcc's code-generator generator +.SH SYNOPSIS +.B lburg +[ +.I option +]... +[ [ +.I input +] +.I output +] +.br +.SH DESCRIPTION +.PP +.I lburg +reads an lcc-style BURG specification from +.I input +and writes a pattern-matching code generator to +.IR output . +If +.I input +is `\-' or is omitted, +.I lburg +reads the standard input; +If +.I output +is `\-' or is omitted, +.I lburg +writes to the standard output. +.PP +.I lburg +accepts specifications that conform to the following EBNF grammar. +Terminals are enclosed in single quotes or are +given in uppercase, all other symbols are nonterminals or English phrases, +{X} denotes zero or more instances of X, and [X] denotes an optional X. +.PP +.nf +.RS +.ft CW +spec:     `%{' configuration `%}' { dcl } `%%' { rule } +               [ `%%' C code ] + +dcl:      `%start' nonterm +          `%term' { ID `=' INT } + +rule:     nonterm `:' tree template [ C expression ] + +tree:     term `(' tree `,' tree `)' +          term `(' tree `)' +          term +          nonterm + +nonterm:  ID + +template: `"' { any character except double quote } `"' +.RE +.fi +.PP +Specifications are structurally similar to +.IR yacc 's. +Text between +`\f(CW%{\fP' +and +`\f(CW%}\fP' +is called the configuration section; there may be several such segments. +All are concatenated and copied verbatim into the head of the output. +Text after the second +`\f(CW%%\fP', +if any, is also copied verbatim into the output, at the end. +.PP +Specifications consist of declarations, a +`\f(CW%%\fP' +separator, and rules. +Input is line-oriented; each declaration and rule must appear on a separate line, +and declarations must begin in column 1. +Declarations declare terminals \(em the operators in subject +trees \(em and associate a unique, positive external symbol +number with each one. +Nonterminals are declared by their presence +on the left side of rules.  The +\f(CW%start\fP +declaration optionally declares a nonterminal as the start symbol. +In the grammar above, +\f(CWterm\fP +and +\f(CWnonterm\fP +denote identifiers that are terminals and nonterminals. +.PP +Rules define tree patterns in a fully parenthesized prefix +form. Every nonterminal denotes a tree. +Each operator has a fixed +arity, which is inferred from the rules in which it is used. +A chain rule is a rule whose pattern is another nonterminal. +If no start symbol is declared, the nonterminal defined by the first rule is used. +.PP +Each rule ends with an expression that computes the cost of matching +that rule; omitted costs +default to zero. Costs of chain rules must be constants. +.PP +The configuration section configures the output +for the trees being parsed and the client's environment. +As shown, this section must define +\f(CWNODEPTR_TYPE\fP +to be a visible typedef symbol for a pointer to a +node in the subject tree. +The labeller invokes +\f(CWOP_LABEL(p)\fP, +\f(CWLEFT\_CHILD(p)\fP, and +\f(CWRIGHT\_CHILD(p)\fP +to read the operator and children from the node pointed to by \f(CWp\fP. +If the configuration section defines these operations as macros, they are implemented in-line; +otherwise, they must be implemented as functions. +.PP +The matcher +computes and stores a single integral state in each node of the subject tree. +The configuration section must define a macro +\f(CWSTATE_LABEL(p)\fP +to access the state field of the node pointed to +by \f(CWp\fP. It must be large enough to hold a pointer, and +a macro is required because it is used as an lvalue. +.PP +.SH OPTIONS +.TP +.BI \-p \ prefix +.br +.ns +.TP +.BI \-p prefix +Use +.I prefix +as the disambiquating prefix for visible names and fields. +The default is `\f(CW_\fP'. +.TP +.B \-T +Arrange for +.sp +.nf +.ft CW +    void _trace(NODEPTR_TYPE p, int eruleno, +                    int cost, int bestcost); +.sp +.fi +.ft R +to be called at each successful match. +\f(CWp\fP +identifies the node and +\f(CWeruleno\fP +identifies the matching rule; the rules are numbered +beginning at 1 in the order they appear in the input. +\f(CWcost\fP +is the cost of the match and +\f(CWbestcost\fP +is the cost of the best previous match. The current match +wins only if +\f(CWcost\fP +is less than \f(CWbestcost\fP. +32767 represents the infinite cost of no previous match. +\f(CW_trace\fP must be declared in the configuration section. +.SH "SEE ALSO" +.IR lcc (1) +.PP +C. W. Fraser and D. R. Hanson, +.IR A Retargetable C Compiler: Design and Implementation , +Benjamin/Cummings, Redwood City, CA, 1995, +ISBN 0-8053-1670-1. Chapter 14. +.PP +C. W. Fraser, D. R. Hanson and T. A. Proebsting, +`Engineering a simple, efficient code generator generator,' +.I +ACM Letters on Programming Languages and Systems +.BR 1 , +3 (Sep. 1992), 213-226. +.br +.SH BUGS +Mail bug reports along with the shortest input +that exposes them to drh@cs.princeton.edu. diff --git a/src/tools/lcc/lburg/lburg.c b/src/tools/lcc/lburg/lburg.c new file mode 100644 index 0000000..c43c96a --- /dev/null +++ b/src/tools/lcc/lburg/lburg.c @@ -0,0 +1,671 @@ +#include <assert.h> +#include <ctype.h> +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include "lburg.h" + +static char rcsid[] = "lburg.c - faked rcsid"; + +static char *prefix = ""; +static int Tflag = 0; +static int ntnumber = 0; +static Nonterm start = 0; +static Term terms; +static Nonterm nts; +static Rule rules; +static int nrules; +static struct block { +	struct block *link; +} *memlist;			/* list of allocated blocks */ + +static char *stringf(char *fmt, ...); +static void print(char *fmt, ...); +static void ckreach(Nonterm p); +static void emitclosure(Nonterm nts); +static void emitcost(Tree t, char *v); +static void emitdefs(Nonterm nts, int ntnumber); +static void emitheader(void); +static void emitkids(Rule rules, int nrules); +static void emitnts(Rule rules, int nrules); +static void emitrecalc(char *pre, Term root, Term kid); +static void emitrecord(char *pre, Rule r, char *c, int cost); +static void emitrule(Nonterm nts); +static void emitlabel(Term terms, Nonterm start, int ntnumber); +static void emitstring(Rule rules); +static void emitstruct(Nonterm nts, int ntnumber); +static void emittest(Tree t, char *v, char *suffix); + +int main(int argc, char *argv[]) { +	int c, i; +	Nonterm p; +	 +	for (i = 1; i < argc; i++) +		if (strcmp(argv[i], "-T") == 0) +			Tflag = 1; +		else if (strncmp(argv[i], "-p", 2) == 0 && argv[i][2]) +			prefix = &argv[i][2]; +		else if (strncmp(argv[i], "-p", 2) == 0 && i + 1 < argc) +			prefix = argv[++i]; +		else if (*argv[i] == '-' && argv[i][1]) { +			yyerror("usage: %s [-T | -p prefix]... [ [ input ] output ] \n", +				argv[0]); +			exit(1); +		} else if (infp == NULL) { +			if (strcmp(argv[i], "-") == 0) +				infp = stdin; +			else if ((infp = fopen(argv[i], "r")) == NULL) { +				yyerror("%s: can't read `%s'\n", argv[0], argv[i]); +				exit(1); +			} +		} else if (outfp == NULL) { +			if (strcmp(argv[i], "-") == 0) +				outfp = stdout; +			if ((outfp = fopen(argv[i], "w")) == NULL) { +				yyerror("%s: can't write `%s'\n", argv[0], argv[i]); +				exit(1); +			} +		} +	if (infp == NULL) +		infp = stdin; +	if (outfp == NULL) +		outfp = stdout; +	yyparse(); +	if (start) +		ckreach(start); +	for (p = nts; p; p = p->link) { +		if (p->rules == NULL) +			yyerror("undefined nonterminal `%s'\n", p->name); +		if (!p->reached) +			yyerror("can't reach nonterminal `%s'\n", p->name); +	} +	emitheader(); +	emitdefs(nts, ntnumber); +	emitstruct(nts, ntnumber); +	emitnts(rules, nrules); +	emitstring(rules); +	emitrule(nts); +	emitclosure(nts); +	if (start) +		emitlabel(terms, start, ntnumber); +	emitkids(rules, nrules); +	if (!feof(infp)) +		while ((c = getc(infp)) != EOF) +			putc(c, outfp); +	while (memlist) {	/* for purify */ +		struct block *q = memlist->link; +		free(memlist); +		memlist = q; +	} +	return errcnt > 0; +} + +/* alloc - allocate nbytes or issue fatal error */ +void *alloc(int nbytes) { +	struct block *p = calloc(1, sizeof *p + nbytes); + +	if (p == NULL) { +		yyerror("out of memory\n"); +		exit(1); +	} +	p->link = memlist; +	memlist = p; +	return p + 1; +} + +/* stringf - format and save a string */ +static char *stringf(char *fmt, ...) { +	va_list ap; +	char buf[512]; + +	va_start(ap, fmt); +	vsprintf(buf, fmt, ap); +	va_end(ap); +	return strcpy(alloc(strlen(buf) + 1), buf); +}	 + +struct entry { +	union { +		char *name; +		struct term t; +		struct nonterm nt; +	} sym; +	struct entry *link; +} *table[211]; +#define HASHSIZE (sizeof table/sizeof table[0]) + +/* hash - return hash number for str */ +static unsigned hash(char *str) { +	unsigned h = 0; + +	while (*str) +		h = (h<<1) + *str++; +	return h; +} + +/* lookup - lookup symbol name */ +static void *lookup(char *name) { +	struct entry *p = table[hash(name)%HASHSIZE]; + +	for ( ; p; p = p->link) +		if (strcmp(name, p->sym.name) == 0) +			return &p->sym; +	return 0; +} + +/* install - install symbol name */ +static void *install(char *name) { +	struct entry *p = alloc(sizeof *p); +	int i = hash(name)%HASHSIZE; + +	p->sym.name = name; +	p->link = table[i]; +	table[i] = p; +	return &p->sym; +} + +/* nonterm - create a new terminal id, if necessary */ +Nonterm nonterm(char *id) { +	Nonterm p = lookup(id), *q = &nts; + +	if (p && p->kind == NONTERM) +		return p; +	if (p && p->kind == TERM) +		yyerror("`%s' is a terminal\n", id); +	p = install(id); +	p->kind = NONTERM; +	p->number = ++ntnumber; +	if (p->number == 1) +		start = p; +	while (*q && (*q)->number < p->number) +		q = &(*q)->link; +	assert(*q == 0 || (*q)->number != p->number); +	p->link = *q; +	*q = p; +	return p; +} + +/* term - create a new terminal id with external symbol number esn */ +Term term(char *id, int esn) { +	Term p = lookup(id), *q = &terms; + +	if (p) +		yyerror("redefinition of terminal `%s'\n", id); +	else +		p = install(id); +	p->kind = TERM; +	p->esn = esn; +	p->arity = -1; +	while (*q && (*q)->esn < p->esn) +		q = &(*q)->link; +	if (*q && (*q)->esn == p->esn) +		yyerror("duplicate external symbol number `%s=%d'\n", +			p->name, p->esn); +	p->link = *q; +	*q = p; +	return p; +} + +/* tree - create & initialize a tree node with the given fields */ +Tree tree(char *id, Tree left, Tree right) { +	Tree t = alloc(sizeof *t); +	Term p = lookup(id); +	int arity = 0; + +	if (left && right) +		arity = 2; +	else if (left) +		arity = 1; +	if (p == NULL && arity > 0) { +		yyerror("undefined terminal `%s'\n", id); +		p = term(id, -1); +	} else if (p == NULL && arity == 0) +		p = (Term)nonterm(id); +	else if (p && p->kind == NONTERM && arity > 0) { +		yyerror("`%s' is a nonterminal\n", id); +		p = term(id, -1); +	} +	if (p->kind == TERM && p->arity == -1) +		p->arity = arity; +	if (p->kind == TERM && arity != p->arity) +		yyerror("inconsistent arity for terminal `%s'\n", id); +	t->op = p; +	t->nterms = p->kind == TERM; +	if ((t->left = left) != NULL) +		t->nterms += left->nterms; +	if ((t->right = right) != NULL) +		t->nterms += right->nterms; +	return t; +} + +/* rule - create & initialize a rule with the given fields */ +Rule rule(char *id, Tree pattern, char *template, char *code) { +	Rule r = alloc(sizeof *r), *q; +	Term p = pattern->op; +	char *end; + +	r->lhs = nonterm(id); +	r->packed = ++r->lhs->lhscount; +	for (q = &r->lhs->rules; *q; q = &(*q)->decode) +		; +	*q = r; +	r->pattern = pattern; +	r->ern = ++nrules; +	r->template = template; +	r->code = code; +	r->cost = strtol(code, &end, 10); +	if (*end) { +		r->cost = -1; +		r->code = stringf("(%s)", code); +	} +	if (p->kind == TERM) { +		for (q = &p->rules; *q; q = &(*q)->next) +			; +		*q = r; +	} else if (pattern->left == NULL && pattern->right == NULL) { +		Nonterm p = pattern->op; +		r->chain = p->chain; +	        p->chain = r; +		if (r->cost == -1) +			yyerror("illegal nonconstant cost `%s'\n", code); +	} +	for (q = &rules; *q; q = &(*q)->link) +		; +	r->link = *q; +	*q = r; +	return r; +} + +/* print - formatted output */ +static void print(char *fmt, ...) { +	va_list ap; + +	va_start(ap, fmt); +	for ( ; *fmt; fmt++) +		if (*fmt == '%') +			switch (*++fmt) { +			case 'd': fprintf(outfp, "%d", va_arg(ap, int)); break; +			case 's': fputs(va_arg(ap, char *), outfp); break; +			case 'P': fprintf(outfp, "%s_", prefix); break; +			case 'T': { +				Tree t = va_arg(ap, Tree); +				print("%S", t->op); +				if (t->left && t->right) +					print("(%T,%T)", t->left, t->right); +				else if (t->left) +					print("(%T)", t->left); +				break; +				} +			case 'R': { +				Rule r = va_arg(ap, Rule); +				print("%S: %T", r->lhs, r->pattern); +				break; +				} +			case 'S': fputs(va_arg(ap, Term)->name, outfp); break; +			case '1': case '2': case '3': case '4': case '5': { +				int n = *fmt - '0'; +				while (n-- > 0) +					putc('\t', outfp); +				break; +				} +			default: putc(*fmt, outfp); break;			 +			} +		else +			putc(*fmt, outfp); +	va_end(ap); +} + +/* reach - mark all nonterminals in tree t as reachable */ +static void reach(Tree t) { +	Nonterm p = t->op; + +	if (p->kind == NONTERM) +		if (!p->reached) +			ckreach(p); +	if (t->left) +		reach(t->left); +	if (t->right) +		reach(t->right); +} + +/* ckreach - mark all nonterminals reachable from p */ +static void ckreach(Nonterm p) { +	Rule r; + +        p->reached = 1; +	for (r = p->rules; r; r = r->decode) +		reach(r->pattern); +} + +/* emitcase - emit one case in function state */ +static void emitcase(Term p, int ntnumber) { +	Rule r; + +	print("%1case %d: /* %S */\n", p->esn, p); +	switch (p->arity) { +	case 0: case -1: +		break; +	case 1: +		print("%2%Plabel(LEFT_CHILD(a));\n"); +		break; +	case 2: +		print("%2%Plabel(LEFT_CHILD(a));\n"); +		print("%2%Plabel(RIGHT_CHILD(a));\n"); +		break; +	default: assert(0); +	} +	for (r = p->rules; r; r = r->next) { +		char *indent = "\t\t\0"; +		switch (p->arity) { +		case 0: case -1: +			print("%2/* %R */\n", r); +			if (r->cost == -1) { +				print("%2c = %s;\n", r->code); +				emitrecord("\t\t", r, "c", 0); +			} else +				emitrecord("\t\t", r, r->code, 0); +			break; +		case 1: +			if (r->pattern->nterms > 1) { +				print("%2if (%1/* %R */\n", r); +				emittest(r->pattern->left, "LEFT_CHILD(a)", " "); +				print("%2) {\n"); +				indent = "\t\t\t"; +			} else +				print("%2/* %R */\n", r); +			if (r->pattern->nterms == 2 && r->pattern->left +			&&  r->pattern->right == NULL) +				emitrecalc(indent, r->pattern->op, r->pattern->left->op); +			print("%sc = ", indent); +			emitcost(r->pattern->left, "LEFT_CHILD(a)"); +			print("%s;\n", r->code); +			emitrecord(indent, r, "c", 0); +			if (indent[2]) +				print("%2}\n"); +			break; +		case 2: +			if (r->pattern->nterms > 1) { +				print("%2if (%1/* %R */\n", r); +				emittest(r->pattern->left,  "LEFT_CHILD(a)", +					r->pattern->right->nterms ? " && " : " "); +				emittest(r->pattern->right, "RIGHT_CHILD(a)", " "); +				print("%2) {\n"); +				indent = "\t\t\t"; +			} else +				print("%2/* %R */\n", r); +			print("%sc = ", indent); +			emitcost(r->pattern->left,  "LEFT_CHILD(a)"); +			emitcost(r->pattern->right, "RIGHT_CHILD(a)"); +			print("%s;\n", r->code); +			emitrecord(indent, r, "c", 0); +			if (indent[2]) +				print("%2}\n"); +			break; +		default: assert(0); +		} +	} +	print("%2break;\n"); +} + +/* emitclosure - emit the closure functions */ +static void emitclosure(Nonterm nts) { +	Nonterm p; + +	for (p = nts; p; p = p->link) +		if (p->chain) +			print("static void %Pclosure_%S(NODEPTR_TYPE, int);\n", p); +	print("\n"); +	for (p = nts; p; p = p->link) +		if (p->chain) { +			Rule r; +			print("static void %Pclosure_%S(NODEPTR_TYPE a, int c) {\n" +"%1struct %Pstate *p = STATE_LABEL(a);\n", p); +			for (r = p->chain; r; r = r->chain) +				emitrecord("\t", r, "c", r->cost); +			print("}\n\n"); +		} +} + +/* emitcost - emit cost computation for tree t */ +static void emitcost(Tree t, char *v) { +	Nonterm p = t->op; + +	if (p->kind == TERM) { +		if (t->left) +			emitcost(t->left,  stringf("LEFT_CHILD(%s)",  v)); +		if (t->right) +			emitcost(t->right, stringf("RIGHT_CHILD(%s)", v)); +	} else +		print("((struct %Pstate *)(%s->x.state))->cost[%P%S_NT] + ", v, p); +} + +/* emitdefs - emit nonterminal defines and data structures */ +static void emitdefs(Nonterm nts, int ntnumber) { +	Nonterm p; + +	for (p = nts; p; p = p->link) +		print("#define %P%S_NT %d\n", p, p->number); +	print("\n"); +	print("static char *%Pntname[] = {\n%10,\n"); +	for (p = nts; p; p = p->link) +		print("%1\"%S\",\n", p); +	print("%10\n};\n\n"); +} + +/* emitheader - emit initial definitions */ +static void emitheader(void) { +	time_t timer = time(NULL); + +	print("/*\ngenerated at %sby %s\n*/\n", ctime(&timer), rcsid); +	print("static void %Pkids(NODEPTR_TYPE, int, NODEPTR_TYPE[]);\n"); +	print("static void %Plabel(NODEPTR_TYPE);\n"); +	print("static int %Prule(void*, int);\n\n"); +} + +/* computekids - compute paths to kids in tree t */ +static char *computekids(Tree t, char *v, char *bp, int *ip) { +	Term p = t->op; + +	if (p->kind == NONTERM) { +		sprintf(bp, "\t\tkids[%d] = %s;\n", (*ip)++, v); +		bp += strlen(bp); +	} else if (p->arity > 0) { +		bp = computekids(t->left, stringf("LEFT_CHILD(%s)", v), bp, ip); +		if (p->arity == 2) +			bp = computekids(t->right, stringf("RIGHT_CHILD(%s)", v), bp, ip); +	} +	return bp; +} + +/* emitkids - emit _kids */ +static void emitkids(Rule rules, int nrules) { +	int i; +	Rule r, *rc = alloc((nrules + 1 + 1)*sizeof *rc); +	char **str  = alloc((nrules + 1 + 1)*sizeof *str); + +	for (i = 0, r = rules; r; r = r->link) { +		int j = 0; +		char buf[1024], *bp = buf; +		*computekids(r->pattern, "p", bp, &j) = 0; +		for (j = 0; str[j] && strcmp(str[j], buf); j++) +			; +		if (str[j] == NULL) +			str[j] = strcpy(alloc(strlen(buf) + 1), buf); +		r->kids = rc[j]; +		rc[j] = r; +	} +	print("static void %Pkids(NODEPTR_TYPE p, int eruleno, NODEPTR_TYPE kids[]) {\n" +"%1if (!p)\n%2fatal(\"%Pkids\", \"Null tree\\n\", 0);\n" +"%1if (!kids)\n%2fatal(\"%Pkids\", \"Null kids\\n\", 0);\n" +"%1switch (eruleno) {\n"); +	for (i = 0; (r = rc[i]) != NULL; i++) { +		for ( ; r; r = r->kids) +			print("%1case %d: /* %R */\n", r->ern, r); +		print("%s%2break;\n", str[i]); +	} +	print("%1default:\n%2fatal(\"%Pkids\", \"Bad rule number %%d\\n\", eruleno);\n%1}\n}\n\n"); +} + +/* emitlabel - emit label function */ +static void emitlabel(Term terms, Nonterm start, int ntnumber) { +	int i; +	Term p; + +	print("static void %Plabel(NODEPTR_TYPE a) {\n%1int c;\n" +"%1struct %Pstate *p;\n\n" +"%1if (!a)\n%2fatal(\"%Plabel\", \"Null tree\\n\", 0);\n"); +	print("%1STATE_LABEL(a) = p = allocate(sizeof *p, FUNC);\n" +"%1p->rule._stmt = 0;\n"); +	for (i = 1; i <= ntnumber; i++) +		print("%1p->cost[%d] =\n", i); +	print("%20x7fff;\n%1switch (OP_LABEL(a)) {\n"); +	for (p = terms; p; p = p->link) +		emitcase(p, ntnumber); +	print("%1default:\n" +"%2fatal(\"%Plabel\", \"Bad terminal %%d\\n\", OP_LABEL(a));\n%1}\n}\n\n"); +} + +/* computents - fill in bp with _nts vector for tree t */ +static char *computents(Tree t, char *bp) { +	if (t) { +		Nonterm p = t->op; +		if (p->kind == NONTERM) { +			sprintf(bp, "%s_%s_NT, ", prefix, p->name); +			bp += strlen(bp); +		} else +			bp = computents(t->right, computents(t->left,  bp)); +	} +	return bp; +} + +/* emitnts - emit _nts ragged array */ +static void emitnts(Rule rules, int nrules) { +	Rule r; +	int i, j, *nts = alloc((nrules + 1)*sizeof *nts); +	char **str = alloc((nrules + 1)*sizeof *str); + +	for (i = 0, r = rules; r; r = r->link) { +		char buf[1024]; +		*computents(r->pattern, buf) = 0; +		for (j = 0; str[j] && strcmp(str[j], buf); j++) +			; +		if (str[j] == NULL) { +			print("static short %Pnts_%d[] = { %s0 };\n", j, buf); +			str[j] = strcpy(alloc(strlen(buf) + 1), buf); +		} +		nts[i++] = j; +	} +	print("\nstatic short *%Pnts[] = {\n"); +	for (i = j = 0, r = rules; r; r = r->link) { +		for ( ; j < r->ern; j++) +			print("%10,%1/* %d */\n", j); +		print("%1%Pnts_%d,%1/* %d */\n", nts[i++], j++); +	} +	print("};\n\n"); +} + +/* emitrecalc - emit code that tests for recalculation of INDIR?(VREGP) */ +static void emitrecalc(char *pre, Term root, Term kid) { +	if (root->kind == TERM && strncmp(root->name, "INDIR", 5) == 0 +	&&   kid->kind == TERM &&  strcmp(kid->name,  "VREGP"   ) == 0) { +		Nonterm p; +		print("%sif (mayrecalc(a)) {\n", pre); +		print("%s%1struct %Pstate *q = a->syms[RX]->u.t.cse->x.state;\n", pre); +		for (p = nts; p; p = p->link) { +			print("%s%1if (q->cost[%P%S_NT] == 0) {\n", pre, p); +			print("%s%2p->cost[%P%S_NT] = 0;\n", pre, p); +			print("%s%2p->rule.%P%S = q->rule.%P%S;\n", pre, p, p); +			print("%s%1}\n", pre); +		} +		print("%s}\n", pre); +	} +} + +/* emitrecord - emit code that tests for a winning match of rule r */ +static void emitrecord(char *pre, Rule r, char *c, int cost) { +	if (Tflag) +		print("%s%Ptrace(a, %d, %s + %d, p->cost[%P%S_NT]);\n", +			pre, r->ern, c, cost, r->lhs); +	print("%sif (", pre); +	print("%s + %d < p->cost[%P%S_NT]) {\n" +"%s%1p->cost[%P%S_NT] = %s + %d;\n%s%1p->rule.%P%S = %d;\n", +		c, cost, r->lhs, pre, r->lhs, c, cost, pre, r->lhs, +		r->packed); +	if (r->lhs->chain) +		print("%s%1%Pclosure_%S(a, %s + %d);\n", pre, r->lhs, c, cost); +	print("%s}\n", pre); +} + +/* emitrule - emit decoding vectors and _rule */ +static void emitrule(Nonterm nts) { +	Nonterm p; + +	for (p = nts; p; p = p->link) { +		Rule r; +		print("static short %Pdecode_%S[] = {\n%10,\n", p); +		for (r = p->rules; r; r = r->decode) +			print("%1%d,\n", r->ern); +		print("};\n\n"); +	} +	print("static int %Prule(void *state, int goalnt) {\n" +"%1if (goalnt < 1 || goalnt > %d)\n%2fatal(\"%Prule\", \"Bad goal nonterminal %%d\\n\", goalnt);\n" +"%1if (!state)\n%2return 0;\n%1switch (goalnt) {\n", ntnumber); +	for (p = nts; p; p = p->link) +		print("%1case %P%S_NT:" +"%1return %Pdecode_%S[((struct %Pstate *)state)->rule.%P%S];\n", p, p, p); +	print("%1default:\n%2fatal(\"%Prule\", \"Bad goal nonterminal %%d\\n\", goalnt);\n%2return 0;\n%1}\n}\n\n"); +} + +/* emitstring - emit arrays of templates, instruction flags, and rules */ +static void emitstring(Rule rules) { +	Rule r; + +	print("static char *%Ptemplates[] = {\n"); +	print("/* 0 */%10,\n"); +	for (r = rules; r; r = r->link) +		print("/* %d */%1\"%s\",%1/* %R */\n", r->ern, r->template, r); +	print("};\n"); +	print("\nstatic char %Pisinstruction[] = {\n"); +	print("/* 0 */%10,\n"); +	for (r = rules; r; r = r->link) { +		int len = strlen(r->template); +		print("/* %d */%1%d,%1/* %s */\n", r->ern, +			len >= 2 && r->template[len-2] == '\\' && r->template[len-1] == 'n', +			r->template); +	} +	print("};\n"); +	print("\nstatic char *%Pstring[] = {\n"); +	print("/* 0 */%10,\n"); +	for (r = rules; r; r = r->link) +		print("/* %d */%1\"%R\",\n", r->ern, r); +	print("};\n\n"); +} + +/* emitstruct - emit the definition of the state structure */ +static void emitstruct(Nonterm nts, int ntnumber) { +	print("struct %Pstate {\n%1short cost[%d];\n%1struct {\n", ntnumber + 1); +	for ( ; nts; nts = nts->link) { +		int n = 1, m = nts->lhscount; +		while ((m >>= 1) != 0) +			n++;		 +		print("%2unsigned int %P%S:%d;\n", nts, n); +	} +	print("%1} rule;\n};\n\n"); +} + +/* emittest - emit clause for testing a match */ +static void emittest(Tree t, char *v, char *suffix) { +	Term p = t->op; + +	if (p->kind == TERM) { +		print("%3%s->op == %d%s/* %S */\n", v, p->esn, +			t->nterms > 1 ? " && " : suffix, p); +		if (t->left) +			emittest(t->left, stringf("LEFT_CHILD(%s)",  v), +				t->right && t->right->nterms ? " && " : suffix); +		if (t->right) +			emittest(t->right, stringf("RIGHT_CHILD(%s)", v), suffix); +	} +} diff --git a/src/tools/lcc/lburg/lburg.h b/src/tools/lcc/lburg/lburg.h new file mode 100644 index 0000000..b67e802 --- /dev/null +++ b/src/tools/lcc/lburg/lburg.h @@ -0,0 +1,65 @@ +#ifndef BURG_INCLUDED +#define BURG_INCLUDED + +/* iburg.c: */ +extern void *alloc(int nbytes); + +typedef enum { TERM=1, NONTERM } Kind; +typedef struct rule *Rule; +typedef struct term *Term; +struct term {		/* terminals: */ +	char *name;		/* terminal name */ +	Kind kind;		/* TERM */ +	int esn;		/* external symbol number */ +	int arity;		/* operator arity */ +	Term link;		/* next terminal in esn order */ +	Rule rules;		/* rules whose pattern starts with term */ +}; + +typedef struct nonterm *Nonterm; +struct nonterm {	/* nonterminals: */ +	char *name;		/* nonterminal name */ +	Kind kind;		/* NONTERM */ +	int number;		/* identifying number */ +	int lhscount;		/* # times nt appears in a rule lhs */ +	int reached;		/* 1 iff reached from start nonterminal */ +	Rule rules;		/* rules w/nonterminal on lhs */ +	Rule chain;		/* chain rules w/nonterminal on rhs */ +	Nonterm link;		/* next terminal in number order */ +}; +extern Nonterm nonterm(char *id); +extern Term term(char *id, int esn); + +typedef struct tree *Tree; +struct tree {		/* tree patterns: */ +	void *op;		/* a terminal or nonterminal */ +	Tree left, right;	/* operands */ +	int nterms;		/* number of terminal nodes in this tree */ +}; +extern Tree tree(char *op, Tree left, Tree right); + +struct rule {		/* rules: */ +	Nonterm lhs;		/* lefthand side nonterminal */ +	Tree pattern;		/* rule pattern */ +	int ern;		/* external rule number */ +	int packed;		/* packed external rule number */ +	int cost;		/* cost, if a constant */ +	char *code;		/* cost, if an expression */ +	char *template;		/* assembler template */ +	Rule link;		/* next rule in ern order */ +	Rule next;		/* next rule with same pattern root */ +	Rule chain;		/* next chain rule with same rhs */ +	Rule decode;		/* next rule with same lhs */ +	Rule kids;		/* next rule with same _kids pattern */ +}; +extern Rule rule(char *id, Tree pattern, char *template, char *code); + +/* gram.y: */ +void yyerror(char *fmt, ...); +int yyparse(void); +void yywarn(char *fmt, ...); +extern int errcnt; +extern FILE *infp; +extern FILE *outfp; + +#endif diff --git a/src/tools/lcc/src/alloc.c b/src/tools/lcc/src/alloc.c new file mode 100644 index 0000000..e0566df --- /dev/null +++ b/src/tools/lcc/src/alloc.c @@ -0,0 +1,94 @@ +#include "c.h" +struct block { +	struct block *next; +	char *limit; +	char *avail; +}; +union align { +	long l; +	char *p; +	double d; +	int (*f)(void); +}; +union header { +	struct block b; +	union align a; +}; +#ifdef PURIFY +union header *arena[3]; + +void *allocate(unsigned long n, unsigned a) { +	union header *new = malloc(sizeof *new + n); + +	assert(a < NELEMS(arena)); +	if (new == NULL) { +		error("insufficient memory\n"); +		exit(1); +	} +	new->b.next = (void *)arena[a]; +	arena[a] = new; +	return new + 1; +} + +void deallocate(unsigned a) { +	union header *p, *q; + +	assert(a < NELEMS(arena)); +	for (p = arena[a]; p; p = q) { +		q = (void *)p->b.next; +		free(p); +	} +	arena[a] = NULL; +} + +void *newarray(unsigned long m, unsigned long n, unsigned a) { +	return allocate(m*n, a); +} +#else +static struct block +	 first[] = {  { NULL },  { NULL },  { NULL } }, +	*arena[] = { &first[0], &first[1], &first[2] }; +static struct block *freeblocks; + +void *allocate(unsigned long n, unsigned a) { +	struct block *ap; + +	assert(a < NELEMS(arena)); +	assert(n > 0); +	ap = arena[a]; +	n = roundup(n, sizeof (union align)); +	while (n > ap->limit - ap->avail) { +		if ((ap->next = freeblocks) != NULL) { +			freeblocks = freeblocks->next; +			ap = ap->next; +		} else +			{ +				unsigned m = sizeof (union header) + n + roundup(10*1024, sizeof (union align)); +				ap->next = malloc(m); +				ap = ap->next; +				if (ap == NULL) { +					error("insufficient memory\n"); +					exit(1); +				} +				ap->limit = (char *)ap + m; +			} +		ap->avail = (char *)((union header *)ap + 1); +		ap->next = NULL; +		arena[a] = ap; + +	} +	ap->avail += n; +	return ap->avail - n; +} + +void *newarray(unsigned long m, unsigned long n, unsigned a) { +	return allocate(m*n, a); +} +void deallocate(unsigned a) { +	assert(a < NELEMS(arena)); +	arena[a]->next = freeblocks; +	freeblocks = first[a].next; +	first[a].next = NULL; +	arena[a] = &first[a]; +} +#endif diff --git a/src/tools/lcc/src/bind.c b/src/tools/lcc/src/bind.c new file mode 100644 index 0000000..bc7b983 --- /dev/null +++ b/src/tools/lcc/src/bind.c @@ -0,0 +1,8 @@ +#include "c.h" +extern Interface nullIR; +extern Interface bytecodeIR; +Binding bindings[] = { +	{ "null",          &nullIR }, +	{ "bytecode",      &bytecodeIR }, +	{ NULL,            NULL }, +}; diff --git a/src/tools/lcc/src/bytecode.c b/src/tools/lcc/src/bytecode.c new file mode 100644 index 0000000..b267d6f --- /dev/null +++ b/src/tools/lcc/src/bytecode.c @@ -0,0 +1,365 @@ +#include "c.h" +#define I(f) b_##f + + +static void I(segment)(int n) { +	static int cseg; + +	if (cseg != n) +		switch (cseg = n) { +		case CODE: print("code\n"); return; +		case DATA: print("data\n"); return; +		case BSS:  print("bss\n");  return; +		case LIT:  print("lit\n");  return; +		default: assert(0); +		} +} + +static void I(address)(Symbol q, Symbol p, long n) { +	q->x.name = stringf("%s%s%D", p->x.name, n > 0 ? "+" : "", n); +} + +static void I(defaddress)(Symbol p) { +	print("address %s\n", p->x.name); +} + +static void I(defconst)(int suffix, int size, Value v) { +	switch (suffix) { +	case I: +		if (size > sizeof (int)) +			print("byte %d %D\n", size, v.i); +		else +			print("byte %d %d\n", size, v.i); +		return; +	case U: +		if (size > sizeof (unsigned)) +			print("byte %d %U\n", size, v.u); +		else +			print("byte %d %u\n", size, v.u); +		return; +	case P: print("byte %d %U\n", size, (unsigned long)v.p); return; +	case F: +		if (size == 4) { +			float f = v.d; +			print("byte 4 %u\n", *(unsigned *)&f); +		} else { +			unsigned *p = (unsigned *)&v.d; +			print("byte 4 %u\n", p[swap]); +			print("byte 4 %u\n", p[1 - swap]); +		} +		return; +	} +	assert(0); +} + +static void I(defstring)(int len, char *str) { +	char *s; + +	for (s = str; s < str + len; s++) +		print("byte 1 %d\n", (*s)&0377); +} + +static void I(defsymbol)(Symbol p) { +	if (p->scope == CONSTANTS) +		switch (optype(ttob(p->type))) { +		case I: p->x.name = stringf("%D", p->u.c.v.i); break; +		case U: p->x.name = stringf("%U", p->u.c.v.u); break; +		case P: p->x.name = stringf("%U", p->u.c.v.p); break; +		case F: +			{	// JDC: added this to get inline floats +				unsigned temp; + +				*(float *)&temp = p->u.c.v.d; +				p->x.name = stringf("%U", temp ); +			} +			break;// JDC: added this +		default: assert(0); +		} +	else if (p->scope >= LOCAL && p->sclass == STATIC) +		p->x.name = stringf("$%d", genlabel(1)); +	else if (p->scope == LABELS || p->generated) +		p->x.name = stringf("$%s", p->name); +	else +		p->x.name = p->name; +} + +static void dumptree(Node p) { +	switch (specific(p->op)) { +	case ASGN+B: +		assert(p->kids[0]); +		assert(p->kids[1]); +		assert(p->syms[0]); +		dumptree(p->kids[0]); +		dumptree(p->kids[1]); +		print("%s %d\n", opname(p->op), p->syms[0]->u.c.v.u); +		return; +	case RET+V: +		assert(!p->kids[0]); +		assert(!p->kids[1]); +		print("%s\n", opname(p->op)); +		return; +	} +	switch (generic(p->op)) { +	case CNST: case ADDRG: case ADDRF: case ADDRL: case LABEL: +		assert(!p->kids[0]); +		assert(!p->kids[1]); +		assert(p->syms[0] && p->syms[0]->x.name); +		print("%s %s\n", opname(p->op), p->syms[0]->x.name); +		return; +	case CVF: case CVI: case CVP: case CVU: +		assert(p->kids[0]); +		assert(!p->kids[1]); +		assert(p->syms[0]); +		dumptree(p->kids[0]); +		print("%s %d\n", opname(p->op), p->syms[0]->u.c.v.i); +		return; +	case ARG: case BCOM: case NEG: case INDIR: case JUMP: case RET: +		assert(p->kids[0]); +		assert(!p->kids[1]); +		dumptree(p->kids[0]); +		print("%s\n", opname(p->op)); +		return; +	case CALL: +		assert(p->kids[0]); +		assert(!p->kids[1]); +		assert(optype(p->op) != B); +		dumptree(p->kids[0]); +		print("%s\n", opname(p->op)); +		if ( !p->count ) { printf("pop\n"); };	// JDC +		return; +	case ASGN: case BOR: case BAND: case BXOR: case RSH: case LSH: +	case ADD: case SUB: case DIV: case MUL: case MOD: +		assert(p->kids[0]); +		assert(p->kids[1]); +		dumptree(p->kids[0]); +		dumptree(p->kids[1]); +		print("%s\n", opname(p->op)); +		return; +	case EQ: case NE: case GT: case GE: case LE: case LT: +		assert(p->kids[0]); +		assert(p->kids[1]); +		assert(p->syms[0]); +		assert(p->syms[0]->x.name); +		dumptree(p->kids[0]); +		dumptree(p->kids[1]); +		print("%s %s\n", opname(p->op), p->syms[0]->x.name); +		return; +	} +	assert(0); +} + +static void I(emit)(Node p) { +	for (; p; p = p->link) +		dumptree(p); +} + +static void I(export)(Symbol p) { +	print("export %s\n", p->x.name); +} + +static void I(function)(Symbol f, Symbol caller[], Symbol callee[], int ncalls) { +	int i; + +	(*IR->segment)(CODE); +	offset = 0; +	for (i = 0; caller[i] && callee[i]; i++) { +		offset = roundup(offset, caller[i]->type->align); +		caller[i]->x.name = callee[i]->x.name = stringf("%d", offset); +		caller[i]->x.offset = callee[i]->x.offset = offset; +		offset += caller[i]->type->size; +	} +	maxargoffset = maxoffset = argoffset = offset = 0; +	gencode(caller, callee); +	print("proc %s %d %d\n", f->x.name, maxoffset, maxargoffset); +	emitcode(); +	print("endproc %s %d %d\n", f->x.name, maxoffset, maxargoffset); + +} + +static void gen02(Node p) { +	assert(p); +	if (generic(p->op) == ARG) { +		assert(p->syms[0]); +		argoffset += (p->syms[0]->u.c.v.i < 4 ? 4 : p->syms[0]->u.c.v.i); +	} else if (generic(p->op) == CALL) { +		maxargoffset = (argoffset > maxargoffset ? argoffset : maxargoffset); +		argoffset = 0; +	} +} + +static void gen01(Node p) { +	if (p) { +		gen01(p->kids[0]); +		gen01(p->kids[1]); +		gen02(p); +	} +} + +static Node I(gen)(Node p) { +	Node q; + +	assert(p); +	for (q = p; q; q = q->link) +		gen01(q); +	return p; +} + +static void I(global)(Symbol p) { +	print("align %d\n", p->type->align > 4 ? 4 : p->type->align); +	print("LABELV %s\n", p->x.name); +} + +static void I(import)(Symbol p) { +	print("import %s\n", p->x.name); +} + +static void I(local)(Symbol p) { +	offset = roundup(offset, p->type->align); +	p->x.name = stringf("%d", offset); +	p->x.offset = offset; +	offset += p->type->size; +} + +static void I(progbeg)(int argc, char *argv[]) {} + +static void I(progend)(void) {} + +static void I(space)(int n) { +	print("skip %d\n", n); +} + +//======================================================== + +// JDC: hacked up to get interleaved source lines in asm code +static char	*sourceFile; +static char *sourcePtr; +static int sourceLine; + +static int filelength( FILE *f ) { +	int		pos; +	int		end; + +	pos = ftell (f); +	fseek (f, 0, SEEK_END); +	end = ftell (f); +	fseek (f, pos, SEEK_SET); + +	return end; +} + +static void LoadSourceFile( const char *filename ) { +	FILE	*f; +	int		length; + +	f = fopen( filename, "r" ); +	if ( !f ) { +		print( ";couldn't open %s\n", filename ); +		sourceFile = NULL; +		return; +	} +	length = filelength( f ); +	sourceFile = malloc( length + 1 ); +	if ( sourceFile ) { +		fread( sourceFile, length, 1, f ); +		sourceFile[length] = 0; +	} + +	fclose( f ); +	sourceLine = 1; +	sourcePtr = sourceFile; +} + +static void PrintToSourceLine( int line ) { +	int		c; + +	if ( !sourceFile ) { +		return; +	} +	while ( sourceLine <= line ) { +		int		i; + +		for ( i = 0 ; sourcePtr[i] && sourcePtr[i] != '\n' ; i++ ) { +		} +		c = sourcePtr[i]; +		if ( c == '\n' ) { +			sourcePtr[i] = 0; +		} +		print( ";%d:%s\n", sourceLine, sourcePtr ); +		if ( c == 0 ) { +			sourcePtr += i;	// end of file +		} else { +			sourcePtr += i+1; +		} +		sourceLine++; +	} +} + +static void I(stabline)(Coordinate *cp) { +	static char *prevfile; +	static int prevline; + +	if (cp->file && (prevfile == NULL || strcmp(prevfile, cp->file) != 0)) { +		print("file \"%s\"\n", prevfile = cp->file); +		prevline = 0; +		if ( sourceFile ) { +			free( sourceFile ); +			sourceFile = NULL; +		} +		// load the new source file +		LoadSourceFile( cp->file ); +	} +	if (cp->y != prevline) { +		print("line %d\n", prevline = cp->y); +		PrintToSourceLine( cp->y ); +	} +} + +//======================================================== + +#define b_blockbeg blockbeg +#define b_blockend blockend + +Interface bytecodeIR = { +	{1, 1, 0},	/* char */ +	{2, 2, 0},	/* short */ +	{4, 4, 0},	/* int */ +	{4, 4, 0},	/* long */ +	{4, 4, 0},	/* long long */ +	{4, 4, 0},	/* float */				// JDC: use inline floats +	{4, 4, 0},	/* double */			// JDC: don't ever emit 8 byte double code +	{4, 4, 0},	/* long double */		// JDC: don't ever emit 8 byte double code +	{4, 4, 0},	/* T* */ +	{0, 4, 0},	/* struct */ +	0,		/* little_endian */ +	0,		/* mulops_calls */ +	0,		/* wants_callb */ +	0,		/* wants_argb */ +	1,		/* left_to_right */ +	0,		/* wants_dag */ +	0,		/* unsigned_char */ +	I(address), +	I(blockbeg), +	I(blockend), +	I(defaddress), +	I(defconst), +	I(defstring), +	I(defsymbol), +	I(emit), +	I(export), +	I(function), +	I(gen), +	I(global), +	I(import), +	I(local), +	I(progbeg), +	I(progend), +	I(segment), +	I(space), +	0,		/* I(stabblock) */ +	0,		/* I(stabend) */ +	0,		/* I(stabfend) */ +	0,		/* I(stabinit) */ +	I(stabline), +	0,		/* I(stabsym) */ +	0,		/* I(stabtype) */ +}; diff --git a/src/tools/lcc/src/c.h b/src/tools/lcc/src/c.h new file mode 100644 index 0000000..e36380e --- /dev/null +++ b/src/tools/lcc/src/c.h @@ -0,0 +1,723 @@ +#include <assert.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> +#include <string.h> + +#define NEW(p,a) ((p) = allocate(sizeof *(p), (a))) +#define NEW0(p,a) memset(NEW((p),(a)), 0, sizeof *(p)) +#define isaddrop(op) (specific(op)==ADDRG+P || specific(op)==ADDRL+P \ +	|| specific(op)==ADDRF+P) + +#define	MAXLINE  512 +#define	BUFSIZE 4096 + +#define istypename(t,tsym) (kind[t] == CHAR \ +	|| (t == ID && tsym && tsym->sclass == TYPEDEF)) +#define sizeop(n) ((n)<<10) +#define generic(op)  ((op)&0x3F0) +#define specific(op) ((op)&0x3FF) +#define opindex(op) (((op)>>4)&0x3F) +#define opkind(op)  ((op)&~0x3F0) +#define opsize(op)  ((op)>>10) +#define optype(op)  ((op)&0xF) +#ifdef __LCC__ +#ifndef __STDC__ +#define __STDC__ +#endif +#endif +#define NELEMS(a) ((int)(sizeof (a)/sizeof ((a)[0]))) +#undef roundup +#define roundup(x,n) (((x)+((n)-1))&(~((n)-1))) +#define mkop(op,ty) (specific((op) + ttob(ty))) + +#define extend(x,ty) ((x)&(1<<(8*(ty)->size-1)) ? (x)|((~0UL)<<(8*(ty)->size-1)) : (x)&ones(8*(ty)->size)) +#define ones(n) ((n)>=8*sizeof (unsigned long) ? ~0UL : ~((~0UL)<<(n))) + +#define isqual(t)     ((t)->op >= CONST) +#define unqual(t)     (isqual(t) ? (t)->type : (t)) + +#define isvolatile(t) ((t)->op == VOLATILE \ +                    || (t)->op == CONST+VOLATILE) +#define isconst(t)    ((t)->op == CONST \ +                    || (t)->op == CONST+VOLATILE) +#define isarray(t)    (unqual(t)->op == ARRAY) +#define isstruct(t)   (unqual(t)->op == STRUCT \ +                    || unqual(t)->op == UNION) +#define isunion(t)    (unqual(t)->op == UNION) +#define isfunc(t)     (unqual(t)->op == FUNCTION) +#define isptr(t)      (unqual(t)->op == POINTER) +#define ischar(t)     ((t)->size == 1 && isint(t)) +#define isint(t)      (unqual(t)->op == INT \ +                    || unqual(t)->op == UNSIGNED) +#define isfloat(t)    (unqual(t)->op == FLOAT) +#define isarith(t)    (unqual(t)->op <= UNSIGNED) +#define isunsigned(t) (unqual(t)->op == UNSIGNED) +#define isscalar(t)   (unqual(t)->op <= POINTER \ +                    || unqual(t)->op == ENUM) +#define isenum(t)     (unqual(t)->op == ENUM) +#define fieldsize(p)  (p)->bitsize +#define fieldright(p) ((p)->lsb - 1) +#define fieldleft(p)  (8*(p)->type->size - \ +                        fieldsize(p) - fieldright(p)) +#define fieldmask(p)  (~(~(unsigned)0<<fieldsize(p))) +typedef struct node *Node; + +typedef struct list *List; + +typedef struct code *Code; + +typedef struct swtch *Swtch; + +typedef struct symbol *Symbol; + +typedef struct coord { +	char *file; +	unsigned x, y; +} Coordinate; +typedef struct table *Table; + +typedef union value { +	long i; +	unsigned long u; +	double d; +	void *p; +	void (*g)(void); +} Value; +typedef struct tree *Tree; + +typedef struct type *Type; + +typedef struct field *Field; + +typedef struct { +	unsigned printed:1; +	unsigned marked; +	unsigned short typeno; +	void *xt; +} Xtype; + +#include "config.h" +typedef struct metrics { +	unsigned char size, align, outofline; +} Metrics; +typedef struct interface { +	Metrics charmetric; +	Metrics shortmetric; +	Metrics intmetric; +	Metrics longmetric; +	Metrics longlongmetric; +	Metrics floatmetric; +	Metrics doublemetric; +	Metrics longdoublemetric; +	Metrics ptrmetric; +	Metrics structmetric; +	unsigned little_endian:1; +	unsigned mulops_calls:1; +	unsigned wants_callb:1; +	unsigned wants_argb:1; +	unsigned left_to_right:1; +	unsigned wants_dag:1; +	unsigned unsigned_char:1; +void (*address)(Symbol p, Symbol q, long n); +void (*blockbeg)(Env *); +void (*blockend)(Env *); +void (*defaddress)(Symbol); +void (*defconst)  (int suffix, int size, Value v); +void (*defstring)(int n, char *s); +void (*defsymbol)(Symbol); +void (*emit)    (Node); +void (*export)(Symbol); +void (*function)(Symbol, Symbol[], Symbol[], int); +Node (*gen)     (Node); +void (*global)(Symbol); +void (*import)(Symbol); +void (*local)(Symbol); +void (*progbeg)(int argc, char *argv[]); +void (*progend)(void); +void (*segment)(int); +void (*space)(int); +void (*stabblock)(int, int, Symbol*); +void (*stabend)  (Coordinate *, Symbol, Coordinate **, Symbol *, Symbol *); +void (*stabfend) (Symbol, int); +void (*stabinit) (char *, int, char *[]); +void (*stabline) (Coordinate *); +void (*stabsym)  (Symbol); +void (*stabtype) (Symbol); +	Xinterface x; +} Interface; +typedef struct binding { +	char *name; +	Interface *ir; +} Binding; + +extern Binding bindings[]; +extern Interface *IR; +typedef struct { +	List blockentry; +	List blockexit; +	List entry; +	List exit; +	List returns; +	List points; +	List calls; +	List end; +} Events; + +enum { +#define xx(a,b,c,d,e,f,g) a=b, +#define yy(a,b,c,d,e,f,g) +#include "token.h" +	LAST +}; +struct node { +	short op; +	short count; + 	Symbol syms[3]; +	Node kids[2]; +	Node link; +	Xnode x; +}; +enum { +	F=FLOAT, +	I=INT, +	U=UNSIGNED, +	P=POINTER, +	V=VOID, +	B=STRUCT +}; +#define gop(name,value) name=value<<4, +#define op(name,type,sizes) + +enum { gop(CNST,1) +       	op(CNST,F,fdx) +       	op(CNST,I,csilh) +       	op(CNST,P,p) +       	op(CNST,U,csilh) +       gop(ARG,2) +       	op(ARG,B,-) +       	op(ARG,F,fdx) +       	op(ARG,I,ilh) +       	op(ARG,P,p) +       	op(ARG,U,ilh) +       gop(ASGN,3) +       	op(ASGN,B,-) +       	op(ASGN,F,fdx) +       	op(ASGN,I,csilh) +       	op(ASGN,P,p) +       	op(ASGN,U,csilh) +       gop(INDIR,4) +       	op(INDIR,B,-) +       	op(INDIR,F,fdx) +       	op(INDIR,I,csilh) +       	op(INDIR,P,p) +       	op(INDIR,U,csilh) +       gop(CVF,7) +       	op(CVF,F,fdx) +       	op(CVF,I,ilh) +       gop(CVI,8) +       	op(CVI,F,fdx) +       	op(CVI,I,csilh) +       	op(CVI,U,csilhp) +       gop(CVP,9) +       	op(CVP,U,p) +       gop(CVU,11) +       	op(CVU,I,csilh) +       	op(CVU,P,p) +       	op(CVU,U,csilh) +       gop(NEG,12) +       	op(NEG,F,fdx) +       	op(NEG,I,ilh) +       gop(CALL,13) +       	op(CALL,B,-) +       	op(CALL,F,fdx) +       	op(CALL,I,ilh) +       	op(CALL,P,p) +       	op(CALL,U,ilh) +       	op(CALL,V,-) +       gop(RET,15) +       	op(RET,F,fdx) +       	op(RET,I,ilh) +       	op(RET,P,p) +       	op(RET,U,ilh) +       	op(RET,V,-) +       gop(ADDRG,16) +       	op(ADDRG,P,p) +       gop(ADDRF,17) +       	op(ADDRF,P,p) +       gop(ADDRL,18) +       	op(ADDRL,P,p) +       gop(ADD,19) +       	op(ADD,F,fdx) +       	op(ADD,I,ilh) +       	op(ADD,P,p) +       	op(ADD,U,ilhp) +       gop(SUB,20) +       	op(SUB,F,fdx) +       	op(SUB,I,ilh) +       	op(SUB,P,p) +       	op(SUB,U,ilhp) +       gop(LSH,21) +       	op(LSH,I,ilh) +       	op(LSH,U,ilh) +       gop(MOD,22) +       	op(MOD,I,ilh) +       	op(MOD,U,ilh) +       gop(RSH,23) +       	op(RSH,I,ilh) +       	op(RSH,U,ilh) +       gop(BAND,24) +       	op(BAND,I,ilh) +       	op(BAND,U,ilh) +       gop(BCOM,25) +       	op(BCOM,I,ilh) +       	op(BCOM,U,ilh) +       gop(BOR,26) +       	op(BOR,I,ilh) +       	op(BOR,U,ilh) +       gop(BXOR,27) +       	op(BXOR,I,ilh) +       	op(BXOR,U,ilh) +       gop(DIV,28) +       	op(DIV,F,fdx) +       	op(DIV,I,ilh) +       	op(DIV,U,ilh) +       gop(MUL,29) +       	op(MUL,F,fdx) +       	op(MUL,I,ilh) +       	op(MUL,U,ilh) +       gop(EQ,30) +       	op(EQ,F,fdx) +       	op(EQ,I,ilh) +       	op(EQ,U,ilhp) +       gop(GE,31) +       	op(GE,F,fdx) +       	op(GE,I,ilh) +       	op(GE,U,ilhp) +       gop(GT,32) +       	op(GT,F,fdx) +       	op(GT,I,ilh) +       	op(GT,U,ilhp) +       gop(LE,33) +       	op(LE,F,fdx) +       	op(LE,I,ilh) +       	op(LE,U,ilhp) +       gop(LT,34) +       	op(LT,F,fdx) +       	op(LT,I,ilh) +       	op(LT,U,ilhp) +       gop(NE,35) +       	op(NE,F,fdx) +       	op(NE,I,ilh) +       	op(NE,U,ilhp) +       gop(JUMP,36) +       	op(JUMP,V,-) +       gop(LABEL,37) +       	op(LABEL,V,-) +       gop(LOAD,14) +       	op(LOAD,B,-) +       	op(LOAD,F,fdx) +       	op(LOAD,I,csilh) +       	op(LOAD,P,p) +       	op(LOAD,U,csilhp) LASTOP }; + +#undef gop +#undef op +enum { CODE=1, BSS, DATA, LIT }; +enum { PERM=0, FUNC, STMT }; +struct list { +	void *x; +	List link; +}; + +struct code { +	enum { Blockbeg, Blockend, Local, Address, Defpoint, +	       Label,    Start,    Gen,   Jump,    Switch +	} kind; +	Code prev, next; +	union { +		struct { +			int level; +			Symbol *locals; +			Table identifiers, types; +			Env x; +		} block; +		Code begin; +		Symbol var; + +		struct { +			Symbol sym; +			Symbol base; +			long offset; +		} addr; +		struct { +			Coordinate src; +			int point; +		} point;  +		Node forest; +		struct { +			Symbol sym; +			Symbol table; +			Symbol deflab; +			int size; +			long *values; +			Symbol *labels; +		} swtch; + +	} u; +}; +struct swtch { +	Symbol sym; +	int lab; +	Symbol deflab; +	int ncases; +	int size; +	long *values; +	Symbol *labels; +}; +struct symbol { +	char *name; +	int scope; +	Coordinate src; +	Symbol up; +	List uses; +	int sclass; +	unsigned structarg:1; + +	unsigned addressed:1; +	unsigned computed:1; +	unsigned temporary:1; +	unsigned generated:1; +	unsigned defined:1; +	Type type; +	float ref; +	union { +		struct { +			int label; +			Symbol equatedto; +		} l; +		struct { +			unsigned cfields:1; +			unsigned vfields:1; +			Table ftab;		/* omit */ +			Field flist; +		} s; +		int value; +		Symbol *idlist; +		struct { +			Value min, max; +		} limits; +		struct { +			Value v; +			Symbol loc; +		} c; +		struct { +			Coordinate pt; +			int label; +			int ncalls; +			Symbol *callee; +		} f; +		int seg; +		Symbol alias; +		struct { +			Node cse; +			int replace; +			Symbol next; +		} t; +	} u; +	Xsymbol x; +}; +enum { CONSTANTS=1, LABELS, GLOBAL, PARAM, LOCAL }; +struct tree { +	int op; +	Type type; +	Tree kids[2]; +	Node node; +	union { +		Value v; +		Symbol sym; + +		Field field; +	} u; +}; +enum { +	AND=38<<4, +	NOT=39<<4, +	OR=40<<4, +	COND=41<<4, +	RIGHT=42<<4, +	FIELD=43<<4 +}; +struct type { +	int op; +	Type type; +	int align; +	int size; +	union { +		Symbol sym; +		struct { +			unsigned oldstyle:1; +			Type *proto; +		} f; +	} u; +	Xtype x; +}; +struct field { +	char *name; +	Type type; +	int offset; +	short bitsize; +	short lsb; +	Field link; +}; +extern int assignargs; +extern int prunetemps; +extern int nodecount; +extern Symbol cfunc; +extern Symbol retv; +extern Tree (*optree[])(int, Tree, Tree); + +extern char kind[]; +extern int errcnt; +extern int errlimit; +extern int wflag; +extern Events events; +extern float refinc; + +extern unsigned char *cp; +extern unsigned char *limit; +extern char *firstfile; +extern char *file; +extern char *line; +extern int lineno; +extern int t; +extern char *token; +extern Symbol tsym; +extern Coordinate src; +extern int Aflag; +extern int Pflag; +extern Symbol YYnull; +extern Symbol YYcheck; +extern int glevel; +extern int xref; + +extern int ncalled; +extern int npoints; + +extern int needconst; +extern int explicitCast; +extern struct code codehead; +extern Code codelist; +extern Table stmtlabs; +extern float density; +extern Table constants; +extern Table externals; +extern Table globals; +extern Table identifiers; +extern Table labels; +extern Table types; +extern int level; + +extern List loci, symbols; + +extern List symbols; + +extern int where; +extern Type chartype; +extern Type doubletype; +extern Type floattype; +extern Type inttype; +extern Type longdouble; +extern Type longtype; +extern Type longlong; +extern Type shorttype; +extern Type signedchar; +extern Type unsignedchar; +extern Type unsignedlonglong; +extern Type unsignedlong; +extern Type unsignedshort; +extern Type unsignedtype; +extern Type charptype; +extern Type funcptype; +extern Type voidptype; +extern Type voidtype; +extern Type unsignedptr; +extern Type signedptr; +extern Type widechar; +extern void  *allocate(unsigned long n, unsigned a); +extern void deallocate(unsigned a); +extern void *newarray(unsigned long m, unsigned long n, unsigned a); +extern void walk(Tree e, int tlab, int flab); +extern Node listnodes(Tree e, int tlab, int flab); +extern Node newnode(int op, Node left, Node right, Symbol p); +extern Tree cvtconst(Tree); +extern void printdag(Node, int); +extern void compound(int, Swtch, int); +extern void defglobal(Symbol, int); +extern void finalize(void); +extern void program(void); + +extern Tree vcall(Symbol func, Type ty, ...); +extern Tree addrof(Tree); +extern Tree asgn(Symbol, Tree); +extern Tree asgntree(int, Tree, Tree); +extern Type assign(Type, Tree); +extern Tree bittree(int, Tree, Tree); +extern Tree call(Tree, Type, Coordinate); +extern Tree calltree(Tree, Type, Tree, Symbol); +extern Tree condtree(Tree, Tree, Tree); +extern Tree cnsttree(Type, ...); +extern Tree consttree(unsigned int, Type); +extern Tree eqtree(int, Tree, Tree); +extern int iscallb(Tree); +extern Tree shtree(int, Tree, Tree); +extern void typeerror(int, Tree, Tree); + +extern void test(int tok, char set[]); +extern void expect(int tok); +extern void skipto(int tok, char set[]); +extern void error(const char *, ...); +extern int fatal(const char *, const char *, int); +extern void warning(const char *, ...); + +typedef void (*Apply)(void *, void *, void *); +extern void attach(Apply, void *, List *); +extern void apply(List event, void *arg1, void *arg2); +extern Tree retype(Tree p, Type ty); +extern Tree rightkid(Tree p); +extern int hascall(Tree p); +extern Type binary(Type, Type); +extern Tree cast(Tree, Type); +extern Tree cond(Tree); +extern Tree expr0(int); +extern Tree expr(int); +extern Tree expr1(int); +extern Tree field(Tree, const char *); +extern char *funcname(Tree); +extern Tree idtree(Symbol); +extern Tree incr(int, Tree, Tree); +extern Tree lvalue(Tree); +extern Tree nullcall(Type, Symbol, Tree, Tree); +extern Tree pointer(Tree); +extern Tree rvalue(Tree); +extern Tree value(Tree); + +extern void defpointer(Symbol); +extern Type initializer(Type, int); +extern void swtoseg(int); + +extern void input_init(int, char *[]); +extern void fillbuf(void); +extern void nextline(void); + +extern int getchr(void); +extern int gettok(void); + +extern void emitcode(void); +extern void gencode (Symbol[], Symbol[]); +extern void fprint(FILE *f, const char *fmt, ...); +extern char *stringf(const char *, ...); +extern void check(Node); +extern void print(const char *, ...); + +extern List append(void *x, List list); +extern int  length(List list); +extern void *ltov (List *list, unsigned a); +extern void init(int, char *[]); + +extern Type typename(void); +extern void checklab(Symbol p, void *cl); +extern Type enumdcl(void); +extern void main_init(int, char *[]); +extern int main(int, char *[]); + +extern void vfprint(FILE *, char *, const char *, va_list); + +extern int process(char *); +extern int findfunc(char *, char *); +extern int findcount(char *, int, int); + +extern Tree constexpr(int); +extern int intexpr(int, int); +extern Tree simplify(int, Type, Tree, Tree); +extern int ispow2(unsigned long u); + +extern int reachable(int); + +extern void addlocal(Symbol); +extern void branch(int); +extern Code code(int); +extern void definelab(int); +extern void definept(Coordinate *); +extern void equatelab(Symbol, Symbol); +extern Node jump(int); +extern void retcode(Tree); +extern void statement(int, Swtch, int); +extern void swcode(Swtch, int *, int, int); +extern void swgen(Swtch); + +extern char * string(const char *str); +extern char *stringn(const char *str, int len); +extern char *stringd(long n); +extern Symbol relocate(const char *name, Table src, Table dst); +extern void use(Symbol p, Coordinate src); +extern void locus(Table tp, Coordinate *cp); +extern Symbol allsymbols(Table); + +extern Symbol constant(Type, Value); +extern void enterscope(void); +extern void exitscope(void); +extern Symbol findlabel(int); +extern Symbol findtype(Type); +extern void foreach(Table, int, void (*)(Symbol, void *), void *); +extern Symbol genident(int, Type, int); +extern int genlabel(int); +extern Symbol install(const char *, Table *, int, int); +extern Symbol intconst(int); +extern Symbol lookup(const char *, Table); +extern Symbol mkstr(char *); +extern Symbol mksymbol(int, const char *, Type); +extern Symbol newtemp(int, int, int); +extern Table table(Table, int); +extern Symbol temporary(int, Type); +extern char *vtoa(Type, Value); + +extern int nodeid(Tree); +extern char *opname(int); +extern int *printed(int); +extern void printtree(Tree, int); +extern Tree root(Tree); +extern Tree texpr(Tree (*)(int), int, int); +extern Tree tree(int, Type, Tree, Tree); + +extern void type_init(int, char *[]); + +extern Type signedint(Type); + +extern int hasproto(Type); +extern void outtype(Type, FILE *); +extern void printdecl (Symbol p, Type ty); +extern void printproto(Symbol p, Symbol args[]); +extern char *typestring(Type ty, char *id); +extern Field fieldref(const char *name, Type ty); +extern Type array(Type, int, int); +extern Type atop(Type); +extern Type btot(int, int); +extern Type compose(Type, Type); +extern Type deref(Type); +extern int eqtype(Type, Type, int); +extern Field fieldlist(Type); +extern Type freturn(Type); +extern Type ftype(Type, Type); +extern Type func(Type, Type *, int); +extern Field newfield(char *, Type, Type); +extern Type newstruct(int, char *); +extern void printtype(Type, int); +extern Type promote(Type); +extern Type ptr(Type); +extern Type qual(int, Type); +extern void rmtypes(int); +extern int ttob(Type); +extern int variadic(Type); + diff --git a/src/tools/lcc/src/config.h b/src/tools/lcc/src/config.h new file mode 100644 index 0000000..6f0d5a6 --- /dev/null +++ b/src/tools/lcc/src/config.h @@ -0,0 +1,102 @@ +typedef struct { +	unsigned char max_unaligned_load; +	Symbol (*rmap)(int); + +	void (*blkfetch)(int size, int off, int reg, int tmp); +	void (*blkstore)(int size, int off, int reg, int tmp); +	void (*blkloop)(int dreg, int doff, +	                 int sreg, int soff, +	                 int size, int tmps[]); +	void (*_label)(Node); +	int (*_rule)(void*, int); +	short **_nts; +	void (*_kids)(Node, int, Node*); +	char **_string; +	char **_templates; +	char *_isinstruction; +	char **_ntname; +	void (*emit2)(Node); +	void (*doarg)(Node); +	void (*target)(Node); +	void (*clobber)(Node); +} Xinterface; +extern int     askregvar(Symbol, Symbol); +extern void    blkcopy(int, int, int, int, int, int[]); +extern int     getregnum(Node); +extern int     mayrecalc(Node); +extern int     mkactual(int, int); +extern void    mkauto(Symbol); +extern Symbol  mkreg(char *, int, int, int); +extern Symbol  mkwildcard(Symbol *); +extern int     move(Node); +extern int     notarget(Node); +extern void    parseflags(int, char **); +extern int     range(Node, int, int); +extern unsigned regloc(Symbol);  /* omit */ +extern void    rtarget(Node, int, Symbol); +extern void    setreg(Node, Symbol); +extern void    spill(unsigned, int, Node); +extern int     widens(Node); + +extern int      argoffset, maxargoffset; +extern int      bflag, dflag; +extern int      dalign, salign; +extern int      framesize; +extern unsigned freemask[], usedmask[]; +extern int      offset, maxoffset; +extern int      swap; +extern unsigned tmask[], vmask[]; +typedef struct { +	unsigned listed:1; +	unsigned registered:1; +	unsigned emitted:1; +	unsigned copy:1; +	unsigned equatable:1; +	unsigned spills:1; +	unsigned mayrecalc:1; +	void *state; +	short inst; +	Node kids[3]; +	Node prev, next; +	Node prevuse; +	short argno; +} Xnode; +typedef struct { +	Symbol vbl; +	short set; +	short number; +	unsigned mask; +} *Regnode; +enum { IREG=0, FREG=1 }; +typedef struct { +	char *name; +	unsigned int eaddr;  /* omit */ +	int offset; +	Node lastuse; +	int usecount; +	Regnode regnode; +	Symbol *wildcard; +} Xsymbol; +enum { RX=2 }; +typedef struct { +	int offset; +	unsigned freemask[2]; +} Env; + +#define LBURG_MAX SHRT_MAX + +enum { VREG=(44<<4) }; + +/* Exported for the front end */ +extern void             blockbeg(Env *); +extern void             blockend(Env *); +extern void             emit(Node); +extern Node             gen(Node); + +extern unsigned         emitbin(Node, int); + +#ifdef NDEBUG +#define debug(x) (void)0 +#else +#define debug(x) (void)(dflag&&((x),0)) +#endif diff --git a/src/tools/lcc/src/dag.c b/src/tools/lcc/src/dag.c new file mode 100644 index 0000000..420cbe7 --- /dev/null +++ b/src/tools/lcc/src/dag.c @@ -0,0 +1,736 @@ +#include "c.h" + + +#define iscall(op) (generic(op) == CALL \ +	|| (IR->mulops_calls \ +	&& (generic(op)==DIV||generic(op)==MOD||generic(op)==MUL) \ +	&& ( optype(op)==U  || optype(op)==I))) +static Node forest; +static struct dag { +	struct node node; +	struct dag *hlink; +} *buckets[16]; +int nodecount; +static Tree firstarg; +int assignargs = 1; +int prunetemps = -1; +static Node *tail; + +static int depth = 0; +static Node replace(Node); +static Node prune(Node); +static Node asgnnode(Symbol, Node); +static struct dag *dagnode(int, Node, Node, Symbol); +static Symbol equated(Symbol); +static void fixup(Node); +static void labelnode(int); +static void list(Node); +static void kill(Symbol); +static Node node(int, Node, Node, Symbol); +static void printdag1(Node, int, int); +static void printnode(Node, int, int); +static void reset(void); +static Node tmpnode(Node); +static void typestab(Symbol, void *); +static Node undag(Node); +static Node visit(Node, int); +static void unlist(void); +void walk(Tree tp, int tlab, int flab) { +	listnodes(tp, tlab, flab); +	if (forest) { +		Node list = forest->link; +		forest->link = NULL; +		if (!IR->wants_dag) +			list = undag(list); +		code(Gen)->u.forest = list; +		forest = NULL; +	} +	reset(); +	deallocate(STMT); +} + +static Node node(int op, Node l, Node r, Symbol sym) { +	int i; +	struct dag *p; + +	i = (opindex(op)^((unsigned long)sym>>2))&(NELEMS(buckets)-1); +	for (p = buckets[i]; p; p = p->hlink) +		if (p->node.op      == op && p->node.syms[0] == sym +		&&  p->node.kids[0] == l  && p->node.kids[1] == r) +			return &p->node; +	p = dagnode(op, l, r, sym); +	p->hlink = buckets[i]; +	buckets[i] = p; +	++nodecount; +	return &p->node; +} +static struct dag *dagnode(int op, Node l, Node r, Symbol sym) { +	struct dag *p; + +	NEW0(p, FUNC); +	p->node.op = op; +	if ((p->node.kids[0] = l) != NULL) +		++l->count; +	if ((p->node.kids[1] = r) != NULL) +		++r->count; +	p->node.syms[0] = sym; +	return p; +} +Node newnode(int op, Node l, Node r, Symbol sym) { +	return &dagnode(op, l, r, sym)->node; +} +static void kill(Symbol p) { +	int i; +	struct dag **q; + +	for (i = 0; i < NELEMS(buckets); i++) +		for (q = &buckets[i]; *q; ) +			if (generic((*q)->node.op) == INDIR && +			    (!isaddrop((*q)->node.kids[0]->op) +			     || (*q)->node.kids[0]->syms[0] == p)) { +				*q = (*q)->hlink; +				--nodecount; +			} else +				q = &(*q)->hlink; +} +static void reset(void) { +	if (nodecount > 0) +		memset(buckets, 0, sizeof buckets); +	nodecount = 0; +} +Node listnodes(Tree tp, int tlab, int flab) { +	Node p = NULL, l, r; +	int op; + +	assert(tlab || flab || (tlab == 0 && flab == 0)); +	if (tp == NULL) +		return NULL; +	if (tp->node) +		return tp->node; +	op = tp->op + sizeop(tp->type->size); +	switch (generic(tp->op)) { +	case AND:   { if (depth++ == 0) reset(); +		      if (flab) { +		      	listnodes(tp->kids[0], 0, flab); +		      	listnodes(tp->kids[1], 0, flab); +		      } else { +		      	listnodes(tp->kids[0], 0, flab = genlabel(1)); +		      	listnodes(tp->kids[1], tlab, 0); +		      	labelnode(flab); +		      } +		      depth--; } break; +	case OR:    { if (depth++ == 0) +		      	reset(); +		      if (tlab) { +		      	listnodes(tp->kids[0], tlab, 0); +		      	listnodes(tp->kids[1], tlab, 0); +		      } else { +		      	tlab = genlabel(1); +		      	listnodes(tp->kids[0], tlab, 0); +		      	listnodes(tp->kids[1], 0, flab); +		      	labelnode(tlab); +		      } +		      depth--; + } break; +	case NOT:   { return listnodes(tp->kids[0], flab, tlab); } +	case COND:  { Tree q = tp->kids[1]; +		      assert(tlab == 0 && flab == 0); +		      if (tp->u.sym) +		      	addlocal(tp->u.sym); +		      flab = genlabel(2); +		      listnodes(tp->kids[0], 0, flab); +		      assert(q && q->op == RIGHT); +		      reset(); +		      listnodes(q->kids[0], 0, 0); +		      if (forest->op == LABEL+V) { +		      	equatelab(forest->syms[0], findlabel(flab + 1)); +		      	unlist(); +		      } +		      list(jump(flab + 1)); +		      labelnode(flab); +		      listnodes(q->kids[1], 0, 0); +		      if (forest->op == LABEL+V) { +		      	equatelab(forest->syms[0], findlabel(flab + 1)); +		      	unlist(); +		      } +		      labelnode(flab + 1); + +		      if (tp->u.sym) +		      	p = listnodes(idtree(tp->u.sym), 0, 0); } break; +	case CNST:  { Type ty = unqual(tp->type); +		      assert(ty->u.sym); +		      if (tlab || flab) { +		      	assert(ty == inttype); +		      	if (tlab && tp->u.v.i != 0) +		      		list(jump(tlab)); +		      	else if (flab && tp->u.v.i == 0) +		      		list(jump(flab)); +		      } +		      else if (ty->u.sym->addressed) +		      	p = listnodes(cvtconst(tp), 0, 0); +		      else +		      	p = node(op, NULL, NULL, constant(ty, tp->u.v)); } break; +	case RIGHT: { if (   tp->kids[0] && tp->kids[1] +			  &&  generic(tp->kids[1]->op) == ASGN +			  && ((generic(tp->kids[0]->op) == INDIR +			  && tp->kids[0]->kids[0] == tp->kids[1]->kids[0]) +			  || (tp->kids[0]->op == FIELD +			  &&  tp->kids[0] == tp->kids[1]->kids[0]))) { +		      	assert(tlab == 0 && flab == 0); +			if (generic(tp->kids[0]->op) == INDIR) { +				p = listnodes(tp->kids[0], 0, 0); +				list(p); +				listnodes(tp->kids[1], 0, 0); +			} +			else { +				assert(generic(tp->kids[0]->kids[0]->op) == INDIR); +				list(listnodes(tp->kids[0]->kids[0], 0, 0)); +				p = listnodes(tp->kids[0], 0, 0); +				listnodes(tp->kids[1], 0, 0); +			} +		      } else if (tp->kids[1]) { +		      	listnodes(tp->kids[0], 0, 0); +		      	p = listnodes(tp->kids[1], tlab, flab); +		      } else +		      	p = listnodes(tp->kids[0], tlab, flab); } break; +	case JUMP:  { assert(tlab == 0 && flab == 0); +		      assert(tp->u.sym == 0); +		      assert(tp->kids[0]); +		      l = listnodes(tp->kids[0], 0, 0); +		      list(newnode(JUMP+V, l, NULL, NULL)); +		      reset(); } break; +	case CALL:  { Tree save = firstarg; +		      firstarg = NULL; +		      assert(tlab == 0 && flab == 0); +		      if (tp->op == CALL+B && !IR->wants_callb) { +		      	Tree arg0 = tree(ARG+P, tp->kids[1]->type, +				tp->kids[1], NULL); +			if (IR->left_to_right) +				firstarg = arg0; +			l = listnodes(tp->kids[0], 0, 0); +			if (!IR->left_to_right || firstarg) { +				firstarg = NULL; +				listnodes(arg0, 0, 0); +			} +		      	p = newnode(CALL+V, l, NULL, NULL); +		      } else { +		      	l = listnodes(tp->kids[0], 0, 0); +		      	r = listnodes(tp->kids[1], 0, 0); +		      	p = newnode(tp->op == CALL+B ? tp->op : op, l, r, NULL); +		      } +		      NEW0(p->syms[0], FUNC); +		      assert(isptr(tp->kids[0]->type)); +		      assert(isfunc(tp->kids[0]->type->type)); +		      p->syms[0]->type = tp->kids[0]->type->type; +		      list(p); +		      reset(); +		      cfunc->u.f.ncalls++; +		      firstarg = save; + } break; +	case ARG:   { assert(tlab == 0 && flab == 0); +		      if (IR->left_to_right) +		      	listnodes(tp->kids[1], 0, 0); +		      if (firstarg) { +		      	Tree arg = firstarg; +		      	firstarg = NULL; +		      	listnodes(arg, 0, 0); +		      } +		      l = listnodes(tp->kids[0], 0, 0); +		      list(newnode(tp->op == ARG+B ? tp->op : op, l, NULL, NULL)); +		      forest->syms[0] = intconst(tp->type->size); +		      forest->syms[1] = intconst(tp->type->align); +		      if (!IR->left_to_right) +		      	listnodes(tp->kids[1], 0, 0); } break; +	case EQ:  case NE: case GT: case GE: case LE: +	case LT:    { assert(tp->u.sym == 0); +		      assert(errcnt || tlab || flab); +		      l = listnodes(tp->kids[0], 0, 0); +		      r = listnodes(tp->kids[1], 0, 0); +		      assert(errcnt || opkind(l->op) == opkind(r->op)); +		      assert(errcnt || optype(op) == optype(l->op)); +		      if (tlab) +		      	assert(flab == 0), +		      	list(newnode(generic(tp->op) + opkind(l->op), l, r, findlabel(tlab))); +		      else if (flab) { +		      	switch (generic(tp->op)) { +		      	case EQ: op = NE; break; +		      	case NE: op = EQ; break; +		      	case GT: op = LE; break; +		      	case LT: op = GE; break; +		      	case GE: op = LT; break; +		      	case LE: op = GT; break; +		      	default: assert(0); +		      	} +		      	list(newnode(op + opkind(l->op), l, r, findlabel(flab))); +		      } +		      if (forest && forest->syms[0]) +		      	forest->syms[0]->ref++; } break; +	case ASGN:  { assert(tlab == 0 && flab == 0); +		      if (tp->kids[0]->op == FIELD) { +		      	Tree  x = tp->kids[0]->kids[0]; +			Field f = tp->kids[0]->u.field; +			assert(generic(x->op) == INDIR); +			reset(); +			l = listnodes(lvalue(x), 0, 0); +			if (fieldsize(f) < 8*f->type->size) { +				unsigned int fmask = fieldmask(f); +				unsigned int  mask = fmask<<fieldright(f); +				Tree q = tp->kids[1]; +				if ((q->op == CNST+I && q->u.v.i == 0) +				||  (q->op == CNST+U && q->u.v.u == 0)) +					q = bittree(BAND, x, cnsttree(unsignedtype, (unsigned long)~mask)); +				else if ((q->op == CNST+I && (q->u.v.i&fmask) == fmask) +				||       (q->op == CNST+U && (q->u.v.u&fmask) == fmask)) +					q = bittree(BOR, x, cnsttree(unsignedtype, (unsigned long)mask)); +				else { +					listnodes(q, 0, 0); +					q = bittree(BOR, +						bittree(BAND, rvalue(lvalue(x)), +							cnsttree(unsignedtype, (unsigned long)~mask)), +						bittree(BAND, shtree(LSH, cast(q, unsignedtype), +							cnsttree(unsignedtype, (unsigned long)fieldright(f))), +							cnsttree(unsignedtype, (unsigned long)mask))); +				} +				r = listnodes(q, 0, 0); +				op = ASGN + ttob(q->type); +			} else { +				r = listnodes(tp->kids[1], 0, 0); +				op = ASGN + ttob(tp->kids[1]->type); +			} +		      } else { +		      	l = listnodes(tp->kids[0], 0, 0); +		      	r = listnodes(tp->kids[1], 0, 0); +		      } +		      list(newnode(tp->op == ASGN+B ? tp->op : op, l, r, NULL)); +		      forest->syms[0] = intconst(tp->kids[1]->type->size); +		      forest->syms[1] = intconst(tp->kids[1]->type->align); +		      if (isaddrop(tp->kids[0]->op) +		      && !tp->kids[0]->u.sym->computed) +		      	kill(tp->kids[0]->u.sym); +		      else +		      	reset(); +		      p = listnodes(tp->kids[1], 0, 0); } break; +	case BOR: case BAND: case BXOR: +	case ADD: case SUB:  case RSH: +	case LSH:   { assert(tlab == 0 && flab == 0); +		      l = listnodes(tp->kids[0], 0, 0); +		      r = listnodes(tp->kids[1], 0, 0); +		      p = node(op, l, r, NULL); } break; +	case DIV: case MUL: +	case MOD:   { assert(tlab == 0 && flab == 0); +		      l = listnodes(tp->kids[0], 0, 0); +		      r = listnodes(tp->kids[1], 0, 0); +		      p = node(op, l, r, NULL); +		      if (IR->mulops_calls && isint(tp->type)) { +		      	list(p); +		      	cfunc->u.f.ncalls++; +		      } } break; +	case RET:   { assert(tlab == 0 && flab == 0); +		      l = listnodes(tp->kids[0], 0, 0); +		      list(newnode(op, l, NULL, NULL)); } break; +	case CVF: case CVI: case CVP: +	case CVU:   { assert(tlab == 0 && flab == 0); +		      assert(optype(tp->kids[0]->op) != optype(tp->op) || tp->kids[0]->type->size != tp->type->size); +		      l = listnodes(tp->kids[0], 0, 0); +		      p = node(op, l, NULL, intconst(tp->kids[0]->type->size)); + } break; +	case BCOM: +	case NEG:   { assert(tlab == 0 && flab == 0); +		      l = listnodes(tp->kids[0], 0, 0); +		      p = node(op, l, NULL, NULL); } break; +	case INDIR: { Type ty = tp->kids[0]->type; +		      assert(tlab == 0 && flab == 0); +		      l = listnodes(tp->kids[0], 0, 0); +		      if (isptr(ty)) +		      	ty = unqual(ty)->type; +		      if (isvolatile(ty) +		      || (isstruct(ty) && unqual(ty)->u.sym->u.s.vfields)) +		      	p = newnode(tp->op == INDIR+B ? tp->op : op, l, NULL, NULL); +		      else +		      	p = node(tp->op == INDIR+B ? tp->op : op, l, NULL, NULL); } break; +	case FIELD: { Tree q = tp->kids[0]; +		      if (tp->type == inttype) { +		      	long n = fieldleft(tp->u.field); +		      	q = shtree(RSH, +		      		shtree(LSH, q, cnsttree(inttype, n)), +		      		cnsttree(inttype, n + fieldright(tp->u.field))); +		      } else if (fieldsize(tp->u.field) < 8*tp->u.field->type->size) +		      	q = bittree(BAND, +		      		shtree(RSH, q, cnsttree(inttype, (long)fieldright(tp->u.field))), +		      		cnsttree(unsignedtype, (unsigned long)fieldmask(tp->u.field))); +		      assert(tlab == 0 && flab == 0); +		      p = listnodes(q, 0, 0); } break; +	case ADDRG: +	case ADDRF: { assert(tlab == 0 && flab == 0); +		      p = node(tp->op + sizeop(voidptype->size), NULL, NULL, tp->u.sym); + } break; +	case ADDRL: { assert(tlab == 0 && flab == 0); +		      if (tp->u.sym->temporary) +		      	addlocal(tp->u.sym); +		      p = node(tp->op + sizeop(voidptype->size), NULL, NULL, tp->u.sym); } break; +	default:assert(0); +	} +	tp->node = p; +	return p; +} +static void list(Node p) { +	if (p && p->link == NULL) { +		if (forest) { +			p->link = forest->link; +			forest->link = p; +		} else +			p->link = p; +		forest = p; +	} +} +static void labelnode(int lab) { +	assert(lab); +	if (forest && forest->op == LABEL+V) +		equatelab(findlabel(lab), forest->syms[0]); +	else +		list(newnode(LABEL+V, NULL, NULL, findlabel(lab))); +	reset(); +} +static void unlist(void) { +	Node p; + +	assert(forest); +	assert(forest != forest->link); +	p = forest->link; +	while (p->link != forest) +		p = p->link; +	p->link = forest->link; +	forest = p; +} +Tree cvtconst(Tree p) { +	Symbol q = constant(p->type, p->u.v); +	Tree e; + +	if (q->u.c.loc == NULL) +		q->u.c.loc = genident(STATIC, p->type, GLOBAL); +	if (isarray(p->type)) { +		e = simplify(ADDRG, atop(p->type), NULL, NULL); +		e->u.sym = q->u.c.loc; +	} else +		e = idtree(q->u.c.loc); +	return e; +} +void gencode(Symbol caller[], Symbol callee[]) { +	Code cp; +	Coordinate save; + +	if (prunetemps == -1) +		prunetemps = !IR->wants_dag; +	save = src; +	if (assignargs) { +		int i; +		Symbol p, q; +		cp = codehead.next->next; +		codelist = codehead.next; +		for (i = 0; (p = callee[i]) != NULL +		         && (q = caller[i]) != NULL; i++) +			if (p->sclass != q->sclass || p->type != q->type) +				walk(asgn(p, idtree(q)), 0, 0); +		codelist->next = cp; +		cp->prev = codelist; +	} +	if (glevel && IR->stabsym) { +		int i; +		Symbol p, q; +		for (i = 0; (p = callee[i]) != NULL +		         && (q = caller[i]) != NULL; i++) { +			(*IR->stabsym)(p); +			if (p->sclass != q->sclass || p->type != q->type) +				(*IR->stabsym)(q); +		} +		swtoseg(CODE); +	} +	cp = codehead.next; +	for ( ; errcnt <= 0 && cp; cp = cp->next) +		switch (cp->kind) { +		case Address:  (*IR->address)(cp->u.addr.sym, cp->u.addr.base, +			       	cp->u.addr.offset); break; +		case Blockbeg: { +			       	Symbol *p = cp->u.block.locals; +			       	(*IR->blockbeg)(&cp->u.block.x); +			       	for ( ; *p; p++) +			       		if ((*p)->ref != 0.0) +			       			(*IR->local)(*p); +			       		else if (glevel) (*IR->local)(*p); +			       } + break; +		case Blockend: (*IR->blockend)(&cp->u.begin->u.block.x); break; +		case Defpoint: src = cp->u.point.src; break; +		case Gen: case Jump: +		case Label:    if (prunetemps) +			       	cp->u.forest = prune(cp->u.forest); +			       fixup(cp->u.forest); +			       cp->u.forest = (*IR->gen)(cp->u.forest); break; +		case Local:    (*IR->local)(cp->u.var); break; +		case Switch:   break; +		default: assert(0); +		} +	src = save; +} +static void fixup(Node p) { +	for ( ; p; p = p->link) +		switch (generic(p->op)) { +		case JUMP: +			if (specific(p->kids[0]->op) == ADDRG+P) +				p->kids[0]->syms[0] = +					equated(p->kids[0]->syms[0]); +			break; +		case LABEL: assert(p->syms[0] == equated(p->syms[0])); break; +		case EQ: case GE: case GT: case LE: case LT: case NE: +			assert(p->syms[0]); +			p->syms[0] = equated(p->syms[0]); +		} +} +static Symbol equated(Symbol p) { +	{ Symbol q; for (q = p->u.l.equatedto; q; q = q->u.l.equatedto) assert(p != q); } +	while (p->u.l.equatedto) +		p = p->u.l.equatedto; +	return p; +} +void emitcode(void) { +	Code cp; +	Coordinate save; + +	save = src; +	cp = codehead.next; +	for ( ; errcnt <= 0 && cp; cp = cp->next) +		switch (cp->kind) { +		case Address: break; +		case Blockbeg: if (glevel && IR->stabblock) { +			       	(*IR->stabblock)('{',  cp->u.block.level - LOCAL, cp->u.block.locals); +			       	swtoseg(CODE); +			       } + break; +		case Blockend: if (glevel && IR->stabblock) { +			       	Code bp = cp->u.begin; +			       	foreach(bp->u.block.identifiers, bp->u.block.level, typestab, NULL); +			       	foreach(bp->u.block.types,       bp->u.block.level, typestab, NULL); +			       	(*IR->stabblock)('}', bp->u.block.level - LOCAL, bp->u.block.locals); +			       	swtoseg(CODE); +			       } + break; +		case Defpoint: src = cp->u.point.src; +			       if (glevel > 0 && IR->stabline) { +			       	(*IR->stabline)(&cp->u.point.src); swtoseg(CODE); } break; +		case Gen: case Jump: +		case Label:    if (cp->u.forest) +			       	(*IR->emit)(cp->u.forest); break; +		case Local:    if (glevel && IR->stabsym) { +			       	(*IR->stabsym)(cp->u.var); +			       	swtoseg(CODE); +			       } break; +		case Switch:   {	int i; +			       	defglobal(cp->u.swtch.table, LIT); +			       	(*IR->defaddress)(equated(cp->u.swtch.labels[0])); +			       	for (i = 1; i < cp->u.swtch.size; i++) { +			       		long k = cp->u.swtch.values[i-1]; +			       		while (++k < cp->u.swtch.values[i]) +			       			assert(k < LONG_MAX), +			       			(*IR->defaddress)(equated(cp->u.swtch.deflab)); +			       		(*IR->defaddress)(equated(cp->u.swtch.labels[i])); +			       	} +			       	swtoseg(CODE); +			       } break; +		default: assert(0); +		} +	src = save; +} + +static Node undag(Node forest) { +	Node p; + +	tail = &forest; +	for (p = forest; p; p = p->link) +		if (generic(p->op) == INDIR) { +			assert(p->count >= 1); +			visit(p, 1); +			if (p->syms[2]) { +				assert(p->syms[2]->u.t.cse); +				p->syms[2]->u.t.cse = NULL; +				addlocal(p->syms[2]); +			} +		} else if (iscall(p->op) && p->count >= 1) +			visit(p, 1); +		else { +			assert(p->count == 0), +			visit(p, 1); +			*tail = p; +			tail = &p->link; +		} +	*tail = NULL; +	return forest; +} +static Node replace(Node p) { +	if (p && (  generic(p->op) == INDIR +		 && generic(p->kids[0]->op) == ADDRL +		 && p->kids[0]->syms[0]->temporary +		 && p->kids[0]->syms[0]->u.t.replace)) { +		p = p->kids[0]->syms[0]->u.t.cse; +		if (generic(p->op) == INDIR && isaddrop(p->kids[0]->op)) +			p = newnode(p->op, newnode(p->kids[0]->op, NULL, NULL, +				p->kids[0]->syms[0]), NULL, NULL); +		else if (generic(p->op) == ADDRG) +			p = newnode(p->op, NULL, NULL, p->syms[0]); +		else +			assert(0); +		p->count = 1; +	} else if (p) { +		p->kids[0] = replace(p->kids[0]); +		p->kids[1] = replace(p->kids[1]); +	} +	return p; +} +static Node prune(Node forest) { +	Node p, *tail = &forest; +	int count = 0; + +	for (p = forest; p; p = p->link) { +		if (count > 0) { +			p->kids[0] = replace(p->kids[0]); +			p->kids[1] = replace(p->kids[1]); +		} +		if ((  generic(p->op) == ASGN +		    && generic(p->kids[0]->op) == ADDRL +		    && p->kids[0]->syms[0]->temporary +		    && p->kids[0]->syms[0]->u.t.cse == p->kids[1])) { +			Symbol tmp = p->kids[0]->syms[0]; +			if (!tmp->defined) +				(*IR->local)(tmp); +			tmp->defined = 1; +			if ((  generic(p->kids[1]->op) == INDIR +			    && isaddrop(p->kids[1]->kids[0]->op) +			    && p->kids[1]->kids[0]->syms[0]->sclass == REGISTER) +			|| ((  generic(p->kids[1]->op) == INDIR +			    && isaddrop(p->kids[1]->kids[0]->op)) && tmp->sclass == AUTO) +			|| (generic(p->kids[1]->op) == ADDRG && tmp->sclass == AUTO)) { +				tmp->u.t.replace = 1; +				count++; +				continue;	/* and omit the assignment */ +			} +		} +		/* keep the assignment and other roots */ +		*tail = p; +		tail = &(*tail)->link; +	} +	assert(*tail == NULL); +	return forest; +} +static Node visit(Node p, int listed) { +	if (p) { +		if (p->syms[2]) +			p = tmpnode(p); +		else if ((p->count <= 1 && !iscall(p->op)) +		||       (p->count == 0 &&  iscall(p->op))) { +			p->kids[0] = visit(p->kids[0], 0); +			p->kids[1] = visit(p->kids[1], 0); +		} + +		else if (specific(p->op) == ADDRL+P || specific(p->op) == ADDRF+P) { +			assert(!listed); +			p = newnode(p->op, NULL, NULL, p->syms[0]); +			p->count = 1; +		} +		else if (p->op == INDIR+B) { +			p = newnode(p->op, p->kids[0], NULL, NULL); +			p->count = 1; +			p->kids[0] = visit(p->kids[0], 0); +			p->kids[1] = visit(p->kids[1], 0); +		} +		else { +			p->kids[0] = visit(p->kids[0], 0); +			p->kids[1] = visit(p->kids[1], 0); +			p->syms[2] = temporary(REGISTER, btot(p->op, opsize(p->op))); +			assert(!p->syms[2]->defined); +			p->syms[2]->ref = 1; +			p->syms[2]->u.t.cse = p; + +			*tail = asgnnode(p->syms[2], p); +			tail = &(*tail)->link; +			if (!listed) +				p = tmpnode(p); +		}; +	} +	return p; +} +static Node tmpnode(Node p) { +	Symbol tmp = p->syms[2]; + +	assert(tmp); +	if (--p->count == 0) +		p->syms[2] = NULL; +	p = newnode(INDIR + ttob(tmp->type), +		newnode(ADDRL + ttob(voidptype), NULL, NULL, tmp), NULL, NULL); +	p->count = 1; +	return p; +} +static Node asgnnode(Symbol tmp, Node p) { +	p = newnode(ASGN + ttob(tmp->type), +		newnode(ADDRL + ttob(voidptype), NULL, NULL, tmp), p, NULL); +	p->syms[0] = intconst(tmp->type->size); +	p->syms[1] = intconst(tmp->type->align); +	return p; +} +/* printdag - print dag p on fd, or the node list if p == 0 */ +void printdag(Node p, int fd) { +	FILE *f = fd == 1 ? stdout : stderr; + +	printed(0); +	if (p == 0) { +		if ((p = forest) != NULL) +			do { +				p = p->link; +				printdag1(p, fd, 0); +			} while (p != forest); +	} else if (*printed(nodeid((Tree)p))) +		fprint(f, "node'%d printed above\n", nodeid((Tree)p)); +	else +		printdag1(p, fd, 0); +} + +/* printdag1 - recursively print dag p */ +static void printdag1(Node p, int fd, int lev) { +	int id, i; + +	if (p == 0 || *printed(id = nodeid((Tree)p))) +		return; +	*printed(id) = 1; +	for (i = 0; i < NELEMS(p->kids); i++) +		printdag1(p->kids[i], fd, lev + 1); +	printnode(p, fd, lev); +} + +/* printnode - print fields of dag p */ +static void printnode(Node p, int fd, int lev) { +	if (p) { +		FILE *f = fd == 1 ? stdout : stderr; +		int i, id = nodeid((Tree)p); +		fprint(f, "%c%d%s", lev == 0 ? '\'' : '#', id, +			&"   "[id < 10 ? 0 : id < 100 ? 1 : 2]); +		fprint(f, "%s count=%d", opname(p->op), p->count); +		for (i = 0; i < NELEMS(p->kids) && p->kids[i]; i++) +			fprint(f, " #%d", nodeid((Tree)p->kids[i])); +		if (generic(p->op) == CALL && p->syms[0] && p->syms[0]->type) +			fprint(f, " {%t}", p->syms[0]->type); +		else +			for (i = 0; i < NELEMS(p->syms) && p->syms[i]; i++) +				if (p->syms[i]->name) +					fprint(f, " %s", p->syms[i]->name); +				else +					fprint(f, " %p", p->syms[i]); +		fprint(f, "\n"); +	} +} + +/* typestab - emit stab entries for p */ +static void typestab(Symbol p, void *cl) { +	if (!isfunc(p->type) && (p->sclass == EXTERN || p->sclass == STATIC) && IR->stabsym) +		(*IR->stabsym)(p); +	else if ((p->sclass == TYPEDEF || p->sclass == 0) && IR->stabtype) +		(*IR->stabtype)(p); +} + diff --git a/src/tools/lcc/src/dagcheck.md b/src/tools/lcc/src/dagcheck.md new file mode 100644 index 0000000..292dbee --- /dev/null +++ b/src/tools/lcc/src/dagcheck.md @@ -0,0 +1,210 @@ +%{ +#include "c.h" +typedef Node NODEPTR_TYPE; +#define OP_LABEL(p)     (specific((p)->op)) +#define LEFT_CHILD(p)   ((p)->kids[0]) +#define RIGHT_CHILD(p)  ((p)->kids[1]) +#define STATE_LABEL(p)  ((p)->x.state) +#define PANIC	   error +%} +%term CNSTF=17 CNSTI=21 CNSTP=23 CNSTU=22 +%term ARGB=41 ARGF=33 ARGI=37 ARGP=39 ARGU=38 +%term ASGNB=57 ASGNF=49 ASGNI=53 ASGNP=55 ASGNU=54 +%term INDIRB=73 INDIRF=65 INDIRI=69 INDIRP=71 INDIRU=70 +%term CVFF=113 CVFI=117 +%term CVIF=129 CVII=133 CVIU=134 +%term CVPP=151 CVPU=150 +%term CVUI=181 CVUP=183 CVUU=182 +%term NEGF=193 NEGI=197 +%term CALLB=217 CALLF=209 CALLI=213 CALLP=215 CALLU=214 CALLV=216 +%term RETF=241 RETI=245 RETP=247 RETU=246 RETV=248 +%term ADDRGP=263 +%term ADDRFP=279 +%term ADDRLP=295 +%term ADDF=305 ADDI=309 ADDP=311 ADDU=310 +%term SUBF=321 SUBI=325 SUBP=327 SUBU=326 +%term LSHI=341 LSHU=342 +%term MODI=357 MODU=358 +%term RSHI=373 RSHU=374 +%term BANDI=389 BANDU=390 +%term BCOMI=405 BCOMU=406 +%term BORI=421 BORU=422 +%term BXORI=437 BXORU=438 +%term DIVF=449 DIVI=453 DIVU=454 +%term MULF=465 MULI=469 MULU=470 +%term EQF=481 EQI=485 EQU=486 +%term GEF=497 GEI=501 GEU=502 +%term GTF=513 GTI=517 GTU=518 +%term LEF=529 LEI=533 LEU=534 +%term LTF=545 LTI=549 LTU=550 +%term NEF=561 NEI=565 NEU=566 +%term JUMPV=584 +%term LABELV=600 +%% +stmt: INDIRB(P) "" +stmt: INDIRF(P) "" +stmt: INDIRI(P) "" +stmt: INDIRU(P) "" +stmt: INDIRP(P) "" +stmt: CALLF(P) "" +stmt: CALLI(P) "" +stmt: CALLU(P) "" +stmt: CALLP(P) "" +stmt: V "" +bogus: I "" 1 +bogus: U "" 1 +bogus: P "" 1 +bogus: F "" 1 +bogus: B "" 1 +bogus: V "" 1 +I: bogus "" 1 +U: bogus "" 1 +P: bogus "" 1 +F: bogus "" 1 +B: bogus "" 1 +V: bogus "" 1 +F: CNSTF "" +I: CNSTI "" +P: CNSTP "" +U: CNSTU "" +V: ARGB(B) "" +V: ARGF(F) "" +V: ARGI(I) "" +V: ARGU(U) "" +V: ARGP(P) "" +V: ASGNB(P,B) "" +V: ASGNF(P,F) "" +V: ASGNI(P,I) "" +V: ASGNU(P,U) "" +V: ASGNP(P,P) "" +B: INDIRB(P) "" +F: INDIRF(P) "" +I: INDIRI(P) "" +U: INDIRU(P) "" +P: INDIRP(P) "" +I: CVII(I) "" +I: CVUI(U) "" +I: CVFI(F) "" +U: CVIU(I) "" +U: CVUU(U) "" +U: CVPU(P) "" +F: CVIF(I) "" +F: CVFF(F) "" +P: CVUP(U) "" +P: CVPP(P) "" +F: NEGF(F) "" +I: NEGI(I) "" +V: CALLB(P,P) "" +F: CALLF(P) "" +I: CALLI(P) "" +U: CALLU(P) "" +P: CALLP(P) "" +V: CALLV(P) "" +V: RETF(F) "" +V: RETI(I) "" +V: RETU(U) "" +V: RETP(P) "" +V: RETV "" +P: ADDRGP "" +P: ADDRFP "" +P: ADDRLP "" +F: ADDF(F,F) "" +I: ADDI(I,I) "" +P: ADDP(P,I) "" +P: ADDP(I,P) "" +P: ADDP(U,P) "" +P: ADDP(P,U) "" +U: ADDU(U,U) "" +F: SUBF(F,F) "" +I: SUBI(I,I) "" +P: SUBP(P,I) "" +P: SUBP(P,U) "" +U: SUBU(U,U) "" +I: LSHI(I,I) "" +U: LSHU(U,I) "" +I: MODI(I,I) "" +U: MODU(U,U) "" +I: RSHI(I,I) "" +U: RSHU(U,I) "" +U: BANDU(U,U) "" +I: BANDI(I,I) "" +U: BCOMU(U) "" +I: BCOMI(I) "" +I: BORI(I,I) "" +U: BORU(U,U) "" +U: BXORU(U,U) "" +I: BXORI(I,I) "" +F: DIVF(F,F) "" +I: DIVI(I,I) "" +U: DIVU(U,U) "" +F: MULF(F,F) "" +I: MULI(I,I) "" +U: MULU(U,U) "" +V: EQF(F,F) "" +V: EQI(I,I) "" +V: EQU(U,U) "" +V: GEF(F,F) "" +V: GEI(I,I) "" +V: GEU(U,U) "" +V: GTF(F,F) "" +V: GTI(I,I) "" +V: GTU(U,U) "" +V: LEF(F,F) "" +V: LEI(I,I) "" +V: LEU(U,U) "" +V: LTF(F,F) "" +V: LTI(I,I) "" +V: LTU(U,U) "" +V: NEF(F,F) "" +V: NEI(I,I) "" +V: NEU(U,U) "" +V: JUMPV(P) "" +V: LABELV "" +%% + +static void reduce(NODEPTR_TYPE p, int goalnt) { +	int i, sz = opsize(p->op), rulenumber = _rule(p->x.state, goalnt); +	short *nts = _nts[rulenumber]; +	NODEPTR_TYPE kids[10]; + +	assert(rulenumber); +	_kids(p, rulenumber, kids); +	for (i = 0; nts[i]; i++) +		reduce(kids[i], nts[i]); +	switch (optype(p->op)) { +#define xx(ty) if (sz == ty->size) return +	case I: +	case U: +		xx(chartype); +		xx(shorttype); +		xx(inttype); +		xx(longtype); +		xx(longlong); +		break; +	case F: +		xx(floattype); +		xx(doubletype); +		xx(longdouble); +		break; +	case P: +		xx(voidptype); +		xx(funcptype); +		break; +	case V: +	case B: if (sz == 0) return; +#undef xx +	} +	printdag(p, 2); +	assert(0); +} + +void check(Node p) { +	struct _state { short cost[1]; }; + +	_label(p); +	if (((struct _state *)p->x.state)->cost[1] > 0) { +		printdag(p, 2); +		assert(0); +	} +	reduce(p, 1); +} diff --git a/src/tools/lcc/src/decl.c b/src/tools/lcc/src/decl.c new file mode 100644 index 0000000..132241e --- /dev/null +++ b/src/tools/lcc/src/decl.c @@ -0,0 +1,1162 @@ +#include "c.h" + + +#define add(x,n) (x > inttype->u.sym->u.limits.max.i-(n) ? (overflow=1,x) : x+(n)) +#define chkoverflow(x,n) ((void)add(x,n)) +#define bits2bytes(n) (((n) + 7)/8) +static int regcount; + +static List autos, registers; +Symbol cfunc;		/* current function */ +Symbol retv;		/* return value location for structs */ + +static void checkref(Symbol, void *); +static Symbol dclglobal(int, char *, Type, Coordinate *); +static Symbol dcllocal(int, char *, Type, Coordinate *); +static Symbol dclparam(int, char *, Type, Coordinate *); +static Type dclr(Type, char **, Symbol **, int); +static Type dclr1(char **, Symbol **, int); +static void decl(Symbol (*)(int, char *, Type, Coordinate *)); +extern void doconst(Symbol, void *); +static void doglobal(Symbol, void *); +static void doextern(Symbol, void *); +static void exitparams(Symbol []); +static void fields(Type); +static void funcdefn(int, char *, Type, Symbol [], Coordinate); +static void initglobal(Symbol, int); +static void oldparam(Symbol, void *); +static Symbol *parameters(Type); +static Type specifier(int *); +static Type structdcl(int); +static Type tnode(int, Type); +void program(void) { +	int n; +	 +	level = GLOBAL; +	for (n = 0; t != EOI; n++) +		if (kind[t] == CHAR || kind[t] == STATIC +		|| t == ID || t == '*' || t == '(') { +			decl(dclglobal); +			deallocate(STMT); +			if (!(glevel >= 3 || xref)) +			deallocate(FUNC); +		} else if (t == ';') { +			warning("empty declaration\n"); +			t = gettok(); +		} else { +			error("unrecognized declaration\n"); +			t = gettok(); +		} +	if (n == 0) +		warning("empty input file\n"); +} +static Type specifier(int *sclass) { +	int cls, cons, sign, size, type, vol; +	Type ty = NULL; + +	cls = vol = cons = sign = size = type = 0; +	if (sclass == NULL) +		cls = AUTO; +	for (;;) { +		int *p, tt = t; +		switch (t) { +		case AUTO: +		case REGISTER: if (level <= GLOBAL && cls == 0) +		               	error("invalid use of `%k'\n", t); +		               p = &cls;  t = gettok();      break; +		case STATIC: case EXTERN: +		case TYPEDEF:  p = &cls;  t = gettok();      break; +		case CONST:    p = &cons; t = gettok();      break; +		case VOLATILE: p = &vol;  t = gettok();      break; +		case SIGNED: +		case UNSIGNED: p = &sign; t = gettok();      break; +		case LONG:     if (size == LONG) { +		                       size = 0; +		                       tt = LONG+LONG; +		               } +		               p = &size; t = gettok();      break; +		case SHORT:    p = &size; t = gettok();      break; +		case VOID: case CHAR: case INT: case FLOAT: +		case DOUBLE:   p = &type; ty = tsym->type; +		                          t = gettok();      break; +		case ENUM:     p = &type; ty = enumdcl();    break; +		case STRUCT: +		case UNION:    p = &type; ty = structdcl(t); break; +		case ID: +			if (istypename(t, tsym) && type == 0 +			&& sign == 0 && size == 0) { +				use(tsym, src); +				ty = tsym->type; +				if (isqual(ty) +				&& ty->size != ty->type->size) { +					ty = unqual(ty); +					if (isconst(tsym->type)) +						ty = qual(CONST, ty); +					if (isvolatile(tsym->type)) +						ty = qual(VOLATILE, ty); +					tsym->type = ty; +				} +				p = &type; +				t = gettok(); +			} else +				p = NULL; +			break; +		default: p = NULL; +		} +		if (p == NULL) +			break; +		if (*p) +			error("invalid use of `%k'\n", tt); +		*p = tt; +	} +	if (sclass) +		*sclass = cls; +	if (type == 0) { +		type = INT; +		ty = inttype; +	} +	if ((size == SHORT     && type != INT) +	||  (size == LONG+LONG && type != INT) +	||  (size == LONG      && type != INT && type != DOUBLE) +	||  (sign && type != INT && type != CHAR)) +		error("invalid type specification\n"); +	if (type == CHAR && sign) +		ty = sign == UNSIGNED ? unsignedchar : signedchar; +	else if (size == SHORT) +		ty = sign == UNSIGNED ? unsignedshort : shorttype; +	else if (size == LONG && type == DOUBLE) +		ty = longdouble; +	else if (size == LONG+LONG) { +		ty = sign == UNSIGNED ? unsignedlonglong : longlong; +		if (Aflag >= 1) +			warning("`%t' is a non-ANSI type\n", ty); +	} else if (size == LONG) +		ty = sign == UNSIGNED ? unsignedlong : longtype; +	else if (sign == UNSIGNED && type == INT) +		ty = unsignedtype; +	if (cons == CONST) +		ty = qual(CONST, ty); +	if (vol  == VOLATILE) +		ty = qual(VOLATILE, ty); +	return ty; +} +static void decl(Symbol (*dcl)(int, char *, Type, Coordinate *)) { +	int sclass; +	Type ty, ty1; +	static char stop[] = { CHAR, STATIC, ID, 0 }; + +	ty = specifier(&sclass); +	if (t == ID || t == '*' || t == '(' || t == '[') { +		char *id; +		Coordinate pos; +		id = NULL; +		pos = src; +		if (level == GLOBAL) { +			Symbol *params = NULL; +			ty1 = dclr(ty, &id, ¶ms, 0); +			if (params && id && isfunc(ty1) +			    && (t == '{' || istypename(t, tsym) +			    || (kind[t] == STATIC && t != TYPEDEF))) { +				if (sclass == TYPEDEF) { +					error("invalid use of `typedef'\n"); +					sclass = EXTERN; +				} +				if (ty1->u.f.oldstyle) +					exitscope(); +				funcdefn(sclass, id, ty1, params, pos); +				return; +			} else if (params) +				exitparams(params); +		} else +			ty1 = dclr(ty, &id, NULL, 0); +		for (;;) { +			if (Aflag >= 1 && !hasproto(ty1)) +				warning("missing prototype\n"); +			if (id == NULL) +				error("missing identifier\n"); +			else if (sclass == TYPEDEF) +				{ +					Symbol p = lookup(id, identifiers); +					if (p && p->scope == level) +						error("redeclaration of `%s'\n", id); +					p = install(id, &identifiers, level, +						level < LOCAL ? PERM : FUNC); +					p->type = ty1; +					p->sclass = TYPEDEF; +					p->src = pos; +				} +			else +				(void)(*dcl)(sclass, id, ty1, &pos); +			if (t != ',') +				break; +			t = gettok(); +			id = NULL; +			pos = src; +			ty1 = dclr(ty, &id, NULL, 0); +		} +	} else if (ty == NULL +	|| !(isenum(ty) || +	     (isstruct(ty) && (*unqual(ty)->u.sym->name < '1' || *unqual(ty)->u.sym->name > '9')))) +		error("empty declaration\n"); +	test(';', stop); +} +static Symbol dclglobal(int sclass, char *id, Type ty, Coordinate *pos) { +	Symbol p; + +	if (sclass == 0) +		sclass = AUTO; +	else if (sclass != EXTERN && sclass != STATIC) { +		error("invalid storage class `%k' for `%t %s'\n", +			sclass, ty, id); +		sclass = AUTO; +	} +	p = lookup(id, identifiers); +	if (p && p->scope == GLOBAL) { +		if (p->sclass != TYPEDEF && eqtype(ty, p->type, 1)) +			ty = compose(ty, p->type); +		else +			error("redeclaration of `%s' previously declared at %w\n", p->name, &p->src); + +		if (!isfunc(ty) && p->defined && t == '=') +			error("redefinition of `%s' previously defined at %w\n", p->name, &p->src); + +		if ((p->sclass == EXTERN && sclass == STATIC) +		||  (p->sclass == STATIC && sclass == AUTO) +		||  (p->sclass == AUTO   && sclass == STATIC)) +			warning("inconsistent linkage for `%s' previously declared at %w\n", p->name, &p->src); + +	} +	if (p == NULL || p->scope != GLOBAL) { +		Symbol q = lookup(id, externals); +		if (q) { +			if (sclass == STATIC || !eqtype(ty, q->type, 1)) +				warning("declaration of `%s' does not match previous declaration at %w\n", id, &q->src); + +			p = relocate(id, externals, globals); +			p->sclass = sclass; +		} else { +			p = install(id, &globals, GLOBAL, PERM); +			p->sclass = sclass; +			(*IR->defsymbol)(p); +		} +		if (p->sclass != STATIC) { +			static int nglobals; +			nglobals++; +			if (Aflag >= 2 && nglobals == 512) +				warning("more than 511 external identifiers\n"); +		} +	} else if (p->sclass == EXTERN) +		p->sclass = sclass; +	p->type = ty; +	p->src = *pos; +	if (t == '=' && isfunc(p->type)) { +		error("illegal initialization for `%s'\n", p->name); +		t = gettok(); +		initializer(p->type, 0); +	} else if (t == '=') { +		initglobal(p, 0); +		if (glevel > 0 && IR->stabsym) { +			(*IR->stabsym)(p); swtoseg(p->u.seg); } +	} else if (p->sclass == STATIC && !isfunc(p->type) +	&& p->type->size == 0) +		error("undefined size for `%t %s'\n", p->type, p->name); +	return p; +} +static void initglobal(Symbol p, int flag) { +	Type ty; + +	if (t == '=' || flag) { +		if (p->sclass == STATIC) { +			for (ty = p->type; isarray(ty); ty = ty->type) +				; +			defglobal(p, isconst(ty) ? LIT : DATA); +		} else +			defglobal(p, DATA); +		if (t == '=') +			t = gettok(); +		ty = initializer(p->type, 0); +		if (isarray(p->type) && p->type->size == 0) +			p->type = ty; +		if (p->sclass == EXTERN) +			p->sclass = AUTO; +	} +} +void defglobal(Symbol p, int seg) { +	p->u.seg = seg; +	swtoseg(p->u.seg); +	if (p->sclass != STATIC) +		(*IR->export)(p); +	(*IR->global)(p); +	p->defined = 1; +} + +static Type dclr(Type basety, char **id, Symbol **params, int abstract) { +	Type ty = dclr1(id, params, abstract); + +	for ( ; ty; ty = ty->type) +		switch (ty->op) { +		case POINTER: +			basety = ptr(basety); +			break; +		case FUNCTION: +			basety = func(basety, ty->u.f.proto, +				ty->u.f.oldstyle); +			break; +		case ARRAY: +			basety = array(basety, ty->size, 0); +			break; +		case CONST: case VOLATILE: +			basety = qual(ty->op, basety); +			break; +		default: assert(0); +		} +	if (Aflag >= 2 && basety->size > 32767) +		warning("more than 32767 bytes in `%t'\n", basety); +	return basety; +} +static Type tnode(int op, Type type) { +	Type ty; + +	NEW0(ty, STMT); +	ty->op = op; +	ty->type = type; +	return ty; +} +static Type dclr1(char **id, Symbol **params, int abstract) { +	Type ty = NULL; + +	switch (t) { +	case ID:                if (id) +					*id = token; +				else +					error("extraneous identifier `%s'\n", token); +				t = gettok(); break; +	case '*': t = gettok(); if (t == CONST || t == VOLATILE) { +					Type ty1; +					ty1 = ty = tnode(t, NULL); +					while ((t = gettok()) == CONST || t == VOLATILE) +						ty1 = tnode(t, ty1); +					ty->type = dclr1(id, params, abstract); +					ty = ty1; +				} else +					ty = dclr1(id, params, abstract); +				ty = tnode(POINTER, ty); break; +	case '(': t = gettok(); if (abstract +				&& (t == REGISTER || istypename(t, tsym) || t == ')')) { +					Symbol *args; +					ty = tnode(FUNCTION, ty); +					enterscope(); +					if (level > PARAM) +						enterscope(); +					args = parameters(ty); +					exitparams(args); +				} else { +					ty = dclr1(id, params, abstract); +					expect(')'); +					if (abstract && ty == NULL +					&& (id == NULL || *id == NULL)) +						return tnode(FUNCTION, NULL); +				} break; +	case '[': break; +	default:  return ty; +	} +	while (t == '(' || t == '[') +		switch (t) { +		case '(': t = gettok(); { Symbol *args; +					  ty = tnode(FUNCTION, ty); +					  enterscope(); +					  if (level > PARAM) +					  	enterscope(); +					  args = parameters(ty); +					  if (params && *params == NULL) +					  	*params = args; +					  else +					  	exitparams(args); + } +		          break; +		case '[': t = gettok(); { int n = 0; +					  if (kind[t] == ID) { +					  	n = intexpr(']', 1); +					  	if (n <= 0) { +					  		error("`%d' is an illegal array size\n", n); +					  		n = 1; +					  	} +					  } else +					  	expect(']'); +					  ty = tnode(ARRAY, ty); +					  ty->size = n; } break; +		default: assert(0); +		} +	return ty; +} +static Symbol *parameters(Type fty) { +	List list = NULL; +	Symbol *params; + +	if (kind[t] == STATIC || istypename(t, tsym)) { +		int n = 0; +		Type ty1 = NULL; +		for (;;) { +			Type ty; +			int sclass = 0; +			char *id = NULL; +			if (ty1 && t == ELLIPSIS) { +				static struct symbol sentinel; +				if (sentinel.type == NULL) { +					sentinel.type = voidtype; +					sentinel.defined = 1; +				} +				if (ty1 == voidtype) +					error("illegal formal parameter types\n"); +				list = append(&sentinel, list); +				t = gettok(); +				break; +			} +			if (!istypename(t, tsym) && t != REGISTER) +				error("missing parameter type\n"); +			n++; +			ty = dclr(specifier(&sclass), &id, NULL, 1); +			if ( (ty == voidtype && (ty1 || id)) +			||  ty1 == voidtype) +				error("illegal formal parameter types\n"); +			if (id == NULL) +				id = stringd(n); +			if (ty != voidtype) +				list = append(dclparam(sclass, id, ty, &src), list); +			if (Aflag >= 1 && !hasproto(ty)) +				warning("missing prototype\n"); +			if (ty1 == NULL) +				ty1 = ty; +			if (t != ',') +				break; +			t = gettok(); +		} +		fty->u.f.proto = newarray(length(list) + 1, +			sizeof (Type *), PERM); +		params = ltov(&list, FUNC); +		for (n = 0; params[n]; n++) +			fty->u.f.proto[n] = params[n]->type; +		fty->u.f.proto[n] = NULL; +		fty->u.f.oldstyle = 0; +	} else { +		if (t == ID) +			for (;;) { +				Symbol p; +				if (t != ID) { +					error("expecting an identifier\n"); +					break; +				} +				p = dclparam(0, token, inttype, &src); +				p->defined = 0; +				list = append(p, list); +				t = gettok(); +				if (t != ',') +					break; +				t = gettok(); +			} +		params = ltov(&list, FUNC); +		fty->u.f.proto = NULL; +		fty->u.f.oldstyle = 1; +	} +	if (t != ')') { +		static char stop[] = { CHAR, STATIC, IF, ')', 0 }; +		expect(')'); +		skipto('{', stop); +	} +	if (t == ')') +		t = gettok(); +	return params; +} +static void exitparams(Symbol params[]) { +	assert(params); +	if (params[0] && !params[0]->defined) +		error("extraneous old-style parameter list\n"); +	if (level > PARAM) +		exitscope(); +	exitscope(); +} + +static Symbol dclparam(int sclass, char *id, Type ty, Coordinate *pos) { +	Symbol p; + +	if (isfunc(ty)) +		ty = ptr(ty); +	else if (isarray(ty)) +		ty = atop(ty); +	if (sclass == 0) +		sclass = AUTO; +	else if (sclass != REGISTER) { +		error("invalid storage class `%k' for `%t%s\n", +			sclass, ty, stringf(id ? " %s'" : "' parameter", id)); +		sclass = AUTO; +	} else if (isvolatile(ty) || isstruct(ty)) { +		warning("register declaration ignored for `%t%s\n", +			ty, stringf(id ? " %s'" : "' parameter", id)); +		sclass = AUTO; +	} + +	p = lookup(id, identifiers); +	if (p && p->scope == level) +		error("duplicate declaration for `%s' previously declared at %w\n", id, &p->src); + +	else +		p = install(id, &identifiers, level, FUNC); +	p->sclass = sclass; +	p->src = *pos; +	p->type = ty; +	p->defined = 1; +	if (t == '=') { +		error("illegal initialization for parameter `%s'\n", id); +		t = gettok(); +		(void)expr1(0); +	} +	return p; +} +static Type structdcl(int op) { +	char *tag; +	Type ty; +	Symbol p; +	Coordinate pos; + +	t = gettok(); +	pos = src; +	if (t == ID) { +		tag = token; +		t = gettok(); +	} else +		tag = ""; +	if (t == '{') { +		static char stop[] = { IF, ',', 0 }; +		ty = newstruct(op, tag); +		ty->u.sym->src = pos; +		ty->u.sym->defined = 1; +		t = gettok(); +		if (istypename(t, tsym)) +			fields(ty); +		else +			error("invalid %k field declarations\n", op); +		test('}', stop); +	} +	else if (*tag && (p = lookup(tag, types)) != NULL +	&& p->type->op == op) { +		ty = p->type; +		if (t == ';' && p->scope < level) +			ty = newstruct(op, tag); +	} +	else { +		if (*tag == 0) +			error("missing %k tag\n", op); +		ty = newstruct(op, tag); +	} +	if (*tag && xref) +		use(ty->u.sym, pos); +	return ty; +} +static void fields(Type ty) { +	{ int n = 0; +	  while (istypename(t, tsym)) { +	  	static char stop[] = { IF, CHAR, '}', 0 }; +	  	Type ty1 = specifier(NULL); +	  	for (;;) { +	  		Field p; +	  		char *id = NULL; +	  		Type fty = dclr(ty1, &id, NULL, 0); +			p = newfield(id, ty, fty); +			if (Aflag >= 1 && !hasproto(p->type)) +				warning("missing prototype\n"); +			if (t == ':') { +				if (unqual(p->type) != inttype +				&&  unqual(p->type) != unsignedtype) { +					error("`%t' is an illegal bit-field type\n", +						p->type); +					p->type = inttype; +				} +				t = gettok(); +				p->bitsize = intexpr(0, 0); +				if (p->bitsize > 8*inttype->size || p->bitsize < 0) { +					error("`%d' is an illegal bit-field size\n", +						p->bitsize); +					p->bitsize = 8*inttype->size; +				} else if (p->bitsize == 0 && id) { +					warning("extraneous 0-width bit field `%t %s' ignored\n", p->type, id); + +					p->name = stringd(genlabel(1)); +				} +				p->lsb = 1; +			} +			else { +				if (id == NULL) +					error("field name missing\n"); +				else if (isfunc(p->type)) +					error("`%t' is an illegal field type\n", p->type); +				else if (p->type->size == 0) +					error("undefined size for field `%t %s'\n", +						p->type, id); +			} +			if (isconst(p->type)) +				ty->u.sym->u.s.cfields = 1; +			if (isvolatile(p->type)) +				ty->u.sym->u.s.vfields = 1; +	  		n++; +	  		if (Aflag >= 2 && n == 128) +	  			warning("more than 127 fields in `%t'\n", ty); +	  		if (t != ',') +	  			break; +	  		t = gettok(); +	  	} +	  	test(';', stop); +	  } } +	{ int bits = 0, off = 0, overflow = 0; +	  Field p, *q = &ty->u.sym->u.s.flist; +	  ty->align = IR->structmetric.align; +	  for (p = *q; p; p = p->link) { +	  	int a = p->type->align ? p->type->align : 1; +		if (p->lsb) +			a = unsignedtype->align; +		if (ty->op == UNION) +			off = bits = 0; +		else if (p->bitsize == 0 || bits == 0 +		|| bits - 1 + p->bitsize > 8*unsignedtype->size) { +			off = add(off, bits2bytes(bits-1)); +			bits = 0; +			chkoverflow(off, a - 1); +			off = roundup(off, a); +		} +		if (a > ty->align) +			ty->align = a; +		p->offset = off; + +		if (p->lsb) { +			if (bits == 0) +				bits = 1; +			if (IR->little_endian) +				p->lsb = bits; +			else +				p->lsb = 8*unsignedtype->size - bits + 1 +					- p->bitsize + 1; +			bits += p->bitsize; +		} else +			off = add(off, p->type->size); +		if (off + bits2bytes(bits-1) > ty->size) +			ty->size = off + bits2bytes(bits-1); +	  	if (p->name == NULL +	  	|| !('1' <= *p->name && *p->name <= '9')) { +	  		*q = p; +	  		q = &p->link; +	  	} +	  } +	  *q = NULL; +	  chkoverflow(ty->size, ty->align - 1); +	  ty->size = roundup(ty->size, ty->align); +	  if (overflow) { +	  	error("size of `%t' exceeds %d bytes\n", ty, inttype->u.sym->u.limits.max.i); +	  	ty->size = inttype->u.sym->u.limits.max.i&(~(ty->align - 1)); +	  } } +} +static void funcdefn(int sclass, char *id, Type ty, Symbol params[], Coordinate pt) { +	int i, n; +	Symbol *callee, *caller, p; +	Type rty = freturn(ty); + +	if (isstruct(rty) && rty->size == 0) +		error("illegal use of incomplete type `%t'\n", rty); +	for (n = 0; params[n]; n++) +		; +	if (n > 0 && params[n-1]->name == NULL) +		params[--n] = NULL; +	if (Aflag >= 2 && n > 31) +		warning("more than 31 parameters in function `%s'\n", id); +	if (ty->u.f.oldstyle) { +		if (Aflag >= 1) +			warning("old-style function definition for `%s'\n", id); +		caller = params; +		callee = newarray(n + 1, sizeof *callee, FUNC); +		memcpy(callee, caller, (n+1)*sizeof *callee); +		enterscope(); +		assert(level == PARAM); +		while (kind[t] == STATIC || istypename(t, tsym)) +			decl(dclparam); +		foreach(identifiers, PARAM, oldparam, callee); + +		for (i = 0; (p = callee[i]) != NULL; i++) { +			if (!p->defined) +				callee[i] = dclparam(0, p->name, inttype, &p->src); +			*caller[i] = *p; +			caller[i]->sclass = AUTO; +			caller[i]->type = promote(p->type); +		} +		p = lookup(id, identifiers); +		if (p && p->scope == GLOBAL && isfunc(p->type) +		&& p->type->u.f.proto) { +			Type *proto = p->type->u.f.proto; +			for (i = 0; caller[i] && proto[i]; i++) { +				Type ty = unqual(proto[i]); +				if (eqtype(isenum(ty) ? ty->type : ty, +					unqual(caller[i]->type), 1) == 0) +					break; +				else if (isenum(ty) && !isenum(unqual(caller[i]->type))) +					warning("compatibility of `%t' and `%t' is compiler dependent\n", +						proto[i], caller[i]->type); +			} +			if (proto[i] || caller[i]) +				error("conflicting argument declarations for function `%s'\n", id); + +		} +		else { +			Type *proto = newarray(n + 1, sizeof *proto, PERM); +			if (Aflag >= 1) +				warning("missing prototype for `%s'\n", id); +			for (i = 0; i < n; i++) +				proto[i] = caller[i]->type; +			proto[i] = NULL; +			ty = func(rty, proto, 1); +		} +	} else { +		callee = params; +		caller = newarray(n + 1, sizeof *caller, FUNC); +		for (i = 0; (p = callee[i]) != NULL && p->name; i++) { +			NEW(caller[i], FUNC); +			*caller[i] = *p; +			if (isint(p->type)) +				caller[i]->type = promote(p->type); +			caller[i]->sclass = AUTO; +			if ('1' <= *p->name && *p->name <= '9') +				error("missing name for parameter %d to function `%s'\n", i + 1, id); + +		} +		caller[i] = NULL; +	} +	for (i = 0; (p = callee[i]) != NULL; i++) +		if (p->type->size == 0) { +			error("undefined size for parameter `%t %s'\n", +				p->type, p->name); +			caller[i]->type = p->type = inttype; +		} +	if (Aflag >= 2 && sclass != STATIC && strcmp(id, "main") == 0) { +		if (ty->u.f.oldstyle) +			warning("`%t %s()' is a non-ANSI definition\n", rty, id); +		else if (!(rty == inttype +			&& ((n == 0 && callee[0] == NULL) +			||  (n == 2 && callee[0]->type == inttype +			&& isptr(callee[1]->type) && callee[1]->type->type == charptype +			&& !variadic(ty))))) +			warning("`%s' is a non-ANSI definition\n", typestring(ty, id)); +	} +	p = lookup(id, identifiers); +	if (p && isfunc(p->type) && p->defined) +		error("redefinition of `%s' previously defined at %w\n", +			p->name, &p->src); +	cfunc = dclglobal(sclass, id, ty, &pt); +	cfunc->u.f.label = genlabel(1); +	cfunc->u.f.callee = callee; +	cfunc->u.f.pt = src; +	cfunc->defined = 1; +	if (xref) +		use(cfunc, cfunc->src); +	if (Pflag) +		printproto(cfunc, cfunc->u.f.callee); +	if (ncalled >= 0) +		ncalled = findfunc(cfunc->name, pt.file); +	labels   = table(NULL, LABELS); +	stmtlabs = table(NULL, LABELS); +	refinc = 1.0; +	regcount = 0; +	codelist = &codehead; +	codelist->next = NULL; +	if (!IR->wants_callb && isstruct(rty)) +		retv = genident(AUTO, ptr(rty), PARAM); +	compound(0, NULL, 0); + +	{ +		Code cp; +		for (cp = codelist; cp->kind < Label; cp = cp->prev) +			; +		if (cp->kind != Jump) { +			if (rty != voidtype) { +				warning("missing return value\n"); +				retcode(cnsttree(inttype, 0L)); +			} else +				retcode(NULL); +		} +	} +	definelab(cfunc->u.f.label); +	if (events.exit) +		apply(events.exit, cfunc, NULL); +	walk(NULL, 0, 0); +	exitscope(); +	assert(level == PARAM); +	foreach(identifiers, level, checkref, NULL); +	if (!IR->wants_callb && isstruct(rty)) { +		Symbol *a; +		a = newarray(n + 2, sizeof *a, FUNC); +		a[0] = retv; +		memcpy(&a[1], callee, (n+1)*sizeof *callee); +		callee = a; +		a = newarray(n + 2, sizeof *a, FUNC); +		NEW(a[0], FUNC); +		*a[0] = *retv; +		memcpy(&a[1], caller, (n+1)*sizeof *callee); +		caller = a; +	} +	if (!IR->wants_argb) +		for (i = 0; caller[i]; i++) +			if (isstruct(caller[i]->type)) { +				caller[i]->type = ptr(caller[i]->type); +				callee[i]->type = ptr(callee[i]->type); +				caller[i]->structarg = callee[i]->structarg = 1; +			} +	if (glevel > 1)	for (i = 0; callee[i]; i++) callee[i]->sclass = AUTO; +	if (cfunc->sclass != STATIC) +		(*IR->export)(cfunc); +	if (glevel && IR->stabsym) { +		swtoseg(CODE); (*IR->stabsym)(cfunc); } +	swtoseg(CODE); +	(*IR->function)(cfunc, caller, callee, cfunc->u.f.ncalls); +	if (glevel && IR->stabfend) +		(*IR->stabfend)(cfunc, lineno); +	foreach(stmtlabs, LABELS, checklab, NULL); +	exitscope(); +	expect('}'); +	labels = stmtlabs = NULL; +	retv  = NULL; +	cfunc = NULL; +} +static void oldparam(Symbol p, void *cl) { +	int i; +	Symbol *callee = cl; + +	for (i = 0; callee[i]; i++) +		if (p->name == callee[i]->name) { +			callee[i] = p; +			return; +		} +	error("declared parameter `%s' is missing\n", p->name); +} +void compound(int loop, struct swtch *swp, int lev) { +	Code cp; +	int nregs; + +	walk(NULL, 0, 0); +	cp = code(Blockbeg); +	enterscope(); +	assert(level >= LOCAL); +	if (level == LOCAL && events.entry) +		apply(events.entry, cfunc, NULL); +	definept(NULL); +	expect('{'); +	autos = registers = NULL; +	if (level == LOCAL && IR->wants_callb +	&& isstruct(freturn(cfunc->type))) { +		retv = genident(AUTO, ptr(freturn(cfunc->type)), level); +		retv->defined = 1; +		retv->ref = 1; +		registers = append(retv, registers); +	} +	while (kind[t] == CHAR || kind[t] == STATIC +	|| (istypename(t, tsym) && getchr() != ':')) +		decl(dcllocal); +	{ +		int i; +		Symbol *a = ltov(&autos, STMT); +		nregs = length(registers); +		for (i = 0; a[i]; i++) +			registers = append(a[i], registers); +		cp->u.block.locals = ltov(®isters, FUNC); +	} +	if (events.blockentry) +		apply(events.blockentry, cp->u.block.locals, NULL); +	while (kind[t] == IF || kind[t] == ID) +		statement(loop, swp, lev); +	walk(NULL, 0, 0); +	foreach(identifiers, level, checkref, NULL); +	{ +		int i = nregs, j; +		Symbol p; +		for ( ; (p = cp->u.block.locals[i]) != NULL; i++) { +			for (j = i; j > nregs +				&& cp->u.block.locals[j-1]->ref < p->ref; j--) +				cp->u.block.locals[j] = cp->u.block.locals[j-1]; +			cp->u.block.locals[j] = p; +		} +	} +	if (events.blockexit) +		apply(events.blockexit, cp->u.block.locals, NULL); +	cp->u.block.level = level; +	cp->u.block.identifiers = identifiers; +	cp->u.block.types = types; +	code(Blockend)->u.begin = cp; +	if (reachable(Gen)) +		definept(NULL); +	if (level > LOCAL) { +		exitscope(); +		expect('}'); +	} +} +static void checkref(Symbol p, void *cl) { +	if (p->scope >= PARAM +	&& (isvolatile(p->type) || isfunc(p->type))) +		p->addressed = 1; +	if (Aflag >= 2 && p->defined && p->ref == 0) { +		if (p->sclass == STATIC) +			warning("static `%t %s' is not referenced\n", +				p->type, p->name); +		else if (p->scope == PARAM) +			warning("parameter `%t %s' is not referenced\n", +				p->type, p->name); +		else if (p->scope >= LOCAL && p->sclass != EXTERN) +			warning("local `%t %s' is not referenced\n", +				p->type, p->name); +	} +	if (p->sclass == AUTO +	&& ((p->scope  == PARAM && regcount == 0) +	 || p->scope  >= LOCAL) +	&& !p->addressed && isscalar(p->type) && p->ref >= 3.0) +		p->sclass = REGISTER; +	if (level == GLOBAL && p->sclass == STATIC && !p->defined +	&& isfunc(p->type) && p->ref) +		error("undefined static `%t %s'\n", p->type, p->name); +	assert(!(level == GLOBAL && p->sclass == STATIC && !p->defined && !isfunc(p->type))); +} +static Symbol dcllocal(int sclass, char *id, Type ty, Coordinate *pos) { +	Symbol p, q; + +	if (sclass == 0) +		sclass = isfunc(ty) ? EXTERN : AUTO; +	else if (isfunc(ty) && sclass != EXTERN) { +		error("invalid storage class `%k' for `%t %s'\n", +			sclass, ty, id); +		sclass = EXTERN; +	} else if (sclass == REGISTER +	&& (isvolatile(ty) || isstruct(ty) || isarray(ty))) { +		warning("register declaration ignored for `%t %s'\n", +			ty, id); +		sclass = AUTO; +	} +	q = lookup(id, identifiers); +	if ((q && q->scope >= level) +	||  (q && q->scope == PARAM && level == LOCAL)) { +		if (sclass == EXTERN && q->sclass == EXTERN +		&& eqtype(q->type, ty, 1)) +			ty = compose(ty, q->type); +		else +			error("redeclaration of `%s' previously declared at %w\n", q->name, &q->src); +	} + +	assert(level >= LOCAL); +	p = install(id, &identifiers, level, sclass == STATIC || sclass == EXTERN ? PERM : FUNC); +	p->type = ty; +	p->sclass = sclass; +	p->src = *pos; +	switch (sclass) { +	case EXTERN:   q = lookup(id, globals); +		       if (q == NULL || q->sclass == TYPEDEF || q->sclass == ENUM) { +		       	q = lookup(id, externals); +		       	if (q == NULL) { +		       		q = install(p->name, &externals, GLOBAL, PERM); +		       		q->type = p->type; +		       		q->sclass = EXTERN; +		       		q->src = src; +		       		(*IR->defsymbol)(q); +		       	} +		       } +		       if (!eqtype(p->type, q->type, 1)) +		       	warning("declaration of `%s' does not match previous declaration at %w\n", q->name, &q->src); + +		       p->u.alias = q; break; +	case STATIC:   (*IR->defsymbol)(p); +		       initglobal(p, 0); +		       if (!p->defined) { +		       	if (p->type->size > 0) { +		       		defglobal(p, BSS); +		       		(*IR->space)(p->type->size); +		       	} else +		       		error("undefined size for `%t %s'\n", +		       			p->type, p->name); +		       } +		       p->defined = 1; break; +	case REGISTER: registers = append(p, registers); +		       regcount++; +		       p->defined = 1; + break; +	case AUTO:     autos = append(p, autos); +		       p->defined = 1; break; +	default: assert(0); +	} +	if (t == '=') { +		Tree e; +		if (sclass == EXTERN) +			error("illegal initialization of `extern %s'\n", id); +		t = gettok(); +		definept(NULL); +		if (isscalar(p->type) +		||  (isstruct(p->type) && t != '{')) { +			if (t == '{') { +				t = gettok(); +				e = expr1(0); +				expect('}'); +			} else +				e = expr1(0); +		} else { +			Symbol t1; +			Type ty = p->type, ty1 = ty; +			while (isarray(ty1)) +				ty1 = ty1->type; +			if (!isconst(ty) && (!isarray(ty) || !isconst(ty1))) +				ty = qual(CONST, ty); +			t1 = genident(STATIC, ty, GLOBAL); +			initglobal(t1, 1); +			if (isarray(p->type) && p->type->size == 0 +			&& t1->type->size > 0) +				p->type = array(p->type->type, +					t1->type->size/t1->type->type->size, 0); +			e = idtree(t1); +		} +		walk(root(asgn(p, e)), 0, 0); +		p->ref = 1; +	} +	if (!isfunc(p->type) && p->defined && p->type->size <= 0) +		error("undefined size for `%t %s'\n", p->type, id); +	return p; +} +void finalize(void) { +	foreach(externals,   GLOBAL,    doextern, NULL); +	foreach(identifiers, GLOBAL,    doglobal, NULL); +	foreach(identifiers, GLOBAL,    checkref, NULL); +	foreach(constants,   CONSTANTS, doconst,  NULL); +} +static void doextern(Symbol p, void *cl) { +	(*IR->import)(p); +} +static void doglobal(Symbol p, void *cl) { +	if (!p->defined && (p->sclass == EXTERN +	|| (isfunc(p->type) && p->sclass == AUTO))) +		(*IR->import)(p); +	else if (!p->defined && !isfunc(p->type) +	&& (p->sclass == AUTO || p->sclass == STATIC)) { +		if (isarray(p->type) +		&& p->type->size == 0 && p->type->type->size > 0) +			p->type = array(p->type->type, 1, 0); +		if (p->type->size > 0) { +			defglobal(p, BSS); +			(*IR->space)(p->type->size); +			if (glevel > 0 && IR->stabsym) +				(*IR->stabsym)(p); +		} else +			error("undefined size for `%t %s'\n", +				p->type, p->name); +		p->defined = 1; +	} +	if (Pflag +	&& !isfunc(p->type) +	&& !p->generated && p->sclass != EXTERN) +		printdecl(p, p->type); +} +void doconst(Symbol p, void *cl) { +	if (p->u.c.loc) { +		assert(p->u.c.loc->u.seg == 0);  +		defglobal(p->u.c.loc, LIT); +		if (isarray(p->type) && p->type->type == widechar) { +			unsigned int *s = p->u.c.v.p; +			int n = p->type->size/widechar->size; +			while (n-- > 0) { +				Value v; +				v.u = *s++; +				(*IR->defconst)(widechar->op, widechar->size, v); +			} +		} else if (isarray(p->type)) +			(*IR->defstring)(p->type->size, p->u.c.v.p); +		else +			(*IR->defconst)(p->type->op, p->type->size, p->u.c.v); +		p->u.c.loc = NULL; +	} +} +void checklab(Symbol p, void *cl) { +	if (!p->defined) +		error("undefined label `%s'\n", p->name); +	p->defined = 1; +} + +Type enumdcl(void) { +	char *tag; +	Type ty; +	Symbol p = {0}; +	Coordinate pos; + +	t = gettok(); +	pos = src; +	if (t == ID) { +		tag = token; +		t = gettok(); +	} else +		tag = ""; +	if (t == '{') { +		static char follow[] = { IF, 0 }; +		int n = 0; +		long k = -1; +		List idlist = 0; +		ty = newstruct(ENUM, tag); +		t = gettok(); +		if (t != ID) +			error("expecting an enumerator identifier\n"); +		while (t == ID) { +			char *id = token; +			Coordinate s; +			if (tsym && tsym->scope == level) +				error("redeclaration of `%s' previously declared at %w\n", +					token, &tsym->src); +			s = src; +			t = gettok(); +			if (t == '=') { +				t = gettok(); +				k = intexpr(0, 0); +			} else { +				if (k == inttype->u.sym->u.limits.max.i) +					error("overflow in value for enumeration constant `%s'\n", id); +				k++; +			} +			p = install(id, &identifiers, level,  level < LOCAL ? PERM : FUNC); +			p->src = s; +			p->type = ty; +			p->sclass = ENUM; +			p->u.value = k; +			idlist = append(p, idlist); +			n++; +			if (Aflag >= 2 && n == 128) +				warning("more than 127 enumeration constants in `%t'\n", ty); +			if (t != ',') +				break; +			t = gettok(); +			if (Aflag >= 2 && t == '}') +				warning("non-ANSI trailing comma in enumerator list\n"); +		} +		test('}', follow); +		ty->type = inttype; +		ty->size = ty->type->size; +		ty->align = ty->type->align; +		ty->u.sym->u.idlist = ltov(&idlist, PERM); +		ty->u.sym->defined = 1; +	} else if ((p = lookup(tag, types)) != NULL && p->type->op == ENUM) { +		ty = p->type; +		if (t == ';') +			error("empty declaration\n"); +	} else { +		error("unknown enumeration `%s'\n",  tag); +		ty = newstruct(ENUM, tag); +		ty->type = inttype; +	} +	if (*tag && xref) +		use(p, pos); +	return ty; +} + +Type typename(void) { +	Type ty = specifier(NULL); + +	if (t == '*' || t == '(' || t == '[') { +		ty = dclr(ty, NULL, NULL, 1); +		if (Aflag >= 1 && !hasproto(ty)) +			warning("missing prototype\n"); +	} +	return ty; +} + diff --git a/src/tools/lcc/src/enode.c b/src/tools/lcc/src/enode.c new file mode 100644 index 0000000..760096d --- /dev/null +++ b/src/tools/lcc/src/enode.c @@ -0,0 +1,545 @@ +#include "c.h" + + +static Tree addtree(int, Tree, Tree); +static Tree andtree(int, Tree, Tree); +static Tree cmptree(int, Tree, Tree); +static int compatible(Type, Type); +static int isnullptr(Tree e); +static Tree multree(int, Tree, Tree); +static Tree subtree(int, Tree, Tree); +#define isvoidptr(ty) \ +	(isptr(ty) && unqual(ty->type) == voidtype) + +Tree (*optree[])(int, Tree, Tree) = { +#define xx(a,b,c,d,e,f,g) e, +#define yy(a,b,c,d,e,f,g) e, +#include "token.h" +}; +Tree call(Tree f, Type fty, Coordinate src) { +	int n = 0; +	Tree args = NULL, r = NULL, e; +	Type *proto, rty = unqual(freturn(fty)); +	Symbol t3 = NULL; + +	if (fty->u.f.oldstyle) +		proto = NULL; +	else +		proto = fty->u.f.proto; +	if (hascall(f)) +		r = f; +	if (isstruct(rty)) +		{ +			t3 = temporary(AUTO, unqual(rty)); +			if (rty->size == 0) +				error("illegal use of incomplete type `%t'\n", rty); +		} +	if (t != ')') +		for (;;) { +			Tree q = pointer(expr1(0)); +			if (proto && *proto && *proto != voidtype) +				{ +					Type aty; +					q = value(q); +					aty = assign(*proto, q); +					if (aty) +						q = cast(q, aty); +					else +						error("type error in argument %d to %s; found `%t' expected `%t'\n", n + 1, funcname(f), + +							q->type, *proto); +					if ((isint(q->type) || isenum(q->type)) +					&& q->type->size != inttype->size) +						q = cast(q, promote(q->type)); +					++proto; +				} +			else +				{ +					if (!fty->u.f.oldstyle && *proto == NULL) +						error("too many arguments to %s\n", funcname(f)); +					q = value(q); +					if (isarray(q->type) || q->type->size == 0) +						error("type error in argument %d to %s; `%t' is illegal\n", n + 1, funcname(f), q->type); + +					else +						q = cast(q, promote(q->type)); +				} +			if (!IR->wants_argb && isstruct(q->type)) { +				if (iscallb(q)) +					q = addrof(q); +				else { +					Symbol t1 = temporary(AUTO, unqual(q->type)); +					q = asgn(t1, q); +					q = tree(RIGHT, ptr(t1->type), +						root(q), lvalue(idtree(t1))); +				} +			} +			if (q->type->size == 0) +				q->type = inttype; +			if (hascall(q)) +				r = r ? tree(RIGHT, voidtype, r, q) : q; +			args = tree(mkop(ARG, q->type), q->type, q, args); +			n++; +			if (Aflag >= 2 && n == 32) +				warning("more than 31 arguments in a call to %s\n", +					funcname(f)); +			if (t != ',') +				break; +			t = gettok(); +		} +	expect(')'); +	if (proto && *proto && *proto != voidtype) +		error("insufficient number of arguments to %s\n", +			funcname(f)); +	if (r) +		args = tree(RIGHT, voidtype, r, args); +	e = calltree(f, rty, args, t3); +	if (events.calls) +		apply(events.calls, &src, &e); +	return e; +} +Tree calltree(Tree f, Type ty, Tree args, Symbol t3) { +	Tree p; + +	if (args) +		f = tree(RIGHT, f->type, args, f); +	if (isstruct(ty)) +		assert(t3), +		p = tree(RIGHT, ty, +			tree(CALL+B, ty, f, addrof(idtree(t3))), +			idtree(t3)); +	else { +		Type rty = ty; +		if (isenum(ty)) +			rty = unqual(ty)->type; +		if (!isfloat(rty)) +			rty = promote(rty); +		p = tree(mkop(CALL, rty), rty, f, NULL); +		if (isptr(ty) || p->type->size > ty->size) +			p = cast(p, ty); +	} +	return p; +} +Tree vcall(Symbol func, Type ty, ...) { +	va_list ap; +	Tree args = NULL, e, f = pointer(idtree(func)), r = NULL; + +	assert(isfunc(func->type)); +	if (ty == NULL) +		ty = freturn(func->type); +	va_start(ap, ty); +	while ((e = va_arg(ap, Tree)) != NULL) { +		if (hascall(e)) +			r = r == NULL ? e : tree(RIGHT, voidtype, r, e); +		args = tree(mkop(ARG, e->type), e->type, e, args); +	} +	va_end(ap); +	if (r != NULL) +		args = tree(RIGHT, voidtype, r, args); +	return calltree(f, ty, args, NULL); +} +int iscallb(Tree e) { +	return e->op == RIGHT && e->kids[0] && e->kids[1] +		&& e->kids[0]->op == CALL+B +		&& e->kids[1]->op == INDIR+B +		&& isaddrop(e->kids[1]->kids[0]->op) +		&& e->kids[1]->kids[0]->u.sym->temporary; +} + +static Tree addtree(int op, Tree l, Tree r) { +	Type ty = inttype; + +	if (isarith(l->type) && isarith(r->type)) { +		ty = binary(l->type, r->type); +		l = cast(l, ty); +		r = cast(r, ty);		 +	} else if (isptr(l->type) && isint(r->type)) +		return addtree(ADD, r, l); +	else if (  isptr(r->type) && isint(l->type) +	&& !isfunc(r->type->type)) +		{ +			long n; +			ty = unqual(r->type); +			n = unqual(ty->type)->size; +			if (n == 0) +				error("unknown size for type `%t'\n", ty->type); +			l = cast(l, promote(l->type)); +			if (n > 1) +				l = multree(MUL, cnsttree(signedptr, n), l); +			if (YYcheck && !isaddrop(r->op))		/* omit */ +				return nullcall(ty, YYcheck, r, l);	/* omit */ +			return simplify(ADD, ty, l, r); +		} + +	else +		typeerror(op, l, r); +	return simplify(op, ty, l, r); +} + +Tree cnsttree(Type ty, ...) { +	Tree p = tree(mkop(CNST,ty), ty, NULL, NULL); +	va_list ap; + +	va_start(ap, ty); +	switch (ty->op) { +	case INT:     p->u.v.i = va_arg(ap, long); break; +	case UNSIGNED:p->u.v.u = va_arg(ap, unsigned long)&ones(8*ty->size); break; +	case FLOAT:   p->u.v.d = va_arg(ap, double); break; +	case POINTER: p->u.v.p = va_arg(ap, void *); break; +	default: assert(0); +	} +	va_end(ap); +	return p; +} + +Tree consttree(unsigned n, Type ty) { +	if (isarray(ty)) +		ty = atop(ty); +	else assert(isint(ty)); +	return cnsttree(ty, (unsigned long)n); +} +static Tree cmptree(int op, Tree l, Tree r) { +	Type ty; + +	if (isarith(l->type) && isarith(r->type)) { +		ty = binary(l->type, r->type); +		l = cast(l, ty); +		r = cast(r, ty); +	} else if (compatible(l->type, r->type)) { +		ty = unsignedptr; +		l = cast(l, ty); +		r = cast(r, ty); +	} else { +		ty = unsignedtype; +		typeerror(op, l, r); +	} +	return simplify(mkop(op,ty), inttype, l, r); +} +static int compatible(Type ty1, Type ty2) { +	return isptr(ty1) && !isfunc(ty1->type) +	    && isptr(ty2) && !isfunc(ty2->type) +	    && eqtype(unqual(ty1->type), unqual(ty2->type), 0); +} +static int isnullptr(Tree e) { +	Type ty = unqual(e->type); + +	return generic(e->op) == CNST +	    && ((ty->op == INT      && e->u.v.i == 0) +	     || (ty->op == UNSIGNED && e->u.v.u == 0) +	     || (isvoidptr(ty)      && e->u.v.p == NULL)); +} +Tree eqtree(int op, Tree l, Tree r) { +	Type xty = l->type, yty = r->type; + +	if ((isptr(xty) && isnullptr(r)) +	||  (isptr(xty) && !isfunc(xty->type) && isvoidptr(yty)) +	||  (isptr(xty) && isptr(yty) +	    && eqtype(unqual(xty->type), unqual(yty->type), 1))) { +		Type ty = unsignedptr; +		l = cast(l, ty); +		r = cast(r, ty); +		return simplify(mkop(op,ty), inttype, l, r); +	} +	if ((isptr(yty) && isnullptr(l)) +	||  (isptr(yty) && !isfunc(yty->type) && isvoidptr(xty))) +		return eqtree(op, r, l); +	return cmptree(op, l, r); +} + +Type assign(Type xty, Tree e) { +	Type yty = unqual(e->type); + +	xty = unqual(xty); +	if (isenum(xty)) +		xty = xty->type; +	if (xty->size == 0 || yty->size == 0) +		return NULL; +	if ( (isarith(xty) && isarith(yty)) +	||  (isstruct(xty) && xty == yty)) +		return xty; +	if (isptr(xty) && isnullptr(e)) +		return xty; +	if (((isvoidptr(xty) && isptr(yty)) +	  || (isptr(xty)     && isvoidptr(yty))) +	&& (  (isconst(xty->type)    || !isconst(yty->type)) +	   && (isvolatile(xty->type) || !isvolatile(yty->type)))) +		return xty; + +	if ((isptr(xty) && isptr(yty) +	    && eqtype(unqual(xty->type), unqual(yty->type), 1)) +	&&  (  (isconst(xty->type)    || !isconst(yty->type)) +	    && (isvolatile(xty->type) || !isvolatile(yty->type)))) +		return xty; +	if (isptr(xty) && isptr(yty) +	&& (  (isconst(xty->type)    || !isconst(yty->type)) +	   && (isvolatile(xty->type) || !isvolatile(yty->type)))) { +		Type lty = unqual(xty->type), rty = unqual(yty->type); +		if ((isenum(lty) && rty == inttype) +		||  (isenum(rty) && lty == inttype)) { +			if (Aflag >= 1) +				warning("assignment between `%t' and `%t' is compiler-dependent\n", +					xty, yty); +			return xty; +		} +	} +	return NULL; +} +Tree asgntree(int op, Tree l, Tree r) { +	Type aty, ty; + +	r = pointer(r); +	ty = assign(l->type, r); +	if (ty) +		r = cast(r, ty); +	else { +		typeerror(ASGN, l, r); +		if (r->type == voidtype) +			r = retype(r, inttype); +		ty = r->type; +	} +	if (l->op != FIELD) +		l = lvalue(l); +	aty = l->type; +	if (isptr(aty)) +		aty = unqual(aty)->type; +	if ( isconst(aty) +	||  (isstruct(aty) && unqual(aty)->u.sym->u.s.cfields)) { +		if (isaddrop(l->op) +		&& !l->u.sym->computed && !l->u.sym->generated) +			error("assignment to const identifier `%s'\n", +				l->u.sym->name); +		else +			error("assignment to const location\n"); +	} +	if (l->op == FIELD) { +		long n = 8*l->u.field->type->size - fieldsize(l->u.field); +		if (n > 0 && isunsigned(l->u.field->type)) +			r = bittree(BAND, r, +				cnsttree(r->type, (unsigned long)fieldmask(l->u.field))); +		else if (n > 0) { +			if (r->op == CNST+I) { +				n = r->u.v.i; +				if (n&(1<<(fieldsize(l->u.field)-1))) +					n |= ~0UL<<fieldsize(l->u.field); +				r = cnsttree(r->type, n); +			} else +				r = shtree(RSH, +					shtree(LSH, r, cnsttree(inttype, n)), +					cnsttree(inttype, n)); +		} +	} +	if (isstruct(ty) && isaddrop(l->op) && iscallb(r)) +		return tree(RIGHT, ty, +			tree(CALL+B, ty, r->kids[0]->kids[0], l), +			idtree(l->u.sym)); +	return tree(mkop(op,ty), ty, l, r); +} +Tree condtree(Tree e, Tree l, Tree r) { +	Symbol t1; +	Type ty, xty = l->type, yty = r->type; +	Tree p; + +	if (isarith(xty) && isarith(yty)) +		ty = binary(xty, yty); +	else if (eqtype(xty, yty, 1)) +		ty = unqual(xty); +	else if (isptr(xty)   && isnullptr(r)) +		ty = xty; +	else if (isnullptr(l) && isptr(yty)) +		ty = yty; +	else if ((isptr(xty) && !isfunc(xty->type) && isvoidptr(yty)) +	||       (isptr(yty) && !isfunc(yty->type) && isvoidptr(xty))) +		ty = voidptype; +	else if ((isptr(xty) && isptr(yty) +		 && eqtype(unqual(xty->type), unqual(yty->type), 1))) +		ty = xty; +	else { +		typeerror(COND, l, r); +		return consttree(0, inttype); +	} +	if (isptr(ty)) { +		ty = unqual(unqual(ty)->type); +		if ((isptr(xty) && isconst(unqual(xty)->type)) +		||  (isptr(yty) && isconst(unqual(yty)->type))) +			ty = qual(CONST, ty); +		if ((isptr(xty) && isvolatile(unqual(xty)->type)) +		||  (isptr(yty) && isvolatile(unqual(yty)->type))) +			ty = qual(VOLATILE, ty); +		ty = ptr(ty); +	} +	switch (e->op) { +	case CNST+I: return cast(e->u.v.i != 0   ? l : r, ty); +	case CNST+U: return cast(e->u.v.u != 0   ? l : r, ty); +	case CNST+P: return cast(e->u.v.p != 0   ? l : r, ty); +	case CNST+F: return cast(e->u.v.d != 0.0 ? l : r, ty); +	} +	if (ty != voidtype && ty->size > 0) { +		t1 = genident(REGISTER, unqual(ty), level); +	/*	t1 = temporary(REGISTER, unqual(ty)); */ +		l = asgn(t1, l); +		r = asgn(t1, r); +	} else +		t1 = NULL; +	p = tree(COND, ty, cond(e), +		tree(RIGHT, ty, root(l), root(r))); +	p->u.sym = t1; +	return p; +} +/* addrof - address of p */ +Tree addrof(Tree p) { +	Tree q = p; + +	for (;;) +		switch (generic(q->op)) { +		case RIGHT: +			assert(q->kids[0] || q->kids[1]); +			q = q->kids[1] ? q->kids[1] : q->kids[0]; +			continue; +		case ASGN: +			q = q->kids[1]; +			continue; +		case COND: { +			Symbol t1 = q->u.sym; +			q->u.sym = 0; +			q = idtree(t1); +			/* fall thru */ +			} +		case INDIR: +			if (p == q) +				return q->kids[0]; +			q = q->kids[0]; +			return tree(RIGHT, q->type, root(p), q); +		default: +			error("addressable object required\n"); +			return value(p); +		} +} + +/* andtree - construct tree for l [&& ||] r */ +static Tree andtree(int op, Tree l, Tree r) { +	if (!isscalar(l->type) || !isscalar(r->type)) +		typeerror(op, l, r); +	return simplify(op, inttype, cond(l), cond(r)); +} + +/* asgn - generate tree for assignment of expr e to symbol p sans qualifiers */ +Tree asgn(Symbol p, Tree e) { +	if (isarray(p->type)) +		e = tree(ASGN+B, p->type, idtree(p), +			tree(INDIR+B, e->type, e, NULL)); +	else { +		Type ty = p->type; +		p->type = unqual(p->type); +		if (isstruct(p->type) && p->type->u.sym->u.s.cfields) { +			p->type->u.sym->u.s.cfields = 0; +			e = asgntree(ASGN, idtree(p), e); +			p->type->u.sym->u.s.cfields = 1; +		} else +			e = asgntree(ASGN, idtree(p), e); +		p->type = ty; +	} +	return e; +} + +/* bittree - construct tree for l [& | ^ %] r */ +Tree bittree(int op, Tree l, Tree r) { +	Type ty = inttype; + +	if (isint(l->type) && isint(r->type)) { + 		ty = binary(l->type, r->type); +		l = cast(l, ty); +		r = cast(r, ty);		 +	} else +		typeerror(op, l, r); +	return simplify(op, ty, l, r); +} + +/* multree - construct tree for l [* /] r */ +static Tree multree(int op, Tree l, Tree r) { +	Type ty = inttype; + +	if (isarith(l->type) && isarith(r->type)) { +		ty = binary(l->type, r->type); +		l = cast(l, ty); +		r = cast(r, ty);		 +	} else +		typeerror(op, l, r); +	return simplify(op, ty, l, r); +} + +/* shtree - construct tree for l [>> <<] r */ +Tree shtree(int op, Tree l, Tree r) { +	Type ty = inttype; + +	if (isint(l->type) && isint(r->type)) { +		ty = promote(l->type); +		l = cast(l, ty); +		r = cast(r, inttype); +	} else +		typeerror(op, l, r); +	return simplify(op, ty, l, r); +} + +/* subtree - construct tree for l - r */ +static Tree subtree(int op, Tree l, Tree r) { +	long n; +	Type ty = inttype; + +	if (isarith(l->type) && isarith(r->type)) { +		ty = binary(l->type, r->type); +		l = cast(l, ty); +		r = cast(r, ty);		 +	} else if (isptr(l->type) && !isfunc(l->type->type) && isint(r->type)) { +		ty = unqual(l->type); +		n = unqual(ty->type)->size; +		if (n == 0) +			error("unknown size for type `%t'\n", ty->type); +		r = cast(r, promote(r->type)); +		if (n > 1) +			r = multree(MUL, cnsttree(signedptr, n), r); +		if (isunsigned(r->type)) +			r = cast(r, unsignedptr); +		else +			r = cast(r, signedptr); +		return simplify(SUB+P, ty, l, r); +	} else if (compatible(l->type, r->type)) { +		ty = unqual(l->type); +		n = unqual(ty->type)->size; +		if (n == 0) +			error("unknown size for type `%t'\n", ty->type); +		l = simplify(SUB+U, unsignedptr, +			cast(l, unsignedptr), cast(r, unsignedptr)); +		return simplify(DIV+I, longtype, +			cast(l, longtype), cnsttree(longtype, n)); +	} else +		typeerror(op, l, r); +	return simplify(op, ty, l, r); +} + +/* typeerror - issue "operands of op have illegal types `l' and `r'" */ +void typeerror(int op, Tree l, Tree r) { +	int i; +	static struct { int op; char *name; } ops[] = { +		{ASGN, "="},	{INDIR, "*"},	{NEG,  "-"}, +		{ADD,  "+"},	{SUB,   "-"},	{LSH,  "<<"}, +		{MOD,  "%"},	{RSH,   ">>"},	{BAND, "&"}, +		{BCOM, "~"},	{BOR,   "|"},	{BXOR, "^"}, +		{DIV,  "/"},	{MUL,   "*"},	{EQ,   "=="}, +		{GE,   ">="},	{GT,    ">"},	{LE,   "<="}, +		{LT,   "<"},	{NE,    "!="},	{AND,  "&&"}, +		{NOT,  "!"},	{OR,    "||"},	{COND, "?:"}, +		{0, 0} +	}; + +	op = generic(op); +	for (i = 0; ops[i].op; i++) +		if (op == ops[i].op) +			break; +	assert(ops[i].name); +	if (r) +		error("operands of %s have illegal types `%t' and `%t'\n", +			ops[i].name, l->type, r->type); +	else +		error("operand of unary %s has illegal type `%t'\n", ops[i].name, +			l->type); +} diff --git a/src/tools/lcc/src/error.c b/src/tools/lcc/src/error.c new file mode 100644 index 0000000..2187c10 --- /dev/null +++ b/src/tools/lcc/src/error.c @@ -0,0 +1,137 @@ +#include "c.h" + + +static void printtoken(void); +int errcnt   = 0; +int errlimit = 20; +char kind[] = { +#define xx(a,b,c,d,e,f,g) f, +#define yy(a,b,c,d,e,f,g) f, +#include "token.h" +}; +int wflag;		/* != 0 to suppress warning messages */ + +void test(int tok, char set[]) { +	if (t == tok) +		t = gettok(); +	else { +		expect(tok); +		skipto(tok, set); +		if (t == tok) +			t = gettok(); +	} +} +void expect(int tok) { +	if (t == tok) +		t = gettok(); +	else { +		error("syntax error; found"); +		printtoken(); +		fprint(stderr, " expecting `%k'\n", tok); +	} +} +void error(const char *fmt, ...) { +	va_list ap; + +	if (errcnt++ >= errlimit) { +		errcnt = -1; +		error("too many errors\n"); +		exit(1); +	} +	va_start(ap, fmt); +	if (firstfile != file && firstfile && *firstfile) +		fprint(stderr, "%s: ", firstfile); +	fprint(stderr, "%w: ", &src); +	vfprint(stderr, NULL, fmt, ap); +	va_end(ap); +} + +void skipto(int tok, char set[]) { +	int n; +	char *s; + +	assert(set); +	for (n = 0; t != EOI && t != tok; t = gettok()) { +		for (s = set; *s && kind[t] != *s; s++) +			; +		if (kind[t] == *s) +			break; +		if (n++ == 0) +			error("skipping"); +		if (n <= 8) +			printtoken(); +		else if (n == 9) +			fprint(stderr, " ..."); +	} +	if (n > 8) { +		fprint(stderr, " up to"); +		printtoken(); +	} +	if (n > 0) +		fprint(stderr, "\n"); +} +/* fatal - issue fatal error message and exit */ +int fatal(const char *name, const char *fmt, int n) { +	print("\n"); +	errcnt = -1; +	error("compiler error in %s--", name); +	fprint(stderr, fmt, n); +	exit(EXIT_FAILURE); +	return 0; +} + +/* printtoken - print current token preceeded by a space */ +static void printtoken(void) { +	switch (t) { +	case ID: fprint(stderr, " `%s'", token); break; +	case ICON: +		fprint(stderr, " `%s'", vtoa(tsym->type, tsym->u.c.v)); +		break; +	case SCON: { +		int i, n; +		if (ischar(tsym->type->type)) { +			char *s = tsym->u.c.v.p; +			n = tsym->type->size; +			fprint(stderr, " \""); +			for (i = 0; i < 20 && i < n && *s; s++, i++) +				if (*s < ' ' || *s >= 0177) +					fprint(stderr, "\\%o", *s); +				else +					fprint(stderr, "%c", *s); +		} else {	/* wchar_t string */ +			unsigned int *s = tsym->u.c.v.p; +			assert(tsym->type->type->size == widechar->size); +			n = tsym->type->size/widechar->size; +			fprint(stderr, " L\""); +			for (i = 0; i < 20 && i < n && *s; s++, i++) +				if (*s < ' ' || *s >= 0177) +					fprint(stderr, "\\x%x", *s); +				else +					fprint(stderr, "%c", *s); +		} +		if (i < n) +			fprint(stderr, " ..."); +		else +			fprint(stderr, "\""); +		break; +		} +	case FCON: +		fprint(stderr, " `%S'", token, (char*)cp - token); +		break; +	case '`': case '\'': fprint(stderr, " \"%k\"", t); break; +	default: fprint(stderr, " `%k'", t); +	} +} + +/* warning - issue warning error message */ +void warning(const char *fmt, ...) { +	va_list ap; + +	va_start(ap, fmt); +	if (wflag == 0) { +		errcnt--; +		error("warning: "); +		vfprint(stderr, NULL, fmt, ap); +	} +	va_end(ap); +} diff --git a/src/tools/lcc/src/event.c b/src/tools/lcc/src/event.c new file mode 100644 index 0000000..4549e3f --- /dev/null +++ b/src/tools/lcc/src/event.c @@ -0,0 +1,28 @@ +#include "c.h" + + +struct entry { +	Apply func; +	void *cl; +}; + +Events events; +void attach(Apply func, void *cl, List *list) { +	struct entry *p; + +	NEW(p, PERM); +	p->func = func; +	p->cl = cl; +	*list = append(p, *list); +} +void apply(List event, void *arg1, void *arg2) { +	if (event) { +		List lp = event; +		do { +			struct entry *p = lp->x; +			(*p->func)(p->cl, arg1, arg2); +			lp = lp->link; +		} while (lp != event); +	} +} + diff --git a/src/tools/lcc/src/expr.c b/src/tools/lcc/src/expr.c new file mode 100644 index 0000000..b8cb08b --- /dev/null +++ b/src/tools/lcc/src/expr.c @@ -0,0 +1,711 @@ +#include "c.h" + + +static char prec[] = { +#define xx(a,b,c,d,e,f,g) c, +#define yy(a,b,c,d,e,f,g) c, +#include "token.h" +}; +static int oper[] = { +#define xx(a,b,c,d,e,f,g) d, +#define yy(a,b,c,d,e,f,g) d, +#include "token.h" +}; +float refinc = 1.0; +static Tree expr2(void); +static Tree expr3(int); +static Tree nullcheck(Tree); +static Tree postfix(Tree); +static Tree unary(void); +static Tree primary(void); +static Type super(Type ty); + +static Type super(Type ty) { +	switch (ty->op) { +	case INT: +		if (ty->size < inttype->size) +			return inttype; +		break; +	case UNSIGNED: +		if (ty->size < unsignedtype->size) +			return unsignedtype; +		break; +	case POINTER: +		return unsignedptr; +	} +	return ty; +} +Tree expr(int tok) { +	static char stop[] = { IF, ID, '}', 0 }; +	Tree p = expr1(0); + +	while (t == ',') { +		Tree q; +		t = gettok(); +		q = pointer(expr1(0)); +		p = tree(RIGHT, q->type, root(value(p)), q); +	} +	if (tok)	 +		test(tok, stop); +	return p; +} +Tree expr0(int tok) { +	return root(expr(tok)); +} +Tree expr1(int tok) { +	static char stop[] = { IF, ID, 0 }; +	Tree p = expr2(); + +	if (t == '=' +	|| (prec[t] >=  6 && prec[t] <=  8) +	|| (prec[t] >= 11 && prec[t] <= 13)) { +		int op = t; +		t = gettok(); +		if (oper[op] == ASGN) +			p = asgntree(ASGN, p, value(expr1(0))); +		else +			{ +				expect('='); +				p = incr(op, p, expr1(0)); +			} +	} +	if (tok)	 +		test(tok, stop); +	return p; +} +Tree incr(int op, Tree v, Tree e) { +	return asgntree(ASGN, v, (*optree[op])(oper[op], v, e)); +} +static Tree expr2(void) { +	Tree p = expr3(4); + +	if (t == '?') { +		Tree l, r; +		Coordinate pts[2]; +		if (Aflag > 1 && isfunc(p->type)) +			warning("%s used in a conditional expression\n", +				funcname(p)); +		p = pointer(p); +		t = gettok(); +		pts[0] = src; +		l = pointer(expr(':')); +		pts[1] = src; +		r = pointer(expr2()); +		if (events.points) +			{ +				apply(events.points, &pts[0], &l); +				apply(events.points, &pts[1], &r); +			} +		p = condtree(p, l, r); +	} +	return p; +} +Tree value(Tree p) { +	int op = generic(rightkid(p)->op); + +	if (p->type != voidtype +	&& (op==AND || op==OR || op==NOT || op==EQ || op==NE +	||  op== LE || op==LT || op== GE || op==GT)) +		p = condtree(p, consttree(1, inttype), +			consttree(0, inttype)); +	return p; +} +static Tree expr3(int k) { +	int k1; +	Tree p = unary(); + +	for (k1 = prec[t]; k1 >= k; k1--) +		while (prec[t] == k1 && *cp != '=') { +			Tree r; +			Coordinate pt; +			int op = t; +			t = gettok(); +			pt = src; +			p = pointer(p); +			if (op == ANDAND || op == OROR) { +				r = pointer(expr3(k1)); +				if (events.points) +					apply(events.points, &pt, &r); +			} else +				r = pointer(expr3(k1 + 1)); +			p = (*optree[op])(oper[op], p, r);  +		} +	return p; +} +static Tree unary(void) { +	Tree p; + +	switch (t) { +	case '*':    t = gettok(); p = unary(); p = pointer(p); +						  if (isptr(p->type) +						  && (isfunc(p->type->type) || isarray(p->type->type))) +						  	p = retype(p, p->type->type); +						  else { +						  	if (YYnull) +						  		p = nullcheck(p); +						  	p = rvalue(p); +						  } break; +	case '&':    t = gettok(); p = unary(); if (isarray(p->type) || isfunc(p->type)) +						  	p = retype(p, ptr(p->type)); +						  else +						  	p = lvalue(p); +						  if (isaddrop(p->op) && p->u.sym->sclass == REGISTER) +						  	error("invalid operand of unary &; `%s' is declared register\n", p->u.sym->name); + +						  else if (isaddrop(p->op)) +						  	p->u.sym->addressed = 1; + break; +	case '+':    t = gettok(); p = unary(); p = pointer(p); +						  if (isarith(p->type)) +						  	p = cast(p, promote(p->type)); +						  else +						  	typeerror(ADD, p, NULL);  break; +	case '-':    t = gettok(); p = unary(); p = pointer(p); +						  if (isarith(p->type)) { +						  	Type ty = promote(p->type); +						  	p = cast(p, ty); +						  	if (isunsigned(ty)) { +						  		warning("unsigned operand of unary -\n"); +						  		p = simplify(ADD, ty, simplify(BCOM, ty, p, NULL), cnsttree(ty, 1UL)); +						  	} else +						  		p = simplify(NEG, ty, p, NULL); +						  } else +						  	typeerror(SUB, p, NULL); break; +	case '~':    t = gettok(); p = unary(); p = pointer(p); +						  if (isint(p->type)) { +						  	Type ty = promote(p->type); +						  	p = simplify(BCOM, ty, cast(p, ty), NULL); +						  } else +						  	typeerror(BCOM, p, NULL);  break; +	case '!':    t = gettok(); p = unary(); p = pointer(p); +						  if (isscalar(p->type)) +						  	p = simplify(NOT, inttype, cond(p), NULL); +						  else +						  	typeerror(NOT, p, NULL); break; +	case INCR:   t = gettok(); p = unary(); p = incr(INCR, pointer(p), consttree(1, inttype)); break; +	case DECR:   t = gettok(); p = unary(); p = incr(DECR, pointer(p), consttree(1, inttype)); break; +	case TYPECODE: case SIZEOF: { int op = t; +				      Type ty; +				      p = NULL; +				      t = gettok(); +				      if (t == '(') { +				      	t = gettok(); +				      	if (istypename(t, tsym)) { +				      		ty = typename(); +				      		expect(')'); +				      	} else { +				      		p = postfix(expr(')')); +				      		ty = p->type; +				      	} +				      } else { +				      	p = unary(); +				      	ty = p->type; +				      } +				      assert(ty); +				      if (op == TYPECODE) +				      	p = cnsttree(inttype, (long)ty->op); +				      else { +				      	if (isfunc(ty) || ty->size == 0) +				      		error("invalid type argument `%t' to `sizeof'\n", ty); +				      	else if (p && rightkid(p)->op == FIELD) +				      		error("`sizeof' applied to a bit field\n"); +				      	p = cnsttree(unsignedlong, (unsigned long)ty->size); +				      } } break; +	case '(': +		t = gettok(); +		if (istypename(t, tsym)) { +			Type ty, ty1 = typename(), pty; +			expect(')'); +			ty = unqual(ty1); +			if (isenum(ty)) { +				Type ty2 = ty->type; +				if (isconst(ty1)) +					ty2 = qual(CONST, ty2); +				if (isvolatile(ty1)) +					ty2 = qual(VOLATILE, ty2); +				ty1 = ty2; +				ty = ty->type; +			} +			p = pointer(unary()); +			pty = p->type; +			if (isenum(pty)) +				pty = pty->type; +			if ((isarith(pty) && isarith(ty)) +			||  (isptr(pty)   && isptr(ty))) { +				explicitCast++; +				p = cast(p, ty); +				explicitCast--; +			} else if ((isptr(pty) && isint(ty)) +			||       (isint(pty) && isptr(ty))) { +				if (Aflag >= 1 && ty->size < pty->size) +					warning("conversion from `%t' to `%t' is compiler dependent\n", p->type, ty); + +				p = cast(p, ty); +			} else if (ty != voidtype) { +				error("cast from `%t' to `%t' is illegal\n", +					p->type, ty1); +				ty1 = inttype; +			} +			if (generic(p->op) == INDIR || ty->size == 0) +				p = tree(RIGHT, ty1, NULL, p); +			else +				p = retype(p, ty1); +		} else +			p = postfix(expr(')')); +		break; +	default: +		p = postfix(primary()); +	} +	return p; +} + +static Tree postfix(Tree p) { +	for (;;) +		switch (t) { +		case INCR:  p = tree(RIGHT, p->type, +			    	tree(RIGHT, p->type, +			    		p, +			    		incr(t, p, consttree(1, inttype))), +			    	p); +			    t = gettok(); break; +		case DECR:  p = tree(RIGHT, p->type, +			    	tree(RIGHT, p->type, +			    		p, +			    		incr(t, p, consttree(1, inttype))), +			    	p); +			    t = gettok(); break; +		case '[':   { +			    	Tree q; +			    	t = gettok(); +			    	q = expr(']'); +			    	if (YYnull) { +			    		if (isptr(p->type)) +			    			p = nullcheck(p); +			    		else if (isptr(q->type)) +			    			q = nullcheck(q); +			    	} +			    	p = (*optree['+'])(ADD, pointer(p), pointer(q)); +			    	if (isptr(p->type) && isarray(p->type->type)) +			    		p = retype(p, p->type->type); +			    	else +			    		p = rvalue(p); +			    } break; +		case '(':   { +			    	Type ty; +			    	Coordinate pt; +			    	p = pointer(p); +			    	if (isptr(p->type) && isfunc(p->type->type)) +			    		ty = p->type->type; +			    	else { +			    		error("found `%t' expected a function\n", p->type); +			    		ty = func(voidtype, NULL, 1); +			    		p = retype(p, ptr(ty)); +			    	} +			    	pt = src; +			    	t = gettok(); +			    	p = call(p, ty, pt); +			    } break; +		case '.':   t = gettok(); +			    if (t == ID) { +			    	if (isstruct(p->type)) { +			    		Tree q = addrof(p); +			    		p = field(q, token); +			    		q = rightkid(q); +			    		if (isaddrop(q->op) && q->u.sym->temporary) +			    			p = tree(RIGHT, p->type, p, NULL); +			    	} else +			    		error("left operand of . has incompatible type `%t'\n", +			    			p->type); +			    	t = gettok(); +			    } else +			    	error("field name expected\n"); break; +		case DEREF: t = gettok(); +			    p = pointer(p); +			    if (t == ID) { +			    	if (isptr(p->type) && isstruct(p->type->type)) { +			    		if (YYnull) +			    			p = nullcheck(p); +			    		p = field(p, token); +			    	} else +			    		error("left operand of -> has incompatible type `%t'\n", p->type); + +			    	t = gettok(); +			    } else +			    	error("field name expected\n"); break; +		default: +			return p; +		} +} +static Tree primary(void) { +	Tree p; + +	assert(t != '('); +	switch (t) { +	case ICON: +	case FCON: p = tree(mkop(CNST,tsym->type), tsym->type, NULL, NULL); +		   p->u.v = tsym->u.c.v; + break; +	case SCON: if (ischar(tsym->type->type)) +		   	tsym->u.c.v.p = stringn(tsym->u.c.v.p, tsym->type->size); +		   else +		   	tsym->u.c.v.p = memcpy(allocate(tsym->type->size, PERM), tsym->u.c.v.p, tsym->type->size); +		   tsym = constant(tsym->type, tsym->u.c.v);  +		   if (tsym->u.c.loc == NULL) +		   	tsym->u.c.loc = genident(STATIC, tsym->type, GLOBAL); +		   p = idtree(tsym->u.c.loc); break; +	case ID:   if (tsym == NULL) +		   	{ +				Symbol p = install(token, &identifiers, level, FUNC); +				p->src = src; +				if (getchr() == '(') { +					Symbol q = lookup(token, externals); +					p->type = func(inttype, NULL, 1); +					p->sclass = EXTERN; +					if (Aflag >= 1) +						warning("missing prototype\n"); +					if (q && !eqtype(q->type, p->type, 1)) +						warning("implicit declaration of `%s' does not match previous declaration at %w\n", q->name, &q->src); + +					if (q == NULL) { +						q = install(p->name, &externals, GLOBAL, PERM); +						q->type = p->type; +						q->sclass = EXTERN; +						q->src = src; +						(*IR->defsymbol)(q); +					} +					p->u.alias = q; +				} else { +					error("undeclared identifier `%s'\n", p->name); +					p->sclass = AUTO; +					p->type = inttype; +					if (p->scope == GLOBAL) +						(*IR->defsymbol)(p); +					else +						addlocal(p); +				} +				t = gettok(); +				if (xref) +					use(p, src); +				return idtree(p); +			} +		   if (xref) +		   	use(tsym, src); +		   if (tsym->sclass == ENUM) +		   	p = consttree(tsym->u.value, inttype); +		   else { +		   	if (tsym->sclass == TYPEDEF) +		   		error("illegal use of type name `%s'\n", tsym->name); +		   	p = idtree(tsym); +		   } break; +	case FIRSTARG: +		if (level > PARAM && cfunc && cfunc->u.f.callee[0]) +			p = idtree(cfunc->u.f.callee[0]); +		else { +			error("illegal use of `%k'\n", FIRSTARG); +			p = cnsttree(inttype, 0L); +		} +		break; +	default: +		error("illegal expression\n"); +			p = cnsttree(inttype, 0L); +	} +	t = gettok(); +	return p; +} +Tree idtree(Symbol p) { +	int op; +	Tree e; +	Type ty = p->type ? unqual(p->type) : voidptype; + +	if (p->scope == GLOBAL || p->sclass == STATIC) +		op = ADDRG; +	else if (p->scope == PARAM) { +		op = ADDRF; +		if (isstruct(p->type) && !IR->wants_argb) +			{ +				e = tree(mkop(op,voidptype), ptr(ptr(p->type)), NULL, NULL); +				e->u.sym = p; +				return rvalue(rvalue(e)); +			} +	} else if (p->sclass == EXTERN) { +		assert(p->u.alias); +		p = p->u.alias; +		op = ADDRG; +	} else +		op = ADDRL; +	p->ref += refinc; +	if (isarray(ty)) +		e = tree(mkop(op,voidptype), p->type,      NULL, NULL); +	else if (isfunc(ty)) +		e = tree(mkop(op,funcptype), p->type,      NULL, NULL); +	else +		e = tree(mkop(op,voidptype), ptr(p->type), NULL, NULL); +	e->u.sym = p; +	if (isptr(e->type)) +		e = rvalue(e); +	return e; +} + +Tree rvalue(Tree p) { +	Type ty = deref(p->type); + +	ty = unqual(ty); +	return tree(mkop(INDIR,ty), ty, p, NULL); +} +Tree lvalue(Tree p) { +	if (generic(p->op) != INDIR) { +		error("lvalue required\n"); +		return value(p); +	} else if (unqual(p->type) == voidtype) +		warning("`%t' used as an lvalue\n", p->type); +	return p->kids[0]; +} +Tree retype(Tree p, Type ty) { +	Tree q; + +	if (p->type == ty) +		return p; +	q = tree(p->op, ty, p->kids[0], p->kids[1]); +	q->node = p->node; +	q->u = p->u; +	return q; +} +Tree rightkid(Tree p) { +	while (p && p->op == RIGHT) +		if (p->kids[1]) +			p = p->kids[1]; +		else if (p->kids[0]) +			p = p->kids[0]; +		else +			assert(0); +	assert(p); +	return p; +} +int hascall(Tree p) { +	if (p == 0) +		return 0; +	if (generic(p->op) == CALL || (IR->mulops_calls && +	  (p->op == DIV+I || p->op == MOD+I || p->op == MUL+I +	|| p->op == DIV+U || p->op == MOD+U || p->op == MUL+U))) +		return 1; +	return hascall(p->kids[0]) || hascall(p->kids[1]); +} +Type binary(Type xty, Type yty) { +#define xx(t) if (xty == t || yty == t) return t +	xx(longdouble); +	xx(doubletype); +	xx(floattype); +	xx(unsignedlonglong); +	xx(longlong); +	xx(unsignedlong); +	if ((xty == longtype     && yty == unsignedtype) +	||  (xty == unsignedtype && yty == longtype)) { +		if (longtype->size > unsignedtype->size) +			return longtype; +		else +			return unsignedlong; +	} +	xx(longtype); +	xx(unsignedtype); +	return inttype; +#undef xx +} +Tree pointer(Tree p) { +	if (isarray(p->type)) +		/* assert(p->op != RIGHT || p->u.sym == NULL), */ +		p = retype(p, atop(p->type)); +	else if (isfunc(p->type)) +		p = retype(p, ptr(p->type)); +	return p; +} +Tree cond(Tree p) { +	int op = generic(rightkid(p)->op); + +	if (op == AND || op == OR || op == NOT +	||  op == EQ  || op == NE +	||  op == LE  || op == LT || op == GE || op == GT) +		return p; +	p = pointer(p); +	return (*optree[NEQ])(NE, p, consttree(0, inttype)); +} +Tree cast(Tree p, Type type) { +	Type src, dst; + +	p = value(p); +	if (p->type == type) +		return p; +	dst = unqual(type); +	src = unqual(p->type); +	if (src->op != dst->op || src->size != dst->size) { +		switch (src->op) { +		case INT: +			if (src->size < inttype->size) +				p = simplify(CVI, inttype, p, NULL); +			break; +		case UNSIGNED: +			if (src->size < inttype->size) +				p = simplify(CVU, inttype, p, NULL); +			else if (src->size < unsignedtype->size) +				p = simplify(CVU, unsignedtype, p, NULL); +			break; +		case ENUM: +			p = retype(p, inttype); +			break; +		case POINTER: +			if (isint(dst) && src->size > dst->size) +				warning("conversion from `%t' to `%t' is undefined\n", p->type, type); +			p = simplify(CVP, super(src), p, NULL); +			break; +		case FLOAT: +			break; +		default: assert(0); +		} +		{ +			src = unqual(p->type); +			dst = super(dst); +			if (src->op != dst->op) +				switch (src->op) { +				case INT: +					p = simplify(CVI, dst, p, NULL); +					break; +				case UNSIGNED: +					if (isfloat(dst)) { +						Type ssrc = signedint(src); +						Tree two = cnsttree(longdouble, (double)2.0); +						p = (*optree['+'])(ADD, +							(*optree['*'])(MUL, +								two, +								simplify(CVU, ssrc, +									simplify(RSH, src, +										p, consttree(1, inttype)), NULL)), +							simplify(CVU, ssrc, +								simplify(BAND, src, +									p, consttree(1, unsignedtype)), NULL)); +					} else +						p = simplify(CVU, dst, p, NULL); +					break; +				case FLOAT: +					if (isunsigned(dst)) { +						Type sdst = signedint(dst); +						Tree c = cast(cnsttree(longdouble, (double)sdst->u.sym->u.limits.max.i + 1), src); +						p = condtree( +							simplify(GE, src, p, c), +							(*optree['+'])(ADD, +								cast(cast(simplify(SUB, src, p, c), sdst), dst), +								cast(cnsttree(unsignedlong, (unsigned long)sdst->u.sym->u.limits.max.i + 1), dst)), +							simplify(CVF, sdst, p, NULL)); +					} else +						p = simplify(CVF, dst, p, NULL); +					break; +				default: assert(0); +				} +			dst = unqual(type); +		} +	} +	src = unqual(p->type); +	switch (src->op) { +	case INT: +		if (src->op != dst->op || src->size != dst->size) +			p = simplify(CVI, dst, p, NULL); +		break; +	case UNSIGNED: +		if (src->op != dst->op || src->size != dst->size) +			p = simplify(CVU, dst, p, NULL); +		break; +	case FLOAT: +		if (src->op != dst->op || src->size != dst->size) +			p = simplify(CVF, dst, p, NULL); +		break; +	case POINTER: +		if (src->op != dst->op) +			p = simplify(CVP, dst, p, NULL); +		else { +			if ((isfunc(src->type) && !isfunc(dst->type)) +			|| (!isfunc(src->type) &&  isfunc(dst->type))) +				warning("conversion from `%t' to `%t' is compiler dependent\n", p->type, type); + +			if (src->size != dst->size) +				p = simplify(CVP, dst, p, NULL); +		} +		break; +	default: assert(0); +	} +	return retype(p, type); +} +Tree field(Tree p, const char *name) { +	Field q; +	Type ty1, ty = p->type; + +	if (isptr(ty)) +		ty = deref(ty); +	ty1 = ty; +	ty = unqual(ty); +	if ((q = fieldref(name, ty)) != NULL) { +		if (isarray(q->type)) { +			ty = q->type->type; +			if (isconst(ty1) && !isconst(ty)) +				ty = qual(CONST, ty); +			if (isvolatile(ty1) && !isvolatile(ty)) +				ty = qual(VOLATILE, ty); +			ty = array(ty, q->type->size/ty->size, q->type->align); +		} else { +			ty = q->type; +			if (isconst(ty1) && !isconst(ty)) +				ty = qual(CONST, ty); +			if (isvolatile(ty1) && !isvolatile(ty)) +				ty = qual(VOLATILE, ty); +			ty = ptr(ty); +		} +		if (YYcheck && !isaddrop(p->op) && q->offset > 0)	/* omit */ +			p = nullcall(ty, YYcheck, p, consttree(q->offset, inttype));	/* omit */ +		else					/* omit */ +		p = simplify(ADD+P, ty, p, consttree(q->offset, inttype)); + +		if (q->lsb) { +			p = tree(FIELD, ty->type, rvalue(p), NULL); +			p->u.field = q; +		} else if (!isarray(q->type)) +			p = rvalue(p); + +	} else { +		error("unknown field `%s' of `%t'\n", name, ty); +		p = rvalue(retype(p, ptr(inttype))); +	} +	return p; +} +/* funcname - return name of function f or a function' */ +char *funcname(Tree f) { +	if (isaddrop(f->op)) +		return stringf("`%s'", f->u.sym->name); +	return "a function"; +} +static Tree nullcheck(Tree p) { +	if (!needconst && YYnull && isptr(p->type)) { +		p = value(p); +		if (strcmp(YYnull->name, "_YYnull") == 0) { +			Symbol t1 = temporary(REGISTER, voidptype); +			p = tree(RIGHT, p->type, +				tree(OR, voidtype, +					cond(asgn(t1, cast(p, voidptype))), +					vcall(YYnull, voidtype,	(file && *file ? pointer(idtree(mkstr(file)->u.c.loc)) : cnsttree(voidptype, NULL)), cnsttree(inttype, (long)lineno)		, NULL)), +				idtree(t1)); +		} + +		else +			p = nullcall(p->type, YYnull, p, cnsttree(inttype, 0L)); + +	} +	return p; +} +Tree nullcall(Type pty, Symbol f, Tree p, Tree e) { +	Type ty; + +	if (isarray(pty)) +		return retype(nullcall(atop(pty), f, p, e), pty); +	ty = unqual(unqual(p->type)->type); +	return vcall(f, pty, +		p, e, +		cnsttree(inttype, (long)ty->size), +		cnsttree(inttype, (long)ty->align), +		(file && *file ? pointer(idtree(mkstr(file)->u.c.loc)) : cnsttree(voidptype, NULL)), cnsttree(inttype, (long)lineno)		, NULL); +} diff --git a/src/tools/lcc/src/gen.c b/src/tools/lcc/src/gen.c new file mode 100644 index 0000000..4ee170d --- /dev/null +++ b/src/tools/lcc/src/gen.c @@ -0,0 +1,830 @@ +#include "c.h" + + +#define readsreg(p) \ +	(generic((p)->op)==INDIR && (p)->kids[0]->op==VREG+P) +#define setsrc(d) ((d) && (d)->x.regnode && \ +	(d)->x.regnode->set == src->x.regnode->set && \ +	(d)->x.regnode->mask&src->x.regnode->mask) + +#define relink(a, b) ((b)->x.prev = (a), (a)->x.next = (b)) + +static Symbol   askfixedreg(Symbol); +static Symbol   askreg(Symbol, unsigned*); +static void     blkunroll(int, int, int, int, int, int, int[]); +static void     docall(Node); +static void     dumpcover(Node, int, int); +static void     dumpregs(char *, char *, char *); +static void     dumprule(int); +static void     dumptree(Node); +static unsigned	emitasm(Node, int); +static void     genreload(Node, Symbol, int); +static void     genspill(Symbol, Node, Symbol); +static Symbol   getreg(Symbol, unsigned*, Node); +static int      getrule(Node, int); +static void     linearize(Node, Node); +static int      moveself(Node); +static void     prelabel(Node); +static Node*    prune(Node, Node*); +static void     putreg(Symbol); +static void     ralloc(Node); +static void     reduce(Node, int); +static int      reprune(Node*, int, int, Node); +static int      requate(Node); +static Node     reuse(Node, int); +static void     rewrite(Node); +static Symbol   spillee(Symbol, unsigned mask[], Node); +static void     spillr(Symbol, Node); +static int      uses(Node, Regnode); + +int offset; + +int maxoffset; + +int framesize; +int argoffset; + +int maxargoffset; + +int dalign, salign; +int bflag = 0;  /* omit */ +int dflag = 0; + +int swap; + +unsigned (*emitter)(Node, int) = emitasm; +static char NeedsReg[] = { +	0,                      /* unused */ +	1,                      /* CNST */ +	0, 0,                   /* ARG ASGN */ +	1,                      /* INDIR  */ +	0, 0, 1, 1,             /*  -  - CVF CVI */ +	1, 0, 1, 1,             /* CVP - CVU NEG */ +	1,                      /* CALL */ +	1,                      /* LOAD */ +	0,                      /* RET */ +	1, 1, 1,                /* ADDRG ADDRF ADDRL */ +	1, 1, 1, 1, 1,          /* ADD SUB LSH MOD RSH */ +	1, 1, 1, 1,             /* BAND BCOM BOR BXOR */ +	1, 1,                   /* DIV MUL */ +	0, 0, 0, 0, 0, 0,       /* EQ GE GT LE LT NE */ +	0, 0                   /* JUMP LABEL   */ +}; +Node head; + +unsigned freemask[2]; +unsigned usedmask[2]; +unsigned tmask[2]; +unsigned vmask[2]; +Symbol mkreg(char *fmt, int n, int mask, int set) { +	Symbol p; + +	NEW0(p, PERM); +	p->name = p->x.name = stringf(fmt, n); +	NEW0(p->x.regnode, PERM); +	p->x.regnode->number = n; +	p->x.regnode->mask = mask<<n; +	p->x.regnode->set = set; +	return p; +} +Symbol mkwildcard(Symbol *syms) { +	Symbol p; + +	NEW0(p, PERM); +	p->name = p->x.name = "wildcard"; +	p->x.wildcard = syms; +	return p; +} +void mkauto(Symbol p) { +	assert(p->sclass == AUTO); +	offset = roundup(offset + p->type->size, p->type->align); +	p->x.offset = -offset; +	p->x.name = stringd(-offset); +} +void blockbeg(Env *e) { +	e->offset = offset; +	e->freemask[IREG] = freemask[IREG]; +	e->freemask[FREG] = freemask[FREG]; +} +void blockend(Env *e) { +	if (offset > maxoffset) +		maxoffset = offset; +	offset = e->offset; +	freemask[IREG] = e->freemask[IREG]; +	freemask[FREG] = e->freemask[FREG]; +} +int mkactual(int align, int size) { +	int n = roundup(argoffset, align); + +	argoffset = n + size; +	return n; +} +static void docall(Node p) { +	p->syms[1] = p->syms[0]; +	p->syms[0] = intconst(argoffset); +	if (argoffset > maxargoffset) +		maxargoffset = argoffset; +	argoffset = 0; +} +void blkcopy(int dreg, int doff, int sreg, int soff, int size, int tmp[]) { +	assert(size >= 0); +	if (size == 0) +		return; +	else if (size <= 2) +		blkunroll(size, dreg, doff, sreg, soff, size, tmp); +	else if (size == 3) { +		blkunroll(2, dreg, doff,   sreg, soff,   2, tmp); +		blkunroll(1, dreg, doff+2, sreg, soff+2, 1, tmp); +	} +	else if (size <= 16) { +		blkunroll(4, dreg, doff, sreg, soff, size&~3, tmp); +		blkcopy(dreg, doff+(size&~3), +	                sreg, soff+(size&~3), size&3, tmp); +	} +	else +		(*IR->x.blkloop)(dreg, doff, sreg, soff, size, tmp); +} +static void blkunroll(int k, int dreg, int doff, int sreg, int soff, int size, int tmp[]) { +	int i; + +	assert(IR->x.max_unaligned_load); +	if (k > IR->x.max_unaligned_load +	&& (k > salign || k > dalign)) +		k = IR->x.max_unaligned_load; +	for (i = 0; i+k < size; i += 2*k) { +		(*IR->x.blkfetch)(k, soff+i,   sreg, tmp[0]); +		(*IR->x.blkfetch)(k, soff+i+k, sreg, tmp[1]); +		(*IR->x.blkstore)(k, doff+i,   dreg, tmp[0]); +		(*IR->x.blkstore)(k, doff+i+k, dreg, tmp[1]); +	} +	if (i < size) { +		(*IR->x.blkfetch)(k, i+soff, sreg, tmp[0]); +		(*IR->x.blkstore)(k, i+doff, dreg, tmp[0]); +	} +} +void parseflags(int argc, char *argv[]) { +	int i; + +	for (i = 0; i < argc; i++) +		if (strcmp(argv[i], "-d") == 0) +			dflag = 1; +		else if (strcmp(argv[i], "-b") == 0)	/* omit */ +			bflag = 1;			/* omit */ +} +static int getrule(Node p, int nt) { +	int rulenum; + +	assert(p); +	rulenum = (*IR->x._rule)(p->x.state, nt); +	if (!rulenum) { +		fprint(stderr, "(%x->op=%s at %w is corrupt.)\n", p, opname(p->op), &src); +		assert(0); +	} +	return rulenum; +} +static void reduce(Node p, int nt) { +	int rulenum, i; +	short *nts; +	Node kids[10]; + +	p = reuse(p, nt); +	rulenum = getrule(p, nt); +	nts = IR->x._nts[rulenum]; +	(*IR->x._kids)(p, rulenum, kids); +	for (i = 0; nts[i]; i++) +		reduce(kids[i], nts[i]); +	if (IR->x._isinstruction[rulenum]) { +		assert(p->x.inst == 0 || p->x.inst == nt); +		p->x.inst = nt; +		if (p->syms[RX] && p->syms[RX]->temporary) { +			debug(fprint(stderr, "(using %s)\n", p->syms[RX]->name)); +			p->syms[RX]->x.usecount++; +		} +	} +} +static Node reuse(Node p, int nt) { +	struct _state { +		short cost[1]; +	}; +	Symbol r = p->syms[RX]; + +	if (generic(p->op) == INDIR && p->kids[0]->op == VREG+P +	&& r->u.t.cse && p->x.mayrecalc +	&& ((struct _state*)r->u.t.cse->x.state)->cost[nt] == 0) +		return r->u.t.cse; +	else +		return p; +} + +int mayrecalc(Node p) { +	int op; + +	assert(p && p->syms[RX]); +	if (p->syms[RX]->u.t.cse == NULL) +		return 0; +	op = generic(p->syms[RX]->u.t.cse->op); +	if (op == CNST || op == ADDRF || op == ADDRG || op == ADDRL) { +		p->x.mayrecalc = 1; +		return 1; +	} else +		return 0; +} +static Node *prune(Node p, Node pp[]) { +	if (p == NULL) +		return pp; +	p->x.kids[0] = p->x.kids[1] = p->x.kids[2] = NULL; +	if (p->x.inst == 0) +		return prune(p->kids[1], prune(p->kids[0], pp)); +	else if (p->syms[RX] && p->syms[RX]->temporary +	&& p->syms[RX]->x.usecount < 2) { +		p->x.inst = 0; +		debug(fprint(stderr, "(clobbering %s)\n", p->syms[RX]->name)); +		return prune(p->kids[1], prune(p->kids[0], pp)); +	} +	else { +		prune(p->kids[1], prune(p->kids[0], &p->x.kids[0])); +		*pp = p; +		return pp + 1; +	} +} + +#define ck(i) return (i) ? 0 : LBURG_MAX + +int range(Node p, int lo, int hi) { +	Symbol s = p->syms[0]; + +	switch (specific(p->op)) { +	case ADDRF+P: +	case ADDRL+P: ck(s->x.offset >= lo && s->x.offset <= hi); +	case CNST+I:  ck(s->u.c.v.i  >= lo && s->u.c.v.i  <= hi); +	case CNST+U:  ck(s->u.c.v.u  >= lo && s->u.c.v.u  <= hi); +	case CNST+P:  ck(s->u.c.v.p  == 0  && lo <= 0 && hi >= 0); +	} +	return LBURG_MAX; +} +static void dumptree(Node p) { +	if (p->op == VREG+P && p->syms[0]) { +		fprint(stderr, "VREGP(%s)", p->syms[0]->name); +		return; +	} else if (generic(p->op) == LOAD) { +		fprint(stderr, "LOAD("); +		dumptree(p->kids[0]); +		fprint(stderr, ")"); +		return; +	} +	fprint(stderr, "%s(", opname(p->op)); +	switch (generic(p->op)) { +	case CNST: case LABEL: +	case ADDRG: case ADDRF: case ADDRL: +		if (p->syms[0]) +			fprint(stderr, "%s", p->syms[0]->name); +		break; +	case RET: +		if (p->kids[0]) +			dumptree(p->kids[0]); +		break; +	case CVF: case CVI: case CVP: case CVU: case JUMP:  +	case ARG: case BCOM: case NEG: case INDIR: +		dumptree(p->kids[0]); +		break; +	case CALL: +		if (optype(p->op) != B) { +			dumptree(p->kids[0]); +			break; +		} +		/* else fall thru */ +	case EQ: case NE: case GT: case GE: case LE: case LT: +	case ASGN: case BOR: case BAND: case BXOR: case RSH: case LSH: +	case ADD: case SUB:  case DIV: case MUL: case MOD: +		dumptree(p->kids[0]); +		fprint(stderr, ", "); +		dumptree(p->kids[1]); +		break; +	default: assert(0); +	} +	fprint(stderr, ")"); +} +static void dumpcover(Node p, int nt, int in) { +	int rulenum, i; +	short *nts; +	Node kids[10]; + +	p = reuse(p, nt); +	rulenum = getrule(p, nt); +	nts = IR->x._nts[rulenum]; +	fprint(stderr, "dumpcover(%x) = ", p); +	for (i = 0; i < in; i++) +		fprint(stderr, " "); +	dumprule(rulenum); +	(*IR->x._kids)(p, rulenum, kids); +	for (i = 0; nts[i]; i++) +		dumpcover(kids[i], nts[i], in+1); +} + +static void dumprule(int rulenum) { +	assert(rulenum); +	fprint(stderr, "%s / %s", IR->x._string[rulenum], +		IR->x._templates[rulenum]); +	if (!IR->x._isinstruction[rulenum]) +		fprint(stderr, "\n"); +} +static unsigned emitasm(Node p, int nt) { +	int rulenum; +	short *nts; +	char *fmt; +	Node kids[10]; + +	p = reuse(p, nt); +	rulenum = getrule(p, nt); +	nts = IR->x._nts[rulenum]; +	fmt = IR->x._templates[rulenum]; +	assert(fmt); +	if (IR->x._isinstruction[rulenum] && p->x.emitted) +		print("%s", p->syms[RX]->x.name); +	else if (*fmt == '#') +		(*IR->x.emit2)(p); +	else { +		if (*fmt == '?') { +			fmt++; +			assert(p->kids[0]); +			if (p->syms[RX] == p->x.kids[0]->syms[RX]) +				while (*fmt++ != '\n') +					; +		} +		for ((*IR->x._kids)(p, rulenum, kids); *fmt; fmt++) +			if (*fmt != '%') +				(void)putchar(*fmt); +			else if (*++fmt == 'F') +				print("%d", framesize); +			else if (*fmt >= '0' && *fmt <= '9') +				emitasm(kids[*fmt - '0'], nts[*fmt - '0']); +			else if (*fmt >= 'a' && *fmt < 'a' + NELEMS(p->syms)) +				fputs(p->syms[*fmt - 'a']->x.name, stdout); +			else +				(void)putchar(*fmt); +	} +	return 0; +} +void emit(Node p) { +	for (; p; p = p->x.next) { +		assert(p->x.registered); +		if ((p->x.equatable && requate(p)) || moveself(p)) +			; +		else +			(*emitter)(p, p->x.inst); +		p->x.emitted = 1; +	} +} +static int moveself(Node p) { +	return p->x.copy +	&& p->syms[RX]->x.name == p->x.kids[0]->syms[RX]->x.name; +} +int move(Node p) { +	p->x.copy = 1; +	return 1; +} +static int requate(Node q) { +	Symbol src = q->x.kids[0]->syms[RX]; +	Symbol tmp = q->syms[RX]; +	Node p; +	int n = 0; + +	debug(fprint(stderr, "(requate(%x): tmp=%s src=%s)\n", q, tmp->x.name, src->x.name)); +	for (p = q->x.next; p; p = p->x.next) +		if (p->x.copy && p->syms[RX] == src +		&&  p->x.kids[0]->syms[RX] == tmp) +			debug(fprint(stderr, "(requate arm 0 at %x)\n", p)), +			p->syms[RX] = tmp; +		else if (setsrc(p->syms[RX]) && !moveself(p) && !readsreg(p)) +			return 0; +		else if (p->x.spills) +			return 0; +		else if (generic(p->op) == CALL && p->x.next) +			return 0; +		else if (p->op == LABEL+V && p->x.next) +			return 0; +		else if (p->syms[RX] == tmp && readsreg(p)) +			debug(fprint(stderr, "(requate arm 5 at %x)\n", p)), +			n++; +		else if (p->syms[RX] == tmp) +			break; +	debug(fprint(stderr, "(requate arm 7 at %x)\n", p)); +	assert(n > 0); +	for (p = q->x.next; p; p = p->x.next) +		if (p->syms[RX] == tmp && readsreg(p)) { +			p->syms[RX] = src; +			if (--n <= 0) +				break; +		} +	return 1; +} +static void prelabel(Node p) { +	if (p == NULL) +		return; +	prelabel(p->kids[0]); +	prelabel(p->kids[1]); +	if (NeedsReg[opindex(p->op)]) +		setreg(p, (*IR->x.rmap)(opkind(p->op))); +	switch (generic(p->op)) { +	case ADDRF: case ADDRL: +		if (p->syms[0]->sclass == REGISTER) +			p->op = VREG+P; +		break; +	case INDIR: +		if (p->kids[0]->op == VREG+P) +			setreg(p, p->kids[0]->syms[0]); +		break; +	case ASGN: +		if (p->kids[0]->op == VREG+P) +			rtarget(p, 1, p->kids[0]->syms[0]); +		break; +	case CVI: case CVU: case CVP: +		if (optype(p->op) != F +		&&  opsize(p->op) <= p->syms[0]->u.c.v.i) +			p->op = LOAD + opkind(p->op); +		break; +	} +	(IR->x.target)(p); +} +void setreg(Node p, Symbol r) { +	p->syms[RX] = r; +} +void rtarget(Node p, int n, Symbol r) { +	Node q = p->kids[n]; + +	assert(q); +	assert(r); +	assert(r->sclass == REGISTER || !r->x.wildcard); +	assert(q->syms[RX]); +	if (r != q->syms[RX] && !q->syms[RX]->x.wildcard) { +		q = newnode(LOAD + opkind(q->op), +			q, NULL, q->syms[0]); +		if (r->u.t.cse == p->kids[n]) +			r->u.t.cse = q; +		p->kids[n] = p->x.kids[n] = q; +		q->x.kids[0] = q->kids[0]; +	} +	setreg(q, r); +	debug(fprint(stderr, "(targeting %x->x.kids[%d]=%x to %s)\n", p, n, p->kids[n], r->x.name)); +} +static void rewrite(Node p) { +	assert(p->x.inst == 0); +	prelabel(p); +	debug(dumptree(p)); +	debug(fprint(stderr, "\n")); +	(*IR->x._label)(p); +	debug(dumpcover(p, 1, 0)); +	reduce(p, 1); +} +Node gen(Node forest) { +	int i; +	struct node sentinel; +	Node dummy, p; + +	head = forest; +	for (p = forest; p; p = p->link) { +		assert(p->count == 0); +		if (generic(p->op) == CALL) +			docall(p); +		else if (   generic(p->op) == ASGN +		&& generic(p->kids[1]->op) == CALL) +			docall(p->kids[1]); +		else if (generic(p->op) == ARG) +			(*IR->x.doarg)(p); +		rewrite(p); +		p->x.listed = 1; +	} +	for (p = forest; p; p = p->link) +		prune(p, &dummy); +	relink(&sentinel, &sentinel); +	for (p = forest; p; p = p->link) +		linearize(p, &sentinel); +	forest = sentinel.x.next; +	assert(forest); +	sentinel.x.next->x.prev = NULL; +	sentinel.x.prev->x.next = NULL; +	for (p = forest; p; p = p->x.next) +		for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) { +			assert(p->x.kids[i]->syms[RX]); +			if (p->x.kids[i]->syms[RX]->temporary) { +				p->x.kids[i]->x.prevuse = +					p->x.kids[i]->syms[RX]->x.lastuse; +				p->x.kids[i]->syms[RX]->x.lastuse = p->x.kids[i]; +			} +		} +	for (p = forest; p; p = p->x.next) { +		ralloc(p); +		if (p->x.listed && NeedsReg[opindex(p->op)] +		&& (*IR->x.rmap)(opkind(p->op))) { +			assert(generic(p->op) == CALL || generic(p->op) == LOAD); +			putreg(p->syms[RX]); +		} +	} +	return forest; +} +int notarget(Node p) { +	return p->syms[RX]->x.wildcard ? 0 : LBURG_MAX; +} +static void putreg(Symbol r) { +	assert(r && r->x.regnode); +	freemask[r->x.regnode->set] |= r->x.regnode->mask; +	debug(dumpregs("(freeing %s)\n", r->x.name, NULL)); +} +static Symbol askfixedreg(Symbol s) { +	Regnode r = s->x.regnode; +	int n = r->set; + +	if (r->mask&~freemask[n]) +		return NULL; +	else { +		freemask[n] &= ~r->mask; +		usedmask[n] |=  r->mask; +		return s; +	} +} +static Symbol askreg(Symbol rs, unsigned rmask[]) { +	int i; + +	if (rs->x.wildcard == NULL) +		return askfixedreg(rs); +	for (i = 31; i >= 0; i--) { +		Symbol r = rs->x.wildcard[i]; +		if (r != NULL +		&& !(r->x.regnode->mask&~rmask[r->x.regnode->set]) +		&& askfixedreg(r)) +			return r; +	} +	return NULL; +} + +static Symbol getreg(Symbol s, unsigned mask[], Node p) { +	Symbol r = askreg(s, mask); +	if (r == NULL) { +		r = spillee(s, mask, p); +		assert(r && r->x.regnode); +		spill(r->x.regnode->mask, r->x.regnode->set, p); +		r = askreg(s, mask); +	} +	assert(r && r->x.regnode); +	r->x.regnode->vbl = NULL; +	return r; +} +int askregvar(Symbol p, Symbol regs) { +	Symbol r; + +	assert(p); +	if (p->sclass != REGISTER) +		return 0; +	else if (!isscalar(p->type)) { +		p->sclass = AUTO; +		return 0; +	} +	else if (p->temporary) { +		p->x.name = "?"; +		return 1; +	} +	else if ((r = askreg(regs, vmask)) != NULL) { +		p->x.regnode = r->x.regnode; +		p->x.regnode->vbl = p; +		p->x.name = r->x.name; +		debug(dumpregs("(allocating %s to symbol %s)\n", p->x.name, p->name)); +		return 1; +	} +	else { +		p->sclass = AUTO; +		return 0; +	} +} +static void linearize(Node p, Node next) { +	int i; + +	for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) +		linearize(p->x.kids[i], next); +	relink(next->x.prev, p); +	relink(p, next); +	debug(fprint(stderr, "(listing %x)\n", p)); +} +static void ralloc(Node p) { +	int i; +	unsigned mask[2]; + +	mask[0] = tmask[0]; +	mask[1] = tmask[1]; +	assert(p); +	debug(fprint(stderr, "(rallocing %x)\n", p)); +	for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) { +		Node kid = p->x.kids[i]; +		Symbol r = kid->syms[RX]; +		assert(r && kid->x.registered); +		if (r->sclass != REGISTER && r->x.lastuse == kid) +			putreg(r); +	} +	if (!p->x.registered && NeedsReg[opindex(p->op)] +	&& (*IR->x.rmap)(opkind(p->op))) { +		Symbol sym = p->syms[RX], set = sym; +		assert(sym); +		if (sym->temporary) +			set = (*IR->x.rmap)(opkind(p->op)); +		assert(set); +		if (set->sclass != REGISTER) { +			Symbol r; +			if (*IR->x._templates[getrule(p, p->x.inst)] == '?') +				for (i = 1; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) { +					Symbol r = p->x.kids[i]->syms[RX]; +					assert(p->x.kids[i]->x.registered); +					assert(r && r->x.regnode); +					assert(sym->x.wildcard || sym != r); +					mask[r->x.regnode->set] &= ~r->x.regnode->mask; +				} +			r = getreg(set, mask, p); +			if (sym->temporary) { +				Node q; +				r->x.lastuse = sym->x.lastuse; +				for (q = sym->x.lastuse; q; q = q->x.prevuse) { +					q->syms[RX] = r; +					q->x.registered = 1; +					if (sym->u.t.cse && q->x.copy) +						q->x.equatable = 1; +				} +			} else { +				p->syms[RX] = r; +				r->x.lastuse = p; +			} +			debug(dumpregs("(allocating %s to node %x)\n", r->x.name, (char *) p)); +		} +	} +	p->x.registered = 1; +	(*IR->x.clobber)(p); +} +static Symbol spillee(Symbol set, unsigned mask[], Node here) { +	Symbol bestreg = NULL; +	int bestdist = -1, i; + +	assert(set); +	if (!set->x.wildcard) +		bestreg = set; +	else { +		for (i = 31; i >= 0; i--) { +			Symbol ri = set->x.wildcard[i]; +			if ( +				ri != NULL && +				ri->x.lastuse && +				(ri->x.regnode->mask&tmask[ri->x.regnode->set]&mask[ri->x.regnode->set]) +			) { +				Regnode rn = ri->x.regnode; +				Node q = here; +				int dist = 0; +				for (; q && !uses(q, rn); q = q->x.next) +					dist++; +				if (q && dist > bestdist) { +					bestdist = dist; +					bestreg = ri; +				} +			} +		} +	} +	assert(bestreg); /* Must be able to spill something. Reconfigure the register allocator +		to ensure that we can allocate a register for all nodes without spilling +		the node's necessary input regs. */	 +	assert(bestreg->x.regnode->vbl == NULL); /* Can't spill register variables because +		the reload site might be in other blocks. Reconfigure the register allocator +		to ensure that this register is never allocated to a variable. */ +	return bestreg; +} +static int uses(Node p, Regnode rn) { +	int i; + +	for (i = 0; i < NELEMS(p->x.kids); i++) +		if ( +			p->x.kids[i] && +			p->x.kids[i]->x.registered && +			rn->set == p->x.kids[i]->syms[RX]->x.regnode->set && +			(rn->mask&p->x.kids[i]->syms[RX]->x.regnode->mask) +		) +			return 1; +	return 0; +} +static void spillr(Symbol r, Node here) { +	int i; +	Symbol tmp; +	Node p = r->x.lastuse; +	assert(p); +	while (p->x.prevuse) +		assert(r == p->syms[RX]), +		p = p->x.prevuse; +	assert(p->x.registered && !readsreg(p)); +	tmp = newtemp(AUTO, optype(p->op), opsize(p->op)); +	genspill(r, p, tmp); +	for (p = here->x.next; p; p = p->x.next) +		for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) { +			Node k = p->x.kids[i]; +			if (k->x.registered && k->syms[RX] == r) +				genreload(p, tmp, i); +		} +	putreg(r); +} +static void genspill(Symbol r, Node last, Symbol tmp) { +	Node p, q; +	Symbol s; +	unsigned ty; + +	debug(fprint(stderr, "(spilling %s to local %s)\n", r->x.name, tmp->x.name)); +	debug(fprint(stderr, "(genspill: ")); +	debug(dumptree(last)); +	debug(fprint(stderr, ")\n")); +	ty = opkind(last->op); +	NEW0(s, FUNC); +	s->sclass = REGISTER; +	s->name = s->x.name = r->x.name; +	s->x.regnode = r->x.regnode; +	q = newnode(ADDRL+P + sizeop(IR->ptrmetric.size), NULL, NULL, s); +	q = newnode(INDIR + ty, q, NULL, NULL); +	p = newnode(ADDRL+P + sizeop(IR->ptrmetric.size), NULL, NULL, tmp); +	p = newnode(ASGN + ty, p, q, NULL); +	p->x.spills = 1; +	rewrite(p); +	prune(p, &q); +	q = last->x.next; +	linearize(p, q); +	for (p = last->x.next; p != q; p = p->x.next) { +		ralloc(p); +		assert(!p->x.listed || !NeedsReg[opindex(p->op)] || !(*IR->x.rmap)(opkind(p->op))); +	} +} + +static void genreload(Node p, Symbol tmp, int i) { +	Node q; +	int ty; + +	debug(fprint(stderr, "(replacing %x with a reload from %s)\n", p->x.kids[i], tmp->x.name)); +	debug(fprint(stderr, "(genreload: ")); +	debug(dumptree(p->x.kids[i])); +	debug(fprint(stderr, ")\n")); +	ty = opkind(p->x.kids[i]->op); +	q = newnode(ADDRL+P + sizeop(IR->ptrmetric.size), NULL, NULL, tmp); +	p->x.kids[i] = newnode(INDIR + ty, q, NULL, NULL); +	rewrite(p->x.kids[i]); +	prune(p->x.kids[i], &q); +	reprune(&p->kids[1], reprune(&p->kids[0], 0, i, p), i, p); +	prune(p, &q); +	linearize(p->x.kids[i], p); +} +static int reprune(Node *pp, int k, int n, Node p) { +	struct node x, *q = *pp; + +	if (q == NULL || k > n) +		return k; +	else if (q->x.inst == 0) +		return reprune(&q->kids[1], +			reprune(&q->kids[0], k, n, p), n, p); +	if (k == n) { +		debug(fprint(stderr, "(reprune changes %x from %x to %x)\n", pp, *pp, p->x.kids[n])); +		*pp = p->x.kids[n]; +		x = *p; +		(IR->x.target)(&x); +	} +	return k + 1; +} +void spill(unsigned mask, int n, Node here) { +	int i; +	Node p; + +	here->x.spills = 1; +	usedmask[n] |= mask; +	if (mask&~freemask[n]) { + +		assert( /* It makes no sense for a node to clobber() its target. */ +			here->x.registered == 0 || /* call isn't coming through clobber() */ +			here->syms[RX] == NULL || +			here->syms[RX]->x.regnode == NULL || +			here->syms[RX]->x.regnode->set != n || +			(here->syms[RX]->x.regnode->mask&mask) == 0 +		); + +		for (p = here; p; p = p->x.next) +			for (i = 0; i < NELEMS(p->x.kids) && p->x.kids[i]; i++) { +				Symbol r = p->x.kids[i]->syms[RX]; +				assert(r); +				if (p->x.kids[i]->x.registered && r->x.regnode->set == n +				&& r->x.regnode->mask&mask) +					spillr(r, here); +			} +	} +} +static void dumpregs(char *msg, char *a, char *b) { +	fprint(stderr, msg, a, b); +	fprint(stderr, "(free[0]=%x)\n", freemask[0]); +	fprint(stderr, "(free[1]=%x)\n", freemask[1]); +} + +int getregnum(Node p) { +	assert(p && p->syms[RX] && p->syms[RX]->x.regnode); +	return p->syms[RX]->x.regnode->number; +} + + +unsigned regloc(Symbol p) { +	assert(p && p->sclass == REGISTER && p->sclass == REGISTER && p->x.regnode); +	return p->x.regnode->set<<8 | p->x.regnode->number; +} + diff --git a/src/tools/lcc/src/init.c b/src/tools/lcc/src/init.c new file mode 100644 index 0000000..172d7c0 --- /dev/null +++ b/src/tools/lcc/src/init.c @@ -0,0 +1,318 @@ +#include "c.h" + + +static int curseg;		/* current segment */ + +/* defpointer - initialize a pointer to p or to 0 if p==0 */ +void defpointer(Symbol p) { +	if (p) { +		(*IR->defaddress)(p); +		p->ref++; +	} else { +		static Value v; +		(*IR->defconst)(P, voidptype->size, v); +	} +} + +/* genconst - generate/check constant expression e; return size */ +static int genconst(Tree e, int def) { +	for (;;) +		switch (generic(e->op)) { +		case ADDRG: +			if (def) +				(*IR->defaddress)(e->u.sym); +			return e->type->size; +		case CNST: +			if (e->op == CNST+P && isarray(e->type)) { +				e = cvtconst(e); +				continue; +			} +			if (def) +				(*IR->defconst)(e->type->op, e->type->size, e->u.v); +			return e->type->size; +		case RIGHT: +			assert(e->kids[0] || e->kids[1]); +			if (e->kids[1] && e->kids[0]) +				error("initializer must be constant\n"); +			e = e->kids[1] ? e->kids[1] : e->kids[0]; +			continue; +		case CVP: +			if (isarith(e->type)) +				error("cast from `%t' to `%t' is illegal in constant expressions\n", +					e->kids[0]->type, e->type); +			/* fall thru */ +		case CVI: case CVU: case CVF: +			e = e->kids[0]; +			continue; +		default: +			error("initializer must be constant\n"); +			if (def) +				genconst(consttree(0, inttype), def); +			return inttype->size; +		} +} + +/* initvalue - evaluate a constant expression for a value of integer type ty */ +static Tree initvalue(Type ty) { +	Type aty; +	Tree e; + +	needconst++; +	e = expr1(0); +	if ((aty = assign(ty, e)) != NULL) +		e = cast(e, aty); +	else { +		error("invalid initialization type; found `%t' expected `%t'\n", +			e->type,  ty); +		e = retype(consttree(0, inttype), ty); +	} +	needconst--; +	if (generic(e->op) != CNST) { +		error("initializer must be constant\n"); +		e = retype(consttree(0, inttype), ty); +	} +	return e; +} + +/* initarray - initialize array of ty of <= len bytes; if len == 0, go to } */ +static int initarray(int len, Type ty, int lev) { +	int n = 0; + +	do { +		initializer(ty, lev); +		n += ty->size; +		if ((len > 0 && n >= len) || t != ',') +			break; +		t = gettok(); +	} while (t != '}'); +	return n; +} + +/* initchar - initialize array of <= len ty characters; if len == 0, go to } */ +static int initchar(int len, Type ty) { +	int n = 0; +	char buf[16], *s = buf; + +	do { +		*s++ = initvalue(ty)->u.v.i; +		if (++n%inttype->size == 0) { +			(*IR->defstring)(inttype->size, buf); +			s = buf; +		} +		if ((len > 0 && n >= len) || t != ',') +			break; +		t = gettok(); +	} while (t != '}'); +	if (s > buf) +		(*IR->defstring)(s - buf, buf); +	return n; +} + +/* initend - finish off an initialization at level lev; accepts trailing comma */ +static void initend(int lev, char follow[]) { +	if (lev == 0 && t == ',') +		t = gettok(); +	test('}', follow); +} + +/* initfields - initialize <= an unsigned's worth of bit fields in fields p to q */ +static int initfields(Field p, Field q) { +	unsigned int bits = 0; +	int i, n = 0; + +	do { +		i = initvalue(inttype)->u.v.i; +		if (fieldsize(p) < 8*p->type->size) { +			if ((p->type == inttype && +			   (i < -(int)(fieldmask(p)>>1)-1 || i > (int)(fieldmask(p)>>1))) +			||  (p->type == unsignedtype && (i&~fieldmask(p)) !=  0)) +				warning("initializer exceeds bit-field width\n"); +			i &= fieldmask(p); +		} +		bits |= i<<fieldright(p); +		if (IR->little_endian) { +			if (fieldsize(p) + fieldright(p) > n) +				n = fieldsize(p) + fieldright(p); +		} else { +			if (fieldsize(p) + fieldleft(p) > n) +				n = fieldsize(p) + fieldleft(p); +		} +		if (p->link == q) +			break; +		p = p->link; +	} while (t == ',' && (t = gettok()) != 0); +	n = (n + 7)/8; +	for (i = 0; i < n; i++) { +		Value v; +		if (IR->little_endian) { +			v.u = (unsigned char)bits; +			bits >>= 8; +		} else {	/* a big endian */ +			v.u = (unsigned char)(bits>>(8*(unsignedtype->size - 1))); +			bits <<= 8; +		} +		(*IR->defconst)(U, unsignedchar->size, v); +	} +	return n; +} + +/* initstruct - initialize a struct ty of <= len bytes; if len == 0, go to } */ +static int initstruct(int len, Type ty, int lev) { +	int a, n = 0; +	Field p = ty->u.sym->u.s.flist; + +	do { +		if (p->offset > n) { +			(*IR->space)(p->offset - n); +			n += p->offset - n; +		} +		if (p->lsb) { +			Field q = p; +			while (q->link && q->link->offset == p->offset) +				q = q->link; +			n += initfields(p, q->link); +			p = q; +		} else { +			initializer(p->type, lev); +			n += p->type->size; +		} +		if (p->link) { +			p = p->link; +			a = p->type->align; +		} else +			a = ty->align; +		if (a && n%a) { +			(*IR->space)(a - n%a); +			n = roundup(n, a); +		} +		if ((len > 0 && n >= len) || t != ',') +			break; +		t = gettok(); +	} while (t != '}'); +	return n; +} + +/* initializer - constexpr | { constexpr ( , constexpr )* [ , ] } */ +Type initializer(Type ty, int lev) { +	int n = 0; +	Tree e; +	Type aty = NULL; +	static char follow[] = { IF, CHAR, STATIC, 0 }; + +	ty = unqual(ty); +	if (isscalar(ty)) { +		needconst++; +		if (t == '{') { +			t = gettok(); +			e = expr1(0); +			initend(lev, follow); +		} else +			e = expr1(0); +		e = pointer(e); +		if ((aty = assign(ty, e)) != NULL) +			e = cast(e, aty); +		else +			error("invalid initialization type; found `%t' expected `%t'\n", +				e->type, ty); +		n = genconst(e, 1); +		deallocate(STMT); +		needconst--; +	} +	if ((isunion(ty) || isstruct(ty)) && ty->size == 0) { +		static char follow[] = { CHAR, STATIC, 0 }; +		error("cannot initialize undefined `%t'\n", ty); +		skipto(';', follow); +		return ty; +	} else if (isunion(ty)) { +		if (t == '{') { +			t = gettok(); +			n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1); +			initend(lev, follow); +		} else { +			if (lev == 0) +				error("missing { in initialization of `%t'\n", ty); +			n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1); +		} +	} else if (isstruct(ty)) { +		if (t == '{') { +			t = gettok(); +			n = initstruct(0, ty, lev + 1); +			test('}', follow); +		} else if (lev > 0) +			n = initstruct(ty->size, ty, lev + 1); +		else { +			error("missing { in initialization of `%t'\n", ty); +			n = initstruct(ty->u.sym->u.s.flist->type->size, ty, lev + 1); +		} +	} +	if (isarray(ty)) +		aty = unqual(ty->type); +	if (isarray(ty) && ischar(aty)) { +		if (t == SCON) { +			if (ty->size > 0 && ty->size == tsym->type->size - 1) +				tsym->type = array(chartype, ty->size, 0); +			n = tsym->type->size; +			(*IR->defstring)(tsym->type->size, tsym->u.c.v.p); +			t = gettok(); +		} else if (t == '{') { +			t = gettok(); +			if (t == SCON) { +				ty = initializer(ty, lev + 1); +				initend(lev, follow); +				return ty; +			} +			n = initchar(0, aty); +			test('}', follow); +		} else if (lev > 0 && ty->size > 0) +			n = initchar(ty->size, aty); +		else {	/* eg, char c[] = 0; */ +			error("missing { in initialization of `%t'\n", ty); +			n = initchar(1, aty); +		} +	} else if (isarray(ty)) { +		if (t == SCON && aty == widechar) { +			int i; +			unsigned int *s = tsym->u.c.v.p; +			if (ty->size > 0 && ty->size == tsym->type->size - widechar->size) +				tsym->type = array(widechar, ty->size/widechar->size, 0); +			n = tsym->type->size; +			for (i = 0; i < n; i += widechar->size) { +				Value v; +				v.u = *s++; +				(*IR->defconst)(widechar->op, widechar->size, v); +			} +			t = gettok(); +		} else if (t == '{') { +			t = gettok(); +			if (t == SCON && aty == widechar) { +				ty = initializer(ty, lev + 1); +				initend(lev, follow); +				return ty; +			} +			n = initarray(0, aty, lev + 1); +			test('}', follow); +		} else if (lev > 0 && ty->size > 0) +			n = initarray(ty->size, aty, lev + 1); +		else { +			error("missing { in initialization of `%t'\n", ty); +			n = initarray(aty->size, aty, lev + 1); +		} +	}	 +	if (ty->size) { +		if (n > ty->size) +			error("too many initializers\n"); +		else if (n < ty->size) +			(*IR->space)(ty->size - n); +	} else if (isarray(ty) && ty->type->size > 0) +		ty = array(ty->type, n/ty->type->size, 0); +	else +		ty->size = n; +	return ty; +} + +/* swtoseg - switch to segment seg, if necessary */ +void swtoseg(int seg) { +	if (curseg != seg) +		(*IR->segment)(seg); +	curseg = seg; +} diff --git a/src/tools/lcc/src/inits.c b/src/tools/lcc/src/inits.c new file mode 100644 index 0000000..c42f61e --- /dev/null +++ b/src/tools/lcc/src/inits.c @@ -0,0 +1,7 @@ +void init(int argc, char *argv[]) { +	{extern void input_init(int, char *[]); input_init(argc, argv);} +	{extern void main_init(int, char *[]); main_init(argc, argv);} +	{extern void prof_init(int, char *[]); prof_init(argc, argv);} +	{extern void trace_init(int, char *[]); trace_init(argc, argv);} +	{extern void type_init(int, char *[]); type_init(argc, argv);} +} diff --git a/src/tools/lcc/src/input.c b/src/tools/lcc/src/input.c new file mode 100644 index 0000000..c2a084e --- /dev/null +++ b/src/tools/lcc/src/input.c @@ -0,0 +1,135 @@ +#include "c.h" + + +static void pragma(void); +static void resynch(void); + +static int bsize; +static unsigned char buffer[MAXLINE+1 + BUFSIZE+1]; +unsigned char *cp;	/* current input character */ +char *file;		/* current input file name */ +char *firstfile;	/* first input file */ +unsigned char *limit;	/* points to last character + 1 */ +char *line;		/* current line */ +int lineno;		/* line number of current line */ + +void nextline(void) { +	do { +		if (cp >= limit) { +			fillbuf(); +			if (cp >= limit) +				cp = limit; +			if (cp == limit) +				return; +		} else { +			lineno++; +			for (line = (char *)cp; *cp==' ' || *cp=='\t'; cp++) +				; +			if (*cp == '#') { +				resynch(); +				nextline(); +			} +		} +	} while (*cp == '\n' && cp == limit); +} +void fillbuf(void) { +	if (bsize == 0) +		return; +	if (cp >= limit) +		cp = &buffer[MAXLINE+1]; +	else +		{ +			int n = limit - cp; +			unsigned char *s = &buffer[MAXLINE+1] - n; +			assert(s >= buffer); +			line = (char *)s - ((char *)cp - line); +			while (cp < limit) +				*s++ = *cp++; +			cp = &buffer[MAXLINE+1] - n; +		} +	if (feof(stdin)) +		bsize = 0; +	else +		bsize = fread(&buffer[MAXLINE+1], 1, BUFSIZE, stdin); +	if (bsize < 0) { +		error("read error\n"); +		exit(EXIT_FAILURE); +	} +	limit = &buffer[MAXLINE+1+bsize]; +	*limit = '\n'; +} +void input_init(int argc, char *argv[]) { +	static int inited; + +	if (inited) +		return; +	inited = 1; +	main_init(argc, argv); +	limit = cp = &buffer[MAXLINE+1]; +	bsize = -1; +	lineno = 0; +	file = NULL; +	fillbuf(); +	if (cp >= limit) +		cp = limit; +	nextline(); +} + +/* pragma - handle #pragma ref id... */ +static void pragma(void) { +	if ((t = gettok()) == ID && strcmp(token, "ref") == 0) +		for (;;) { +			while (*cp == ' ' || *cp == '\t') +				cp++; +			if (*cp == '\n' || *cp == 0) +				break; +			if ((t = gettok()) == ID && tsym) { +				tsym->ref++; +				use(tsym, src); +			}	 +		} +} + +/* resynch - set line number/file name in # n [ "file" ] and #pragma ... */ +static void resynch(void) { +	for (cp++; *cp == ' ' || *cp == '\t'; ) +		cp++; +	if (limit - cp < MAXLINE) +		fillbuf(); +	if (strncmp((char *)cp, "pragma", 6) == 0) { +		cp += 6; +		pragma(); +	} else if (*cp >= '0' && *cp <= '9') { +	line:	for (lineno = 0; *cp >= '0' && *cp <= '9'; ) +			lineno = 10*lineno + *cp++ - '0'; +		lineno--; +		while (*cp == ' ' || *cp == '\t') +			cp++; +		if (*cp == '"') { +			file = (char *)++cp; +			while (*cp && *cp != '"' && *cp != '\n') +				cp++; +			file = stringn(file, (char *)cp - file); +			if (*cp == '\n') +				warning("missing \" in preprocessor line\n"); +			if (firstfile == 0) +				firstfile = file; +		} +	} else if (strncmp((char *)cp, "line", 4) == 0) { +		for (cp += 4; *cp == ' ' || *cp == '\t'; ) +			cp++; +		if (*cp >= '0' && *cp <= '9') +			goto line; +		if (Aflag >= 2) +			warning("unrecognized control line\n"); +	} else if (Aflag >= 2 && *cp != '\n') +		warning("unrecognized control line\n"); +	while (*cp) +		if (*cp++ == '\n') { +			if (cp == limit + 1) +				nextline(); +			else +				break; +		} +} + diff --git a/src/tools/lcc/src/lex.c b/src/tools/lcc/src/lex.c new file mode 100644 index 0000000..ec2f1ec --- /dev/null +++ b/src/tools/lcc/src/lex.c @@ -0,0 +1,923 @@ +#include "c.h" +#include <float.h> +#include <errno.h> + + +#define MAXTOKEN 32 + +enum { BLANK=01,  NEWLINE=02, LETTER=04, +       DIGIT=010, HEX=020,    OTHER=040 }; + +static unsigned char map[256] = { /* 000 nul */	0, +				   /* 001 soh */	0, +				   /* 002 stx */	0, +				   /* 003 etx */	0, +				   /* 004 eot */	0, +				   /* 005 enq */	0, +				   /* 006 ack */	0, +				   /* 007 bel */	0, +				   /* 010 bs  */	0, +				   /* 011 ht  */	BLANK, +				   /* 012 nl  */	NEWLINE, +				   /* 013 vt  */	BLANK, +				   /* 014 ff  */	BLANK, +				   /* 015 cr  */	0, +				   /* 016 so  */	0, +				   /* 017 si  */	0, +				   /* 020 dle */	0, +				   /* 021 dc1 */	0, +				   /* 022 dc2 */	0, +				   /* 023 dc3 */	0, +				   /* 024 dc4 */	0, +				   /* 025 nak */	0, +				   /* 026 syn */	0, +				   /* 027 etb */	0, +				   /* 030 can */	0, +				   /* 031 em  */	0, +				   /* 032 sub */	0, +				   /* 033 esc */	0, +				   /* 034 fs  */	0, +				   /* 035 gs  */	0, +				   /* 036 rs  */	0, +				   /* 037 us  */	0, +				   /* 040 sp  */	BLANK, +				   /* 041 !   */	OTHER, +				   /* 042 "   */	OTHER, +				   /* 043 #   */	OTHER, +				   /* 044 $   */	0, +				   /* 045 %   */	OTHER, +				   /* 046 &   */	OTHER, +				   /* 047 '   */	OTHER, +				   /* 050 (   */	OTHER, +				   /* 051 )   */	OTHER, +				   /* 052 *   */	OTHER, +				   /* 053 +   */	OTHER, +				   /* 054 ,   */	OTHER, +				   /* 055 -   */	OTHER, +				   /* 056 .   */	OTHER, +				   /* 057 /   */	OTHER, +				   /* 060 0   */	DIGIT, +				   /* 061 1   */	DIGIT, +				   /* 062 2   */	DIGIT, +				   /* 063 3   */	DIGIT, +				   /* 064 4   */	DIGIT, +				   /* 065 5   */	DIGIT, +				   /* 066 6   */	DIGIT, +				   /* 067 7   */	DIGIT, +				   /* 070 8   */	DIGIT, +				   /* 071 9   */	DIGIT, +				   /* 072 :   */	OTHER, +				   /* 073 ;   */	OTHER, +				   /* 074 <   */	OTHER, +				   /* 075 =   */	OTHER, +				   /* 076 >   */	OTHER, +				   /* 077 ?   */	OTHER, +				   /* 100 @   */	0, +				   /* 101 A   */	LETTER|HEX, +				   /* 102 B   */	LETTER|HEX, +				   /* 103 C   */	LETTER|HEX, +				   /* 104 D   */	LETTER|HEX, +				   /* 105 E   */	LETTER|HEX, +				   /* 106 F   */	LETTER|HEX, +				   /* 107 G   */	LETTER, +				   /* 110 H   */	LETTER, +				   /* 111 I   */	LETTER, +				   /* 112 J   */	LETTER, +				   /* 113 K   */	LETTER, +				   /* 114 L   */	LETTER, +				   /* 115 M   */	LETTER, +				   /* 116 N   */	LETTER, +				   /* 117 O   */	LETTER, +				   /* 120 P   */	LETTER, +				   /* 121 Q   */	LETTER, +				   /* 122 R   */	LETTER, +				   /* 123 S   */	LETTER, +				   /* 124 T   */	LETTER, +				   /* 125 U   */	LETTER, +				   /* 126 V   */	LETTER, +				   /* 127 W   */	LETTER, +				   /* 130 X   */	LETTER, +				   /* 131 Y   */	LETTER, +				   /* 132 Z   */	LETTER, +				   /* 133 [   */	OTHER, +				   /* 134 \   */	OTHER, +				   /* 135 ]   */	OTHER, +				   /* 136 ^   */	OTHER, +				   /* 137 _   */	LETTER, +				   /* 140 `   */	0, +				   /* 141 a   */	LETTER|HEX, +				   /* 142 b   */	LETTER|HEX, +				   /* 143 c   */	LETTER|HEX, +				   /* 144 d   */	LETTER|HEX, +				   /* 145 e   */	LETTER|HEX, +				   /* 146 f   */	LETTER|HEX, +				   /* 147 g   */	LETTER, +				   /* 150 h   */	LETTER, +				   /* 151 i   */	LETTER, +				   /* 152 j   */	LETTER, +				   /* 153 k   */	LETTER, +				   /* 154 l   */	LETTER, +				   /* 155 m   */	LETTER, +				   /* 156 n   */	LETTER, +				   /* 157 o   */	LETTER, +				   /* 160 p   */	LETTER, +				   /* 161 q   */	LETTER, +				   /* 162 r   */	LETTER, +				   /* 163 s   */	LETTER, +				   /* 164 t   */	LETTER, +				   /* 165 u   */	LETTER, +				   /* 166 v   */	LETTER, +				   /* 167 w   */	LETTER, +				   /* 170 x   */	LETTER, +				   /* 171 y   */	LETTER, +				   /* 172 z   */	LETTER, +				   /* 173 {   */	OTHER, +				   /* 174 |   */	OTHER, +				   /* 175 }   */	OTHER, +				   /* 176 ~   */	OTHER, }; +static struct symbol tval; +static char cbuf[BUFSIZE+1]; +static unsigned int wcbuf[BUFSIZE+1]; + +Coordinate src;		/* current source coordinate */ +int t; +char *token;		/* current token */ +Symbol tsym;		/* symbol table entry for current token */ + +static void *cput(int c, void *cl); +static void *wcput(int c, void *cl); +static void *scon(int q, void *put(int c, void *cl), void *cl); +static int backslash(int q); +static Symbol fcon(void); +static Symbol icon(unsigned long, int, int); +static void ppnumber(char *); + +int gettok(void) { +	for (;;) { +		register unsigned char *rcp = cp; +		while (map[*rcp]&BLANK) +			rcp++; +		if (limit - rcp < MAXTOKEN) { +			cp = rcp; +			fillbuf(); +			rcp = cp; +		} +		src.file = file; +		src.x = (char *)rcp - line; +		src.y = lineno; +		cp = rcp + 1; +		switch (*rcp++) { +		case '/': if (*rcp == '*') { +			  	int c = 0; +			  	for (rcp++; *rcp != '/' || c != '*'; ) +			  		if (map[*rcp]&NEWLINE) { +			  			if (rcp < limit) +			  				c = *rcp; +			  			cp = rcp + 1; +			  			nextline(); +			  			rcp = cp; +			  			if (rcp == limit) +			  				break; +			  		} else +			  			c = *rcp++; +			  	if (rcp < limit) +			  		rcp++; +			  	else +			  		error("unclosed comment\n"); +			  	cp = rcp; +			  	continue; +			  } +			  return '/'; +		case '<': +			if (*rcp == '=') return cp++, LEQ; +			if (*rcp == '<') return cp++, LSHIFT; +			return '<'; +		case '>': +			if (*rcp == '=') return cp++, GEQ; +			if (*rcp == '>') return cp++, RSHIFT; +			return '>'; +		case '-': +			if (*rcp == '>') return cp++, DEREF; +			if (*rcp == '-') return cp++, DECR; +			return '-'; +		case '=': return *rcp == '=' ? cp++, EQL    : '='; +		case '!': return *rcp == '=' ? cp++, NEQ    : '!'; +		case '|': return *rcp == '|' ? cp++, OROR   : '|'; +		case '&': return *rcp == '&' ? cp++, ANDAND : '&'; +		case '+': return *rcp == '+' ? cp++, INCR   : '+'; +		case ';': case ',': case ':': +		case '*': case '~': case '%': case '^': case '?': +		case '[': case ']': case '{': case '}': case '(': case ')':  +			return rcp[-1]; +		case '\n': case '\v': case '\r': case '\f': +			nextline(); +			if (cp == limit) { +				tsym = NULL; +				return EOI; +			} +			continue; + +		case 'i': +			if (rcp[0] == 'f' +			&& !(map[rcp[1]]&(DIGIT|LETTER))) { +				cp = rcp + 1; +				return IF; +			} +			if (rcp[0] == 'n' +			&&  rcp[1] == 't' +			&& !(map[rcp[2]]&(DIGIT|LETTER))) { +				cp = rcp + 2; +				tsym = inttype->u.sym; +				return INT; +			} +			goto id; +		case 'h': case 'j': case 'k': case 'm': case 'n': case 'o': +		case 'p': case 'q': case 'x': case 'y': case 'z': +		case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': +		case 'G': case 'H': case 'I': case 'J': case 'K': +		case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R': +		case 'S': case 'T': case 'U': case 'V': case 'W': case 'X': +		case 'Y': case 'Z': +		id: +			if (limit - rcp < MAXLINE) { +				cp = rcp - 1; +				fillbuf(); +				rcp = ++cp; +			} +			assert(cp == rcp); +			token = (char *)rcp - 1; +			while (map[*rcp]&(DIGIT|LETTER)) +				rcp++; +			token = stringn(token, (char *)rcp - token); +			tsym = lookup(token, identifiers); +			cp = rcp; +			return ID; +		case '0': case '1': case '2': case '3': case '4': +		case '5': case '6': case '7': case '8': case '9': { +			unsigned long n = 0; +			if (limit - rcp < MAXLINE) { +				cp = rcp - 1; +				fillbuf(); +				rcp = ++cp; +			} +			assert(cp == rcp); +			token = (char *)rcp - 1; +			if (*token == '0' && (*rcp == 'x' || *rcp == 'X')) { +				int d, overflow = 0; +				while (*++rcp) { +					if (map[*rcp]&DIGIT) +						d = *rcp - '0'; +					else if (*rcp >= 'a' && *rcp <= 'f') +						d = *rcp - 'a' + 10; +					else if (*rcp >= 'A' && *rcp <= 'F') +						d = *rcp - 'A' + 10; +					else +						break; +					if (n&~(~0UL >> 4)) +						overflow = 1; +					else +						n = (n<<4) + d; +				} +				if ((char *)rcp - token <= 2) +					error("invalid hexadecimal constant `%S'\n", token, (char *)rcp-token); +				cp = rcp; +				tsym = icon(n, overflow, 16); +			} else if (*token == '0') { +				int err = 0, overflow = 0; +				for ( ; map[*rcp]&DIGIT; rcp++) { +					if (*rcp == '8' || *rcp == '9') +						err = 1; +					if (n&~(~0UL >> 3)) +						overflow = 1; +					else +						n = (n<<3) + (*rcp - '0'); +				} +				if (*rcp == '.' || *rcp == 'e' || *rcp == 'E') { +					cp = rcp; +					tsym = fcon(); +					return FCON; +				} +				cp = rcp; +				tsym = icon(n, overflow, 8); +				if (err) +					error("invalid octal constant `%S'\n", token, (char*)cp-token); +			} else { +				int overflow = 0; +				for (n = *token - '0'; map[*rcp]&DIGIT; ) { +					int d = *rcp++ - '0'; +					if (n > (ULONG_MAX - d)/10) +						overflow = 1; +					else +						n = 10*n + d; +				} +				if (*rcp == '.' || *rcp == 'e' || *rcp == 'E') { +					cp = rcp; +					tsym = fcon(); +					return FCON; +				} +				cp = rcp; +				tsym = icon(n, overflow, 10); +			} +			return ICON; +		} +		case '.': +			if (rcp[0] == '.' && rcp[1] == '.') { +				cp += 2; +				return ELLIPSIS; +			} +			if ((map[*rcp]&DIGIT) == 0) +				return '.'; +			if (limit - rcp < MAXLINE) { +				cp = rcp - 1; +				fillbuf(); +				rcp = ++cp; +			} +			assert(cp == rcp); +			cp = rcp - 1; +			token = (char *)cp; +			tsym = fcon(); +			return FCON; +		case 'L': +			if (*rcp == '\'') { +				unsigned int *s = scon(*cp, wcput, wcbuf); +				if (s - wcbuf > 2) +					warning("excess characters in wide-character literal ignored\n"); +				tval.type = widechar; +				tval.u.c.v.u = wcbuf[0]; +				tsym = &tval; +				return ICON; +			} else if (*rcp == '"') { +				unsigned int *s = scon(*cp, wcput, wcbuf); +				tval.type = array(widechar, s - wcbuf, 0); +				tval.u.c.v.p = wcbuf; +				tsym = &tval; +				return SCON; +			} else +				goto id; +		case '\'': { +			char *s = scon(*--cp, cput, cbuf); +			if (s - cbuf > 2) +				warning("excess characters in multibyte character literal ignored\n"); +			tval.type = inttype; +			if (chartype->op == INT) +				tval.u.c.v.i = extend(cbuf[0], chartype); +			else +				tval.u.c.v.i = cbuf[0]&0xFF; +			tsym = &tval; +			return ICON; +			} +		case '"': { +			char *s = scon(*--cp, cput, cbuf); +			tval.type = array(chartype, s - cbuf, 0); +			tval.u.c.v.p = cbuf; +			tsym = &tval; +			return SCON; +			} +		case 'a': +			if (rcp[0] == 'u' +			&&  rcp[1] == 't' +			&&  rcp[2] == 'o' +			&& !(map[rcp[3]]&(DIGIT|LETTER))) { +				cp = rcp + 3; +				return AUTO; +			} +			goto id; +		case 'b': +			if (rcp[0] == 'r' +			&&  rcp[1] == 'e' +			&&  rcp[2] == 'a' +			&&  rcp[3] == 'k' +			&& !(map[rcp[4]]&(DIGIT|LETTER))) { +				cp = rcp + 4; +				return BREAK; +			} +			goto id; +		case 'c': +			if (rcp[0] == 'a' +			&&  rcp[1] == 's' +			&&  rcp[2] == 'e' +			&& !(map[rcp[3]]&(DIGIT|LETTER))) { +				cp = rcp + 3; +				return CASE; +			} +			if (rcp[0] == 'h' +			&&  rcp[1] == 'a' +			&&  rcp[2] == 'r' +			&& !(map[rcp[3]]&(DIGIT|LETTER))) { +				cp = rcp + 3; +				tsym = chartype->u.sym; +				return CHAR; +			} +			if (rcp[0] == 'o' +			&&  rcp[1] == 'n' +			&&  rcp[2] == 's' +			&&  rcp[3] == 't' +			&& !(map[rcp[4]]&(DIGIT|LETTER))) { +				cp = rcp + 4; +				return CONST; +			} +			if (rcp[0] == 'o' +			&&  rcp[1] == 'n' +			&&  rcp[2] == 't' +			&&  rcp[3] == 'i' +			&&  rcp[4] == 'n' +			&&  rcp[5] == 'u' +			&&  rcp[6] == 'e' +			&& !(map[rcp[7]]&(DIGIT|LETTER))) { +				cp = rcp + 7; +				return CONTINUE; +			} +			goto id; +		case 'd': +			if (rcp[0] == 'e' +			&&  rcp[1] == 'f' +			&&  rcp[2] == 'a' +			&&  rcp[3] == 'u' +			&&  rcp[4] == 'l' +			&&  rcp[5] == 't' +			&& !(map[rcp[6]]&(DIGIT|LETTER))) { +				cp = rcp + 6; +				return DEFAULT; +			} +			if (rcp[0] == 'o' +			&&  rcp[1] == 'u' +			&&  rcp[2] == 'b' +			&&  rcp[3] == 'l' +			&&  rcp[4] == 'e' +			&& !(map[rcp[5]]&(DIGIT|LETTER))) { +				cp = rcp + 5; +				tsym = doubletype->u.sym; +				return DOUBLE; +			} +			if (rcp[0] == 'o' +			&& !(map[rcp[1]]&(DIGIT|LETTER))) { +				cp = rcp + 1; +				return DO; +			} +			goto id; +		case 'e': +			if (rcp[0] == 'l' +			&&  rcp[1] == 's' +			&&  rcp[2] == 'e' +			&& !(map[rcp[3]]&(DIGIT|LETTER))) { +				cp = rcp + 3; +				return ELSE; +			} +			if (rcp[0] == 'n' +			&&  rcp[1] == 'u' +			&&  rcp[2] == 'm' +			&& !(map[rcp[3]]&(DIGIT|LETTER))) { +				cp = rcp + 3; +				return ENUM; +			} +			if (rcp[0] == 'x' +			&&  rcp[1] == 't' +			&&  rcp[2] == 'e' +			&&  rcp[3] == 'r' +			&&  rcp[4] == 'n' +			&& !(map[rcp[5]]&(DIGIT|LETTER))) { +				cp = rcp + 5; +				return EXTERN; +			} +			goto id; +		case 'f': +			if (rcp[0] == 'l' +			&&  rcp[1] == 'o' +			&&  rcp[2] == 'a' +			&&  rcp[3] == 't' +			&& !(map[rcp[4]]&(DIGIT|LETTER))) { +				cp = rcp + 4; +				tsym = floattype->u.sym; +				return FLOAT; +			} +			if (rcp[0] == 'o' +			&&  rcp[1] == 'r' +			&& !(map[rcp[2]]&(DIGIT|LETTER))) { +				cp = rcp + 2; +				return FOR; +			} +			goto id; +		case 'g': +			if (rcp[0] == 'o' +			&&  rcp[1] == 't' +			&&  rcp[2] == 'o' +			&& !(map[rcp[3]]&(DIGIT|LETTER))) { +				cp = rcp + 3; +				return GOTO; +			} +			goto id; +		case 'l': +			if (rcp[0] == 'o' +			&&  rcp[1] == 'n' +			&&  rcp[2] == 'g' +			&& !(map[rcp[3]]&(DIGIT|LETTER))) { +				cp = rcp + 3; +				return LONG; +			} +			goto id; +		case 'r': +			if (rcp[0] == 'e' +			&&  rcp[1] == 'g' +			&&  rcp[2] == 'i' +			&&  rcp[3] == 's' +			&&  rcp[4] == 't' +			&&  rcp[5] == 'e' +			&&  rcp[6] == 'r' +			&& !(map[rcp[7]]&(DIGIT|LETTER))) { +				cp = rcp + 7; +				return REGISTER; +			} +			if (rcp[0] == 'e' +			&&  rcp[1] == 't' +			&&  rcp[2] == 'u' +			&&  rcp[3] == 'r' +			&&  rcp[4] == 'n' +			&& !(map[rcp[5]]&(DIGIT|LETTER))) { +				cp = rcp + 5; +				return RETURN; +			} +			goto id; +		case 's': +			if (rcp[0] == 'h' +			&&  rcp[1] == 'o' +			&&  rcp[2] == 'r' +			&&  rcp[3] == 't' +			&& !(map[rcp[4]]&(DIGIT|LETTER))) { +				cp = rcp + 4; +				return SHORT; +			} +			if (rcp[0] == 'i' +			&&  rcp[1] == 'g' +			&&  rcp[2] == 'n' +			&&  rcp[3] == 'e' +			&&  rcp[4] == 'd' +			&& !(map[rcp[5]]&(DIGIT|LETTER))) { +				cp = rcp + 5; +				return SIGNED; +			} +			if (rcp[0] == 'i' +			&&  rcp[1] == 'z' +			&&  rcp[2] == 'e' +			&&  rcp[3] == 'o' +			&&  rcp[4] == 'f' +			&& !(map[rcp[5]]&(DIGIT|LETTER))) { +				cp = rcp + 5; +				return SIZEOF; +			} +			if (rcp[0] == 't' +			&&  rcp[1] == 'a' +			&&  rcp[2] == 't' +			&&  rcp[3] == 'i' +			&&  rcp[4] == 'c' +			&& !(map[rcp[5]]&(DIGIT|LETTER))) { +				cp = rcp + 5; +				return STATIC; +			} +			if (rcp[0] == 't' +			&&  rcp[1] == 'r' +			&&  rcp[2] == 'u' +			&&  rcp[3] == 'c' +			&&  rcp[4] == 't' +			&& !(map[rcp[5]]&(DIGIT|LETTER))) { +				cp = rcp + 5; +				return STRUCT; +			} +			if (rcp[0] == 'w' +			&&  rcp[1] == 'i' +			&&  rcp[2] == 't' +			&&  rcp[3] == 'c' +			&&  rcp[4] == 'h' +			&& !(map[rcp[5]]&(DIGIT|LETTER))) { +				cp = rcp + 5; +				return SWITCH; +			} +			goto id; +		case 't': +			if (rcp[0] == 'y' +			&&  rcp[1] == 'p' +			&&  rcp[2] == 'e' +			&&  rcp[3] == 'd' +			&&  rcp[4] == 'e' +			&&  rcp[5] == 'f' +			&& !(map[rcp[6]]&(DIGIT|LETTER))) { +				cp = rcp + 6; +				return TYPEDEF; +			} +			goto id; +		case 'u': +			if (rcp[0] == 'n' +			&&  rcp[1] == 'i' +			&&  rcp[2] == 'o' +			&&  rcp[3] == 'n' +			&& !(map[rcp[4]]&(DIGIT|LETTER))) { +				cp = rcp + 4; +				return UNION; +			} +			if (rcp[0] == 'n' +			&&  rcp[1] == 's' +			&&  rcp[2] == 'i' +			&&  rcp[3] == 'g' +			&&  rcp[4] == 'n' +			&&  rcp[5] == 'e' +			&&  rcp[6] == 'd' +			&& !(map[rcp[7]]&(DIGIT|LETTER))) { +				cp = rcp + 7; +				return UNSIGNED; +			} +			goto id; +		case 'v': +			if (rcp[0] == 'o' +			&&  rcp[1] == 'i' +			&&  rcp[2] == 'd' +			&& !(map[rcp[3]]&(DIGIT|LETTER))) { +				cp = rcp + 3; +				tsym = voidtype->u.sym; +				return VOID; +			} +			if (rcp[0] == 'o' +			&&  rcp[1] == 'l' +			&&  rcp[2] == 'a' +			&&  rcp[3] == 't' +			&&  rcp[4] == 'i' +			&&  rcp[5] == 'l' +			&&  rcp[6] == 'e' +			&& !(map[rcp[7]]&(DIGIT|LETTER))) { +				cp = rcp + 7; +				return VOLATILE; +			} +			goto id; +		case 'w': +			if (rcp[0] == 'h' +			&&  rcp[1] == 'i' +			&&  rcp[2] == 'l' +			&&  rcp[3] == 'e' +			&& !(map[rcp[4]]&(DIGIT|LETTER))) { +				cp = rcp + 4; +				return WHILE; +			} +			goto id; +		case '_': +			if (rcp[0] == '_' +			&&  rcp[1] == 't' +			&&  rcp[2] == 'y' +			&&  rcp[3] == 'p' +			&&  rcp[4] == 'e' +			&&  rcp[5] == 'c' +			&&  rcp[6] == 'o' +			&&  rcp[7] == 'd' +			&&  rcp[8] == 'e' +			&& !(map[rcp[9]]&(DIGIT|LETTER))) { +				cp = rcp + 9; +				return TYPECODE; +			} +			if (rcp[0] == '_' +			&&  rcp[1] == 'f' +			&&  rcp[2] == 'i' +			&&  rcp[3] == 'r' +			&&  rcp[4] == 's' +			&&  rcp[5] == 't' +			&&  rcp[6] == 'a' +			&&  rcp[7] == 'r' +			&&  rcp[8] == 'g' +			&& !(map[rcp[9]]&(DIGIT|LETTER))) { +				cp = rcp + 9; +				return FIRSTARG; +			} +			goto id; +		default: +			if ((map[cp[-1]]&BLANK) == 0) { +				if (cp[-1] < ' ' || cp[-1] >= 0177) +					error("illegal character `\\0%o'\n", cp[-1]); +				else +					error("illegal character `%c'\n", cp[-1]); +			} +		} +	} +} +static Symbol icon(unsigned long n, int overflow, int base) { +	if (((*cp=='u'||*cp=='U') && (cp[1]=='l'||cp[1]=='L')) +	||  ((*cp=='l'||*cp=='L') && (cp[1]=='u'||cp[1]=='U'))) { +		tval.type = unsignedlong; +		cp += 2; +	} else if (*cp == 'u' || *cp == 'U') { +		if (overflow || n > unsignedtype->u.sym->u.limits.max.i) +			tval.type = unsignedlong; +		else +			tval.type = unsignedtype; +		cp += 1; +	} else if (*cp == 'l' || *cp == 'L') { +		if (overflow || n > longtype->u.sym->u.limits.max.i) +			tval.type = unsignedlong; +		else +			tval.type = longtype; +		cp += 1; +	} else if (overflow || n > longtype->u.sym->u.limits.max.i) +		tval.type = unsignedlong; +	else if (n > inttype->u.sym->u.limits.max.i) +		tval.type = longtype; +	else if (base != 10 && n > inttype->u.sym->u.limits.max.i) +		tval.type = unsignedtype; +	else +		tval.type = inttype; +	switch (tval.type->op) { +	case INT: +		if (overflow || n > tval.type->u.sym->u.limits.max.i) { +			warning("overflow in constant `%S'\n", token, +				(char*)cp - token); +			tval.u.c.v.i = tval.type->u.sym->u.limits.max.i; +		} else +			tval.u.c.v.i = n; +		break; +	case UNSIGNED: +		if (overflow || n > tval.type->u.sym->u.limits.max.u) { +			warning("overflow in constant `%S'\n", token, +				(char*)cp - token); +			tval.u.c.v.u = tval.type->u.sym->u.limits.max.u; +		} else +			tval.u.c.v.u = n; +		break; +	default: assert(0); +	} +	ppnumber("integer"); +	return &tval; +} +static void ppnumber(char *which) { +	unsigned char *rcp = cp--; + +	for ( ; (map[*cp]&(DIGIT|LETTER)) || *cp == '.'; cp++) +		if ((cp[0] == 'E' || cp[0] == 'e') +		&&  (cp[1] == '-' || cp[1] == '+')) +			cp++; +	if (cp > rcp) +		error("`%S' is a preprocessing number but an invalid %s constant\n", token, + +			(char*)cp-token, which); +} +static Symbol fcon(void) { +	if (*cp == '.') +		do +			cp++; +		while (map[*cp]&DIGIT); +	if (*cp == 'e' || *cp == 'E') { +		if (*++cp == '-' || *cp == '+') +			cp++; +		if (map[*cp]&DIGIT) +			do +				cp++; +			while (map[*cp]&DIGIT); +		else +			error("invalid floating constant `%S'\n", token, +				(char*)cp - token); +	} + +	errno = 0; +	tval.u.c.v.d = strtod(token, NULL); +	if (errno == ERANGE) +		warning("overflow in floating constant `%S'\n", token, +			(char*)cp - token); +	if (*cp == 'f' || *cp == 'F') { +		++cp; +		if (tval.u.c.v.d > floattype->u.sym->u.limits.max.d) +			warning("overflow in floating constant `%S'\n", token, +				(char*)cp - token); +		tval.type = floattype; +	} else if (*cp == 'l' || *cp == 'L') { +		cp++; +		tval.type = longdouble; +	} else { +		if (tval.u.c.v.d > doubletype->u.sym->u.limits.max.d) +			warning("overflow in floating constant `%S'\n", token, +				(char*)cp - token); +		tval.type = doubletype; +	} +	ppnumber("floating"); +	return &tval; +} + +static void *cput(int c, void *cl) { +	char *s = cl; + +	if (c < 0 || c > 255) +		warning("overflow in escape sequence with resulting value `%d'\n", c); +	*s++ = c; +	return s; +} + +static void *wcput(int c, void *cl) { +	unsigned int *s = cl; + +	*s++ = c; +	return s; +} + +static void *scon(int q, void *put(int c, void *cl), void *cl) { +	int n = 0, nbad = 0; + +	do { +		cp++; +		while (*cp != q) { +			int c; +			if (map[*cp]&NEWLINE) { +				if (cp < limit) +					break; +				cp++; +				nextline(); +				if (cp == limit) +					break; +				continue; +			} +			c = *cp++; +			if (c == '\\') { +				if (map[*cp]&NEWLINE) { +					if (cp < limit) +						break; +					cp++; +					nextline(); +				} +				if (limit - cp < MAXTOKEN) +					fillbuf(); +				c = backslash(q); +			} else if (c < 0 || c > 255 || map[c] == 0) +				nbad++; +			if (n++ < BUFSIZE) +				cl = put(c, cl); +		} +		if (*cp == q) +			cp++; +		else +			error("missing %c\n", q); +	} while (q == '"' && getchr() == '"'); +	cl = put(0, cl); +	if (n >= BUFSIZE) +		error("%s literal too long\n", q == '"' ? "string" : "character"); +	if (Aflag >= 2 && q == '"' && n > 509) +		warning("more than 509 characters in a string literal\n"); +	if (Aflag >= 2 && nbad > 0) +		warning("%s literal contains non-portable characters\n", +			q == '"' ? "string" : "character"); +	return cl; +} +int getchr(void) { +	for (;;) { +		while (map[*cp]&BLANK) +			cp++; +		if (!(map[*cp]&NEWLINE)) +			return *cp; +		cp++; +		nextline(); +		if (cp == limit) +			return EOI; +	} +} +static int backslash(int q) { +	unsigned int c; + +	switch (*cp++) { +	case 'a': return 7; +	case 'b': return '\b'; +	case 'f': return '\f'; +	case 'n': return '\n'; +	case 'r': return '\r'; +	case 't': return '\t'; +	case 'v': return '\v'; +	case '\'': case '"': case '\\': case '\?': break; +	case 'x': { +		int overflow = 0; +		if ((map[*cp]&(DIGIT|HEX)) == 0) { +			if (*cp < ' ' || *cp == 0177) +				error("ill-formed hexadecimal escape sequence\n"); +			else +				error("ill-formed hexadecimal escape sequence `\\x%c'\n", *cp); +			if (*cp != q) +				cp++; +			return 0; +		} +		for (c = 0; map[*cp]&(DIGIT|HEX); cp++) { +			if (c >> (8*widechar->size - 4)) +				overflow = 1; +			if (map[*cp]&DIGIT) +				c = (c<<4) + *cp - '0'; +			else +				c = (c<<4) + (*cp&~040) - 'A' + 10; +		} +		if (overflow) +			warning("overflow in hexadecimal escape sequence\n"); +		return c&ones(8*widechar->size); +		} +	case '0': case '1': case '2': case '3': +	case '4': case '5': case '6': case '7': +		c = *(cp-1) - '0'; +		if (*cp >= '0' && *cp <= '7') { +			c = (c<<3) + *cp++ - '0'; +			if (*cp >= '0' && *cp <= '7') +				c = (c<<3) + *cp++ - '0'; +		} +		return c; +	default: +		if (cp[-1] < ' ' || cp[-1] >= 0177) +			warning("unrecognized character escape sequence\n"); +		else +			warning("unrecognized character escape sequence `\\%c'\n", cp[-1]); +	} +	return cp[-1]; +} diff --git a/src/tools/lcc/src/list.c b/src/tools/lcc/src/list.c new file mode 100644 index 0000000..29e660a --- /dev/null +++ b/src/tools/lcc/src/list.c @@ -0,0 +1,56 @@ +#include "c.h" + + +static List freenodes;		/* free list nodes */ + +/* append - append x to list, return new list */ +List append(void *x, List list) { +	List new; + +	if ((new = freenodes) != NULL) +		freenodes = freenodes->link; +	else +		NEW(new, PERM); +	if (list) { +		new->link = list->link; +		list->link = new; +	} else +		new->link = new; +	new->x = x; +	return new; +} + +/* length - # elements in list */ +int length(List list) { +	int n = 0; + +	if (list) { +		List lp = list; +		do +			n++; +		while ((lp = lp->link) != list); +	} +	return n; +} + +/* ltov - convert list to an NULL-terminated vector allocated in arena */ +void *ltov(List *list, unsigned arena) { +	int i = 0; +	void **array = newarray(length(*list) + 1, sizeof array[0], arena); + +	if (*list) { +		List lp = *list; +		do { +			lp = lp->link; +			array[i++] = lp->x; +		} while (lp != *list); +#ifndef PURIFY +		lp = (*list)->link; +		(*list)->link = freenodes; +		freenodes = lp; +#endif +	} +	*list = NULL; +	array[i] = NULL; +	return array; +} diff --git a/src/tools/lcc/src/main.c b/src/tools/lcc/src/main.c new file mode 100644 index 0000000..63b85f2 --- /dev/null +++ b/src/tools/lcc/src/main.c @@ -0,0 +1,225 @@ +#include "c.h" + +static char rcsid[] = "main.c - faked rcsid"; + +static void typestab(Symbol, void *); + +static void stabline(Coordinate *); +static void stabend(Coordinate *, Symbol, Coordinate **, Symbol *, Symbol *); +Interface *IR = NULL; + +int Aflag;		/* >= 0 if -A specified */ +int Pflag;		/* != 0 if -P specified */ +int glevel;		/* == [0-9] if -g[0-9] specified */ +int xref;		/* != 0 for cross-reference data */ +Symbol YYnull;		/* _YYnull  symbol if -n or -nvalidate specified */ +Symbol YYcheck;		/* _YYcheck symbol if -nvalidate,check specified */ + +static char *comment; +static Interface stabIR; +static char *currentfile;       /* current file name */ +static int currentline;		/* current line number */ +static FILE *srcfp;		/* stream for current file, if non-NULL */ +static int srcpos;		/* position of srcfp, if srcfp is non-NULL */ +int main(int argc, char *argv[]) { +	int i, j; +	for (i = argc - 1; i > 0; i--) +		if (strncmp(argv[i], "-target=", 8) == 0) +			break; +	if (i > 0) { +		char *s = strchr(argv[i], '\\'); +		if (s != NULL) +			*s = '/'; +		for (j = 0; bindings[j].name && bindings[j].ir; j++) +			if (strcmp(&argv[i][8], bindings[j].name) == 0) { +				IR = bindings[j].ir; +				break; +			} +		if (s != NULL) +			*s = '\\'; +	} +	if (!IR) { +		fprint(stderr, "%s: unknown target", argv[0]); +		if (i > 0) +			fprint(stderr, " `%s'", &argv[i][8]); +		fprint(stderr, "; must specify one of\n"); +		for (i = 0; bindings[i].name; i++) +			fprint(stderr, "\t-target=%s\n", bindings[i].name); +		exit(EXIT_FAILURE); +	} +	init(argc, argv); +	t = gettok(); +	(*IR->progbeg)(argc, argv); +	if (glevel && IR->stabinit) +		(*IR->stabinit)(firstfile, argc, argv); +	program(); +	if (events.end) +		apply(events.end, NULL, NULL); +	memset(&events, 0, sizeof events); +	if (glevel || xref) { +		Symbol symroot = NULL; +		Coordinate src; +		foreach(types,       GLOBAL, typestab, &symroot); +		foreach(identifiers, GLOBAL, typestab, &symroot); +		src.file = firstfile; +		src.x = 0; +		src.y = lineno; +		if ((glevel > 2 || xref) && IR->stabend) +			(*IR->stabend)(&src, symroot, +				ltov(&loci,    PERM), +				ltov(&symbols, PERM), NULL); +		else if (IR->stabend) +			(*IR->stabend)(&src, NULL, NULL, NULL, NULL); +	} +	finalize(); +	(*IR->progend)(); +	deallocate(PERM); +	return errcnt > 0; +} +/* main_init - process program arguments */ +void main_init(int argc, char *argv[]) { +	char *infile = NULL, *outfile = NULL; +	int i; +	static int inited; + +	if (inited) +		return; +	inited = 1; +	type_init(argc, argv); +	for (i = 1; i < argc; i++) +		if (strcmp(argv[i], "-g") == 0 || strcmp(argv[i], "-g2") == 0) +			glevel = 2; +		else if (strncmp(argv[i], "-g", 2) == 0) {	/* -gn[,x] */ +			char *p = strchr(argv[i], ','); +			glevel = atoi(argv[i]+2); +			if (p) { +				comment = p + 1; +				if (glevel == 0) +					glevel = 1; +				if (stabIR.stabline == NULL) { +					stabIR.stabline = IR->stabline; +					stabIR.stabend = IR->stabend; +					IR->stabline = stabline; +					IR->stabend = stabend; +				} +			}	 +		} else if (strcmp(argv[i], "-x") == 0) +			xref++; +		else if (strcmp(argv[i], "-A") == 0) { +			++Aflag; +		} else if (strcmp(argv[i], "-P") == 0) +			Pflag++; +		else if (strcmp(argv[i], "-w") == 0) +			wflag++; +		else if (strcmp(argv[i], "-n") == 0) { +			if (!YYnull) { +				YYnull = install(string("_YYnull"), &globals, GLOBAL, PERM); +				YYnull->type = func(voidptype, NULL, 1); +				YYnull->sclass = EXTERN; +				(*IR->defsymbol)(YYnull); +			} +		} else if (strncmp(argv[i], "-n", 2) == 0) {	/* -nvalid[,check] */ +			char *p = strchr(argv[i], ','); +			if (p) { +				YYcheck = install(string(p+1), &globals, GLOBAL, PERM); +				YYcheck->type = func(voidptype, NULL, 1); +				YYcheck->sclass = EXTERN; +				(*IR->defsymbol)(YYcheck); +				p = stringn(argv[i]+2, p - (argv[i]+2)); +			} else +				p = string(argv[i]+2); +			YYnull = install(p, &globals, GLOBAL, PERM); +			YYnull->type = func(voidptype, NULL, 1); +			YYnull->sclass = EXTERN; +			(*IR->defsymbol)(YYnull); +		} else if (strcmp(argv[i], "-v") == 0) +			fprint(stderr, "%s %s\n", argv[0], rcsid); +		else if (strncmp(argv[i], "-s", 2) == 0) +			density = strtod(&argv[i][2], NULL); +		else if (strncmp(argv[i], "-errout=", 8) == 0) { +			FILE *f = fopen(argv[i]+8, "w"); +			if (f == NULL) { +				fprint(stderr, "%s: can't write errors to `%s'\n", argv[0], argv[i]+8); +				exit(EXIT_FAILURE); +			} +			fclose(f); +			f = freopen(argv[i]+8, "w", stderr); +			assert(f); +		} else if (strncmp(argv[i], "-e", 2) == 0) { +			int x; +			if ((x = strtol(&argv[i][2], NULL, 0)) > 0) +				errlimit = x; +		} else if (strncmp(argv[i], "-little_endian=", 15) == 0) +			IR->little_endian = argv[i][15] - '0'; +		else if (strncmp(argv[i], "-mulops_calls=", 18) == 0) +			IR->mulops_calls = argv[i][18] - '0'; +		else if (strncmp(argv[i], "-wants_callb=", 13) == 0) +			IR->wants_callb = argv[i][13] - '0'; +		else if (strncmp(argv[i], "-wants_argb=", 12) == 0) +			IR->wants_argb = argv[i][12] - '0'; +		else if (strncmp(argv[i], "-left_to_right=", 15) == 0) +			IR->left_to_right = argv[i][15] - '0'; +		else if (strncmp(argv[i], "-wants_dag=", 11) == 0) +			IR->wants_dag = argv[i][11] - '0'; +		else if (*argv[i] != '-' || strcmp(argv[i], "-") == 0) { +			if (infile == NULL) +				infile = argv[i]; +			else if (outfile == NULL) +				outfile = argv[i]; +		} + +	if (infile != NULL && strcmp(infile, "-") != 0 +	&& freopen(infile, "r", stdin) == NULL) { +		fprint(stderr, "%s: can't read `%s'\n", argv[0], infile); +		exit(EXIT_FAILURE); +	} +	if (outfile != NULL && strcmp(outfile, "-") != 0 +	&& freopen(outfile, "w", stdout) == NULL) { +		fprint(stderr, "%s: can't write `%s'\n", argv[0], outfile); +		exit(EXIT_FAILURE); +	} +} +/* typestab - emit stab entries for p */ +static void typestab(Symbol p, void *cl) { +	if (*(Symbol *)cl == 0 && p->sclass && p->sclass != TYPEDEF) +		*(Symbol *)cl = p; +	if ((p->sclass == TYPEDEF || p->sclass == 0) && IR->stabtype) +		(*IR->stabtype)(p); +} + +/* stabline - emit source code for source coordinate *cp */ +static void stabline(Coordinate *cp) { +	if (cp->file && cp->file != currentfile) { +		if (srcfp) +			fclose(srcfp); +		currentfile = cp->file; +		srcfp = fopen(currentfile, "r"); +		srcpos = 0; +		currentline = 0; +	} +	if (currentline != cp->y && srcfp) { +		char buf[512]; +		if (srcpos > cp->y) { +			rewind(srcfp); +			srcpos = 0; +		} +		for ( ; srcpos < cp->y; srcpos++) +			if (fgets(buf, sizeof buf, srcfp) == NULL) { +				fclose(srcfp); +				srcfp = NULL; +				break; +			} +		if (srcfp && srcpos == cp->y) +			print("%s%s", comment, buf); +	} +	currentline = cp->y; +	if (stabIR.stabline) +		(*stabIR.stabline)(cp); +} + +static void stabend(Coordinate *cp, Symbol p, Coordinate **cpp, Symbol *sp, Symbol *stab) { +	if (stabIR.stabend) +		(*stabIR.stabend)(cp, p, cpp, sp, stab); +	if (srcfp) +		fclose(srcfp); +} diff --git a/src/tools/lcc/src/null.c b/src/tools/lcc/src/null.c new file mode 100644 index 0000000..b9f551c --- /dev/null +++ b/src/tools/lcc/src/null.c @@ -0,0 +1,74 @@ +#include "c.h" +#define I(f) null_##f + +static Node I(gen)(Node p) { return p; } +static void I(address)(Symbol q, Symbol p, long n) {} +static void I(blockbeg)(Env *e) {} +static void I(blockend)(Env *e) {} +static void I(defaddress)(Symbol p) {} +static void I(defconst)(int suffix, int size, Value v) {} +static void I(defstring)(int len, char *s) {} +static void I(defsymbol)(Symbol p) {} +static void I(emit)(Node p) {} +static void I(export)(Symbol p) {} +static void I(function)(Symbol f, Symbol caller[], Symbol callee[], int ncalls) {} +static void I(global)(Symbol p) {} +static void I(import)(Symbol p) {} +static void I(local)(Symbol p) {} +static void I(progbeg)(int argc, char *argv[]) {} +static void I(progend)(void) {} +static void I(segment)(int s) {} +static void I(space)(int n) {} +static void I(stabblock)(int brace, int lev, Symbol *p) {} +static void I(stabend)(Coordinate *cp, Symbol p, Coordinate **cpp, Symbol *sp, Symbol *stab) {} +static void I(stabfend)(Symbol p, int lineno) {} +static void I(stabinit)(char *file, int argc, char *argv[]) {} +static void I(stabline)(Coordinate *cp) {} +static void I(stabsym)(Symbol p) {} +static void I(stabtype)(Symbol p) {} + + +Interface nullIR = { +	{1, 1, 0},	/* char */ +	{2, 2, 0},	/* short */ +	{4, 4, 0},	/* int */ +	{8, 8, 1},	/* long */ +	{8 ,8, 1},	/* long long */ +	{4, 4, 1},	/* float */ +	{8, 8, 1},	/* double */ +	{16,16,1},	/* long double */ +	{4, 4, 0},	/* T* */ +	{0, 4, 0},	/* struct */ +	1,		/* little_endian */ +	0,		/* mulops_calls */ +	0,		/* wants_callb */ +	0,		/* wants_argb */ +	1,		/* left_to_right */ +	0,		/* wants_dag */ +	0,		/* unsigned_char */ +	I(address), +	I(blockbeg), +	I(blockend), +	I(defaddress), +	I(defconst), +	I(defstring), +	I(defsymbol), +	I(emit), +	I(export), +	I(function), +	I(gen), +	I(global), +	I(import), +	I(local), +	I(progbeg), +	I(progend), +	I(segment), +	I(space), +	I(stabblock), +	I(stabend), +	I(stabfend), +	I(stabinit), +	I(stabline), +	I(stabsym), +	I(stabtype) +}; diff --git a/src/tools/lcc/src/output.c b/src/tools/lcc/src/output.c new file mode 100644 index 0000000..a9c93e7 --- /dev/null +++ b/src/tools/lcc/src/output.c @@ -0,0 +1,135 @@ +#include "c.h" + + +static char *outs(const char *str, FILE *f, char *bp) { +	if (f) +		fputs(str, f); +	else +		while ((*bp = *str++)) +			bp++; +	return bp; +} + +static char *outd(long n, FILE *f, char *bp) { +	unsigned long m; +	char buf[25], *s = buf + sizeof buf; + +	*--s = '\0'; +	if (n < 0) +		m = -n; +	else +		m = n; +	do +		*--s = m%10 + '0'; +	while ((m /= 10) != 0); +	if (n < 0) +		*--s = '-'; +	return outs(s, f, bp); +} + +static char *outu(unsigned long n, int base, FILE *f, char *bp) { +	char buf[25], *s = buf + sizeof buf; + +	*--s = '\0'; +	do +		*--s = "0123456789abcdef"[n%base]; +	while ((n /= base) != 0); +	return outs(s, f, bp); +} +void print(const char *fmt, ...) { +	va_list ap; + +	va_start(ap, fmt); +	vfprint(stdout, NULL, fmt, ap); +	va_end(ap); +} +/* fprint - formatted output to  f */ +void fprint(FILE *f, const char *fmt, ...) { +	va_list ap; + +	va_start(ap, fmt); +	vfprint(f, NULL, fmt, ap); +	va_end(ap); +} + +/* stringf - formatted output to a saved string */ +char *stringf(const char *fmt, ...) { +	char buf[1024]; +	va_list ap; + +	va_start(ap, fmt); +	vfprint(NULL, buf, fmt, ap); +	va_end(ap); +	return string(buf); +} + +/* vfprint - formatted output to f or string bp */ +void vfprint(FILE *f, char *bp, const char *fmt, va_list ap) { +	for (; *fmt; fmt++) +		if (*fmt == '%') +			switch (*++fmt) { +			case 'd': bp = outd(va_arg(ap, int), f, bp); break; +			case 'D': bp = outd(va_arg(ap, long), f, bp); break; +			case 'U': bp = outu(va_arg(ap, unsigned long), 10, f, bp); break; +			case 'u': bp = outu(va_arg(ap, unsigned), 10, f, bp); break; +			case 'o': bp = outu(va_arg(ap, unsigned), 8, f, bp); break; +			case 'X': bp = outu(va_arg(ap, unsigned long), 16, f, bp); break; +			case 'x': bp = outu(va_arg(ap, unsigned), 16, f, bp); break; +			case 'f': case 'e': +			case 'g': { +				  	static char format[] = "%f"; +				  	char buf[128]; +				  	format[1] = *fmt; +				  	sprintf(buf, format, va_arg(ap, double)); +				  	bp = outs(buf, f, bp); +				  } +; break; +			case 's': bp = outs(va_arg(ap, char *), f, bp); break; +			case 'p': { +				void *p = va_arg(ap, void *); +				if (p) +					bp = outs("0x", f, bp); +				bp = outu((unsigned long)p, 16, f, bp); +				break; +				  } +			case 'c': if (f) fputc(va_arg(ap, int), f); else *bp++ = va_arg(ap, int); break; +			case 'S': { char *s = va_arg(ap, char *); +				    int n = va_arg(ap, int); +				    if (s) { +				    	for ( ; n-- > 0; s++) +				    		if (f) (void)putc(*s, f); else *bp++ = *s; +				    } + } break; +			case 'k': { int t = va_arg(ap, int); +				    static char *tokens[] = { +#define xx(a,b,c,d,e,f,g) g, +#define yy(a,b,c,d,e,f,g) g, +#include "token.h" +				    }; +				    assert(tokens[t&0177]); +				    bp = outs(tokens[t&0177], f, bp); + } break; +			case 't': { Type ty = va_arg(ap, Type); +				    assert(f); +				    outtype(ty ? ty : voidtype, f); + } break; +			case 'w': { Coordinate *p = va_arg(ap, Coordinate *); +				    if (p->file && *p->file) { +				    	bp = outs(p->file, f, bp); +				    	bp = outs(":", f, bp); +				    } +				    bp = outd(p->y, f, bp); + } break; +			case 'I': { int n = va_arg(ap, int); +				    while (--n >= 0) +				    	if (f) (void)putc(' ', f); else *bp++ = ' '; + } break; +			default:  if (f) (void)putc(*fmt, f); else *bp++ = *fmt; break; +			} +		else if (f) +			(void)putc(*fmt, f); +		else +			*bp++ = *fmt; +	if (!f) +		*bp = '\0'; +} diff --git a/src/tools/lcc/src/prof.c b/src/tools/lcc/src/prof.c new file mode 100644 index 0000000..02709ed --- /dev/null +++ b/src/tools/lcc/src/prof.c @@ -0,0 +1,228 @@ +#include "c.h" + + +struct callsite { +	char *file, *name; +	union coordinate { +		unsigned int coord; +		struct { unsigned int y:16,x:10,index:6; } le; +		struct { unsigned int index:6,x:10,y:16; } be; +	} u; +}; +struct func { +	struct func *link; +	struct caller *callers; +	char *name; +	union coordinate src; +}; +struct map {		/* source code map; 200 coordinates/map */ +	int size; +	union coordinate u[200]; +}; + +int npoints;		/* # of execution points if -b specified */ +int ncalled = -1;	/* #times prof.out says current function was called */ +static Symbol YYlink;	/* symbol for file's struct _bbdata */ +static Symbol YYcounts;	/* symbol for _YYcounts if -b specified */ +static List maplist;	/* list of struct map *'s */ +static List filelist;	/* list of file names */ +static Symbol funclist;	/* list of struct func *'s */ +static Symbol afunc;	/* current function's struct func */ + +/* bbcall - build tree to set _callsite at call site *cp, emit call site data */ +static void bbcall(Symbol yycounts, Coordinate *cp, Tree *e) { +	static Symbol caller; +	Value v; +	union coordinate u; +	Symbol p = genident(STATIC, array(voidptype, 0, 0), GLOBAL); +	Tree t = *e; + +	defglobal(p, LIT); +	defpointer(cp->file ? mkstr(cp->file)->u.c.loc : (Symbol)0); +	defpointer(mkstr(cfunc->name)->u.c.loc); +	if (IR->little_endian) { +		u.le.x = cp->x; +		u.le.y = cp->y; +	} else { +		u.be.x = cp->x; +		u.be.y = cp->y; +	} +	(*IR->defconst)(U, unsignedtype->size, (v.u = u.coord, v)); +	if (caller == 0) { +		caller = mksymbol(EXTERN, "_caller", ptr(voidptype)); +		caller->defined = 0; +	} +	if (generic((*e)->op) != CALL) +		t = (*e)->kids[0]; +	assert(generic(t->op) == CALL); +	t = tree(t->op, t->type, +		tree(RIGHT, t->kids[0]->type, +			t->kids[0], +			tree(RIGHT, t->kids[0]->type, asgn(caller, idtree(p)), t->kids[0])), +		t->kids[1]); +	if (generic((*e)->op) != CALL) +		t = tree((*e)->op, (*e)->type, t, (*e)->kids[1]); +	*e = t; +} + +/* bbentry - return tree for _prologue(&afunc, &YYlink)' */ +static void bbentry(Symbol yylink, Symbol f) { +	static Symbol prologue; +	 +	afunc = genident(STATIC, array(voidptype, 4, 0), GLOBAL); +	if (prologue == 0) { +		prologue = mksymbol(EXTERN, "_prologue", ftype(inttype, voidptype)); +		prologue->defined = 0; +	} +	walk(vcall(prologue, voidtype, pointer(idtree(afunc)), pointer(idtree(yylink)), NULL), 0, 0); + +} + +/* bbexit - return tree for _epilogue(&afunc)' */ +static void bbexit(Symbol yylink, Symbol f, Tree e) { +	static Symbol epilogue; +	 +	if (epilogue == 0) { +		epilogue = mksymbol(EXTERN, "_epilogue", ftype(inttype, voidptype)); +		epilogue->defined = 0; +	} +	walk(vcall(epilogue, voidtype, pointer(idtree(afunc)), NULL), 0, 0); +} + +/* bbfile - add file to list of file names, return its index */ +static int bbfile(char *file) { +	if (file) { +		List lp; +		int i = 1; +		if ((lp = filelist) != NULL) +			do { +				lp = lp->link; +				if (((Symbol)lp->x)->u.c.v.p == file) +					return i; +				i++; +			} while (lp != filelist); +		filelist = append(mkstr(file), filelist); +		return i; +	} +	return 0; +} + +/* bbfunc - emit function name and src coordinates */ +static void bbfunc(Symbol yylink, Symbol f) { +	Value v; +	union coordinate u; + +	defglobal(afunc, DATA); +	defpointer(funclist); +	defpointer(NULL); +	defpointer(mkstr(f->name)->u.c.loc); +	if (IR->little_endian) { +		u.le.x = f->u.f.pt.x; +		u.le.y = f->u.f.pt.y; +		u.le.index = bbfile(f->u.f.pt.file); +	} else { +		u.be.x = f->u.f.pt.x; +		u.be.y = f->u.f.pt.y; +		u.be.index = bbfile(f->u.f.pt.file); +	} +	(*IR->defconst)(U, unsignedtype->size, (v.u = u.coord, v)); +	funclist = afunc; +} + +/* bbincr - build tree to increment execution point at *cp */ +static void bbincr(Symbol yycounts, Coordinate *cp, Tree *e) { +	struct map *mp = maplist->x; +	Tree t; + +	/* append *cp to source map */ +	if (mp->size >= NELEMS(mp->u)) { +		NEW(mp, PERM); +		mp->size = 0; +		maplist = append(mp, maplist); +	} +	if (IR->little_endian) { +		mp->u[mp->size].le.x = cp->x; +		mp->u[mp->size].le.y = cp->y; +		mp->u[mp->size++].le.index = bbfile(cp->file); +	} else { +		mp->u[mp->size].be.x = cp->x; +		mp->u[mp->size].be.y = cp->y; +		mp->u[mp->size++].be.index = bbfile(cp->file); +	} +	t = incr('+', rvalue((*optree['+'])(ADD, pointer(idtree(yycounts)), +		consttree(npoints++, inttype))), consttree(1, inttype)); +	if (*e) +		*e = tree(RIGHT, (*e)->type, t, *e); +	else +		*e = t; +} + +/* bbvars - emit definition for basic block counting data */ +static void bbvars(Symbol yylink) { +	int i, j, n = npoints; +	Value v; +	struct map **mp; +	Symbol coords, files, *p; + +	if (!YYcounts && !yylink) +		return; +	if (YYcounts) { +		if (n <= 0) +			n = 1; +		YYcounts->type = array(unsignedtype, n, 0); +		defglobal(YYcounts, BSS); +	} +	files = genident(STATIC, array(charptype, 1, 0), GLOBAL); +	defglobal(files, LIT); +	for (p = ltov(&filelist, PERM); *p; p++) +		defpointer((*p)->u.c.loc); +	defpointer(NULL); +	coords = genident(STATIC, array(unsignedtype, n, 0), GLOBAL); +	defglobal(coords, LIT); +	for (i = n, mp = ltov(&maplist, PERM); *mp; i -= (*mp)->size, mp++) +		for (j = 0; j < (*mp)->size; j++) +			(*IR->defconst)(U, unsignedtype->size, (v.u = (*mp)->u[j].coord, v)); +	if (i > 0) +		(*IR->space)(i*coords->type->type->size); +	defpointer(NULL); +	defglobal(yylink, DATA); +	defpointer(NULL); +	(*IR->defconst)(U, unsignedtype->size, (v.u = n, v)); +	defpointer(YYcounts); +	defpointer(coords); +	defpointer(files); +	defpointer(funclist); +} + +/* profInit - initialize basic block profiling options */ +void prof_init(int argc, char *argv[]) { +	int i; +	static int inited; + +	if (inited) +		return; +	inited = 1; +	type_init(argc, argv); +	if (IR) { +		for (i = 1; i < argc; i++) +			if (strncmp(argv[i], "-a", 2) == 0) { +				if (ncalled == -1 +				&& process(argv[i][2] ? &argv[i][2] : "prof.out") > 0) +					ncalled = 0; +			} else if ((strcmp(argv[i], "-b") == 0 +			         || strcmp(argv[i], "-C") == 0) && YYlink == 0) { +				YYlink = genident(STATIC, array(unsignedtype, 0, 0), GLOBAL); +				attach((Apply)bbentry, YYlink, &events.entry); +				attach((Apply)bbexit,  YYlink, &events.returns); +				attach((Apply)bbfunc,  YYlink, &events.exit); +				attach((Apply)bbvars,  YYlink, &events.end); +				if (strcmp(argv[i], "-b") == 0) { +					YYcounts = genident(STATIC, array(unsignedtype, 0, 0), GLOBAL); +					maplist = append(allocate(sizeof (struct map), PERM), maplist); +					((struct map *)maplist->x)->size = 0; +					attach((Apply)bbcall, YYcounts, &events.calls); +					attach((Apply)bbincr, YYcounts, &events.points); +				} +			} +  } +} diff --git a/src/tools/lcc/src/profio.c b/src/tools/lcc/src/profio.c new file mode 100644 index 0000000..37fc25b --- /dev/null +++ b/src/tools/lcc/src/profio.c @@ -0,0 +1,276 @@ +/* C compiler: prof.out input + +prof.out format: +#files +    name +    ... (#files-1 times) +#functions +    name file# x y count caller file x y  +    ... (#functions-1 times) +#points +    file# x y count +    ... (#points-1 times) +*/ +#include "c.h" + + +struct count {			/* count data: */ +	int x, y;			/* source coordinate */ +	int count;			/* associated execution count */ +}; + +#define MAXTOKEN 64 + +struct file {			/* per-file prof.out data: */ +	struct file *link;		/* link to next file */ +	char *name;			/* file name */ +	int size;			/* size of counts[] */ +	int count;			/* counts[0..count-1] hold valid data */ +	struct count *counts;		/* count data */ +	struct func {			/* function data: */ +		struct func *link;		/* link to next function */ +		char *name;			/* function name */ +		struct count count;		/* total number of calls */ +		struct caller {		/* caller data: */ +			struct caller *link;	/* link to next caller */ +			char *name;		/* caller's name */ +			char *file;		/* call site: file, x, y */ +			int x, y; +			int count;		/* number of calls from this site */ +		} *callers; +	} *funcs;			/* list of functions */ +} *filelist; +FILE *fp; + +/* acaller - add caller and site (file,x,y) to callee's callers list */ +static void acaller(char *caller, char *file, int x, int y, int count, struct func *callee) { +	struct caller *q; + +	assert(callee); +	for (q = callee->callers; q && (caller != q->name +		|| file != q->file || x != q->x || y != q->y); q = q->link) +		; +	if (!q) { +		struct caller **r; +		NEW(q, PERM); +		q->name = caller; +		q->file = file; +		q->x = x; +		q->y = y; +		q->count = 0; +		for (r = &callee->callers; *r && (strcmp(q->name, (*r)->name) > 0 +			|| strcmp(q->file, (*r)->file) > 0 || q->y > (*r)->y || q->y > (*r)->y); r = &(*r)->link) +			; +		q->link = *r; +		*r = q; +	} +	q->count += count; +} + +/* compare - return <0, 0, >0 if a<b, a==b, a>b, resp. */ +static int compare(struct count *a, struct count *b) { +	if (a->y == b->y) +		return a->x - b->x; +	return a->y - b->y; +} + +/* findfile - return file name's file list entry, or 0 */ +static struct file *findfile(char *name) { +	struct file *p; + +	for (p = filelist; p; p = p->link) +		if (p->name == name) +			return p; +	return 0; +} + +/* afunction - add function name and its data to file's function list */ +static struct func *afunction(char *name, char *file, int x, int y, int count) { +	struct file *p = findfile(file); +	struct func *q; + +	assert(p); +	for (q = p->funcs; q && name != q->name; q = q->link) +		; +	if (!q) { +		struct func **r; +		NEW(q, PERM); +		q->name = name; +		q->count.x = x; +		q->count.y = y; +		q->count.count = 0; +		q->callers = 0; +		for (r = &p->funcs; *r && compare(&q->count, &(*r)->count) > 0; r = &(*r)->link) +			; +		q->link = *r; +		*r = q; +	} +	q->count.count += count; +	return q; +} + +/* apoint - append execution point i to file's data */  +static void apoint(int i, char *file, int x, int y, int count) { +	struct file *p = findfile(file); + +	assert(p); +	if (i >= p->size) { +		int j; +		if (p->size == 0) { +			p->size = i >= 200 ? 2*i : 200; +			p->counts = newarray(p->size, sizeof *p->counts, PERM); +		} else { +			struct count *new; +			p->size = 2*i; +			new = newarray(p->size, sizeof *new, PERM); +			for (j = 0; j < p->count; j++) +				new[j] = p->counts[j]; +			p->counts = new; +		} +		for (j = p->count; j < p->size; j++) { +			static struct count z; +			p->counts[j] = z; +		} +	} +	p->counts[i].x = x; +	p->counts[i].y = y; +	p->counts[i].count += count; +	if (i >= p->count) +		p->count = i + 1; +} + +/* findcount - return count associated with (file,x,y) or -1 */ +int findcount(char *file, int x, int y) { +	static struct file *cursor; + +	if (cursor == 0 || cursor->name != file) +		cursor = findfile(file); +	if (cursor) { +		int l, u; +		struct count *c = cursor->counts; +		for (l = 0, u = cursor->count - 1; l <= u; ) { +			int k = (l + u)/2; +			if (c[k].y > y || (c[k].y == y && c[k].x > x)) +				u = k - 1; +			else if (c[k].y < y || (c[k].y == y && c[k].x < x)) +				l = k + 1; +			else +				return c[k].count; +		} +	} +	return -1; +} + +/* findfunc - return count associated with function name in file or -1 */ +int findfunc(char *name, char *file) { +	static struct file *cursor; + +	if (cursor == 0 || cursor->name != file) +		cursor = findfile(file); +	if (cursor) { +		struct func *p; +		for (p = cursor->funcs; p; p = p->link) +			if (p->name == name) +				return p->count.count; +	} +	return -1; +} + +/* getd - read a nonnegative number */ +static int getd(void) { +	int c, n = 0; + +	while ((c = getc(fp)) != EOF && (c == ' ' || c == '\n' || c == '\t')) +		; +	if (c >= '0' && c <= '9') { +		do +			n = 10*n + (c - '0'); +		while ((c = getc(fp)) >= '0' && c <= '9'); +		return n; +	} +	return -1; +} + +/* getstr - read a string */ +static char *getstr(void) { +	int c; +	char buf[MAXTOKEN], *s = buf; + +	while ((c = getc(fp)) != EOF && c != ' ' && c != '\n' && c != '\t') +		if (s - buf < (int)sizeof buf - 2) +			*s++ = c; +	*s = 0; +	return s == buf ? (char *)0 : string(buf); +} + +/* gather - read prof.out data from fd */ +static int gather(void) { +	int i, nfiles, nfuncs, npoints; +	char *files[64]; + +	if ((nfiles = getd()) < 0) +		return 0; +	assert(nfiles < NELEMS(files)); +	for (i = 0; i < nfiles; i++) { +		if ((files[i] = getstr()) == 0) +			return -1; +		if (!findfile(files[i])) { +			struct file *new; +			NEW(new, PERM); +			new->name = files[i]; +			new->size = new->count = 0; +			new->counts = 0; +			new->funcs = 0; +			new->link = filelist; +			filelist = new; +		} +	} +	if ((nfuncs = getd()) < 0) +		return -1; +	for (i = 0; i < nfuncs; i++) { +		struct func *q; +		char *name, *file; +		int f, x, y, count; +		if ((name = getstr()) == 0 || (f = getd()) <= 0 +		|| (x = getd()) < 0 || (y = getd()) < 0 || (count = getd()) < 0) +			return -1; +		q = afunction(name, files[f-1], x, y, count); +		if ((name = getstr()) == 0 || (file = getstr()) == 0 +		|| (x = getd()) < 0 || (y = getd()) < 0) +			return -1; +		if (*name != '?') +			acaller(name, file, x, y, count, q); +	} +	if ((npoints = getd()) < 0) +		return -1; +	for (i = 0; i < npoints; i++) { +		int f, x, y, count; +		if ((f = getd()) < 0 || (x = getd()) < 0 || (y = getd()) < 0 +		|| (count = getd()) < 0) +			return -1; +		if (f) +			apoint(i, files[f-1], x, y, count); +	} +	return 1; +} + +/* process - read prof.out data from file */ +int process(char *file) { +	int more; + +	if ((fp = fopen(file, "r")) != NULL) { +		struct file *p; +		while ((more = gather()) > 0) +			; +		fclose(fp); +		if (more < 0) +			return more; +		for (p = filelist; p; p = p->link) +			qsort(p->counts, p->count, sizeof *p->counts, +				(int (*)(const void *, const void *)) +				compare); +		 +		return 1; +	} +	return 0; +} diff --git a/src/tools/lcc/src/simp.c b/src/tools/lcc/src/simp.c new file mode 100644 index 0000000..ea26ab6 --- /dev/null +++ b/src/tools/lcc/src/simp.c @@ -0,0 +1,587 @@ +#include "c.h" +#include <float.h> + + +#define foldcnst(TYPE,VAR,OP) \ +	if (l->op == CNST+TYPE && r->op == CNST+TYPE) \ +		return cnsttree(ty, l->u.v.VAR OP r->u.v.VAR) +#define commute(L,R) \ +	if (generic(R->op) == CNST && generic(L->op) != CNST) \ +		do { Tree t = L; L = R; R = t; } while(0) +#define xfoldcnst(TYPE,VAR,OP,FUNC)\ +	if (l->op == CNST+TYPE && r->op == CNST+TYPE\ +	&& FUNC(l->u.v.VAR,r->u.v.VAR,\ +		ty->u.sym->u.limits.min.VAR,\ +		ty->u.sym->u.limits.max.VAR, needconst)) \ +		return cnsttree(ty, l->u.v.VAR OP r->u.v.VAR) +#define xcvtcnst(FTYPE,SRC,DST,VAR,EXPR) \ +	if (l->op == CNST+FTYPE) do {\ +		if (!explicitCast\ +		&&  ((SRC) < DST->u.sym->u.limits.min.VAR || (SRC) > DST->u.sym->u.limits.max.VAR))\ +			warning("overflow in converting constant expression from `%t' to `%t'\n", l->type, DST);\ +		if (needconst\ +		|| !((SRC) < DST->u.sym->u.limits.min.VAR || (SRC) > DST->u.sym->u.limits.max.VAR))\ +			return cnsttree(ty, (EXPR)); } while(0) +#define identity(X,Y,TYPE,VAR,VAL) \ +	if (X->op == CNST+TYPE && X->u.v.VAR == VAL) return Y +#define zerofield(OP,TYPE,VAR) \ +	if (l->op == FIELD \ +	&&  r->op == CNST+TYPE && r->u.v.VAR == 0)\ +		return eqtree(OP, bittree(BAND, l->kids[0],\ +			cnsttree(unsignedtype, \ +				(unsigned long)fieldmask(l->u.field)<<fieldright(l->u.field))), r) +#define cfoldcnst(TYPE,VAR,OP) \ +	if (l->op == CNST+TYPE && r->op == CNST+TYPE) \ +		return cnsttree(inttype, (long)(l->u.v.VAR OP r->u.v.VAR)) +#define foldaddp(L,R,RTYPE,VAR) \ +	if (L->op == CNST+P && R->op == CNST+RTYPE) { \ +		Tree e = tree(CNST+P, ty, NULL, NULL);\ +		e->u.v.p = (char *)L->u.v.p + R->u.v.VAR;\ +		return e; } +#define ufoldcnst(TYPE,EXP) if (l->op == CNST+TYPE) return EXP +#define sfoldcnst(OP) \ +	if (l->op == CNST+U && r->op == CNST+I \ +	&& r->u.v.i >= 0 && r->u.v.i < 8*l->type->size) \ +		return cnsttree(ty, (unsigned long)(l->u.v.u OP r->u.v.i)) +#define geu(L,R,V) \ +	if (R->op == CNST+U && R->u.v.u == 0) do { \ +		warning("result of unsigned comparison is constant\n"); \ +		return tree(RIGHT, inttype, root(L), cnsttree(inttype, (long)(V))); } while(0) +#define idempotent(OP) if (l->op == OP) return l->kids[0] + +int needconst; +int explicitCast; +static int addi(long x, long y, long min, long max, int needconst) { +	int cond = x == 0 || y == 0 +	|| (x < 0 && y < 0 && x >= min - y) +	|| (x < 0 && y > 0) +	|| (x > 0 && y < 0) +	|| (x > 0 && y > 0 && x <= max - y); +	if (!cond && needconst) { +		warning("overflow in constant expression\n"); +		cond = 1; +	} +	return cond; + + +} + +static int addd(double x, double y, double min, double max, int needconst) { +	int cond = x == 0 || y == 0 +	|| (x < 0 && y < 0 && x >= min - y) +	|| (x < 0 && y > 0) +	|| (x > 0 && y < 0) +	|| (x > 0 && y > 0 && x <= max - y); +	if (!cond && needconst) { +		warning("overflow in constant expression\n"); +		cond = 1; +	} +	return cond; + + +} + +static Tree addrtree(Tree e, long n, Type ty) { +	Symbol p = e->u.sym, q; + +	if (p->scope  == GLOBAL +	||  p->sclass == STATIC || p->sclass == EXTERN) +		NEW0(q, PERM); +	else +		NEW0(q, FUNC); +	q->name = stringd(genlabel(1)); +	q->sclass = p->sclass; +	q->scope = p->scope; +	assert(isptr(ty) || isarray(ty)); +	q->type = isptr(ty) ? ty->type : ty; +	q->temporary = p->temporary; +	q->generated = p->generated; +	q->addressed = p->addressed; +	q->computed = 1; +	q->defined = 1; +	q->ref = 1; +	if (p->scope  == GLOBAL +	||  p->sclass == STATIC || p->sclass == EXTERN) { +		if (p->sclass == AUTO) +			q->sclass = STATIC; +		(*IR->address)(q, p, n); +	} else { +		Code cp; +		addlocal(p); +		cp = code(Address); +		cp->u.addr.sym = q; +		cp->u.addr.base = p; +		cp->u.addr.offset = n; +	} +	e = tree(e->op, ty, NULL, NULL); +	e->u.sym = q; +	return e; +} + +/* div[id] - return 1 if min <= x/y <= max, 0 otherwise */ +static int divi(long x, long y, long min, long max, int needconst) { +	int cond = y != 0 && !(x == min && y == -1); +	if (!cond && needconst) { +		warning("overflow in constant expression\n"); +		cond = 1; +	} +	return cond; + + +} + +static int divd(double x, double y, double min, double max, int needconst) { +	int cond; + +	if (x < 0) x = -x; +	if (y < 0) y = -y; +	cond = y != 0 && !(y < 1 && x > max*y); +	if (!cond && needconst) { +		warning("overflow in constant expression\n"); +		cond = 1; +	} +	return cond; + +} + +/* mul[id] - return 1 if min <= x*y <= max, 0 otherwise */ +static int muli(long x, long y, long min, long max, int needconst) { +	int cond = (x > -1 && x <= 1) || (y > -1 && y <= 1) +	|| (x < 0 && y < 0 && -x <= max/-y) +	|| (x < 0 && y > 0 &&  x >= min/y) +	|| (x > 0 && y < 0 &&  y >= min/x) +	|| (x > 0 && y > 0 &&  x <= max/y); +	if (!cond && needconst) { +		warning("overflow in constant expression\n"); +		cond = 1; +	} +	return cond; + + +} + +static int muld(double x, double y, double min, double max, int needconst) { +	int cond = (x >= -1 && x <= 1) || (y >= -1 && y <= 1) +	|| (x < 0 && y < 0 && -x <= max/-y) +	|| (x < 0 && y > 0 &&  x >= min/y) +	|| (x > 0 && y < 0 &&  y >= min/x) +	|| (x > 0 && y > 0 &&  x <= max/y); +	if (!cond && needconst) { +		warning("overflow in constant expression\n"); +		cond = 1; +	} +	return cond; + + +} +/* sub[id] - return 1 if min <= x-y <= max, 0 otherwise */ +static int subi(long x, long y, long min, long max, int needconst) { +	return addi(x, -y, min, max, needconst); +} + +static int subd(double x, double y, double min, double max, int needconst) { +	return addd(x, -y, min, max, needconst); +} +Tree constexpr(int tok) { +	Tree p; + +	needconst++; +	p = expr1(tok); +	needconst--; +	return p; +} + +int intexpr(int tok, int n) { +	Tree p = constexpr(tok); + +	needconst++; +	if (p->op == CNST+I || p->op == CNST+U) +		n = cast(p, inttype)->u.v.i; +	else +		error("integer expression must be constant\n"); +	needconst--; +	return n; +} +Tree simplify(int op, Type ty, Tree l, Tree r) { +	int n; + +	if (optype(op) == 0) +		op = mkop(op, ty); +	switch (op) { +		case ADD+U: +			foldcnst(U,u,+); +			commute(r,l); +			identity(r,l,U,u,0); +			break; +		case ADD+I: +			xfoldcnst(I,i,+,addi); +			commute(r,l); +			identity(r,l,I,i,0); +			break; +		case CVI+I: +			xcvtcnst(I,l->u.v.i,ty,i,(long)extend(l->u.v.i,ty)); +			break; +		case CVU+I: +			if (l->op == CNST+U) { +				if (!explicitCast && l->u.v.u > ty->u.sym->u.limits.max.i) +					warning("overflow in converting constant expression from `%t' to `%t'\n", l->type, ty); +				if (needconst || !(l->u.v.u > ty->u.sym->u.limits.max.i)) +					return cnsttree(ty, (long)extend(l->u.v.u,ty)); +			} +			break; +		case CVP+U: +			xcvtcnst(P,(unsigned long)l->u.v.p,ty,u,(unsigned long)l->u.v.p); +			break; +		case CVU+P: +			xcvtcnst(U,(void*)l->u.v.u,ty,p,(void*)l->u.v.u); +			break; +		case CVP+P: +			xcvtcnst(P,l->u.v.p,ty,p,l->u.v.p); +			break; +		case CVI+U: +			xcvtcnst(I,l->u.v.i,ty,u,((unsigned long)l->u.v.i)&ones(8*ty->size)); +			break; +		case CVU+U: +			xcvtcnst(U,l->u.v.u,ty,u,l->u.v.u&ones(8*ty->size)); +			break; + +		case CVI+F: +			xcvtcnst(I,l->u.v.i,ty,d,(double)l->u.v.i); +		case CVU+F: +			xcvtcnst(U,l->u.v.u,ty,d,(double)l->u.v.u); +			break; +		case CVF+I: +			xcvtcnst(F,l->u.v.d,ty,i,(long)l->u.v.d); +			break; +		case CVF+F: { +			float d = 0.0f; +			if (l->op == CNST+F) { +				if (l->u.v.d < ty->u.sym->u.limits.min.d) +					d = ty->u.sym->u.limits.min.d; +				else if (l->u.v.d > ty->u.sym->u.limits.max.d) +					d = ty->u.sym->u.limits.max.d; +				else +					d = l->u.v.d; +			} +			xcvtcnst(F,l->u.v.d,ty,d,(double)d); +			break; +			} +		case BAND+U: +			foldcnst(U,u,&); +			commute(r,l); +			identity(r,l,U,u,ones(8*ty->size)); +			if (r->op == CNST+U && r->u.v.u == 0) +				return tree(RIGHT, ty, root(l), cnsttree(ty, 0UL)); +			break; +		case BAND+I: +			foldcnst(I,i,&); +			commute(r,l); +			identity(r,l,I,i,ones(8*ty->size)); +			if (r->op == CNST+I && r->u.v.u == 0) +				return tree(RIGHT, ty, root(l), cnsttree(ty, 0L)); +			break; + +		case MUL+U: +			commute(l,r); +			if (l->op == CNST+U && (n = ispow2(l->u.v.u)) != 0) +				return simplify(LSH, ty, r, cnsttree(inttype, (long)n)); +			foldcnst(U,u,*); +			identity(r,l,U,u,1); +			break; +		case NE+I: +			cfoldcnst(I,i,!=); +			commute(r,l); +			zerofield(NE,I,i); +			break; + +		case EQ+I: +			cfoldcnst(I,i,==); +			commute(r,l); +			zerofield(EQ,I,i); +			break; +		case ADD+P: +			foldaddp(l,r,I,i); +			foldaddp(l,r,U,u); +			foldaddp(r,l,I,i); +			foldaddp(r,l,U,u); +			commute(r,l); +			identity(r,retype(l,ty),I,i,0); +			identity(r,retype(l,ty),U,u,0); +			if (isaddrop(l->op) +			&& ((r->op == CNST+I && r->u.v.i <= longtype->u.sym->u.limits.max.i +			    && r->u.v.i >= longtype->u.sym->u.limits.min.i) +			|| (r->op == CNST+U && r->u.v.u <= longtype->u.sym->u.limits.max.i))) +				return addrtree(l, cast(r, longtype)->u.v.i, ty); +			if (l->op == ADD+P && isaddrop(l->kids[1]->op) +			&& ((r->op == CNST+I && r->u.v.i <= longtype->u.sym->u.limits.max.i +			    && r->u.v.i >= longtype->u.sym->u.limits.min.i) +			||  (r->op == CNST+U && r->u.v.u <= longtype->u.sym->u.limits.max.i))) +				return simplify(ADD+P, ty, l->kids[0], +					addrtree(l->kids[1], cast(r, longtype)->u.v.i, ty)); +			if ((l->op == ADD+I || l->op == SUB+I) +			&& l->kids[1]->op == CNST+I && isaddrop(r->op)) +				return simplify(ADD+P, ty, l->kids[0], +					simplify(generic(l->op)+P, ty, r, l->kids[1])); +			if (l->op == ADD+P && generic(l->kids[1]->op) == CNST +			&& generic(r->op) == CNST) +				return simplify(ADD+P, ty, l->kids[0], +					simplify(ADD, l->kids[1]->type, l->kids[1], r)); +			if (l->op == ADD+I && generic(l->kids[1]->op) == CNST +			&&  r->op == ADD+P && generic(r->kids[1]->op) == CNST) +				return simplify(ADD+P, ty, l->kids[0], +					simplify(ADD+P, ty, r->kids[0], +					simplify(ADD, r->kids[1]->type, l->kids[1], r->kids[1]))); +			if (l->op == RIGHT && l->kids[1]) +				return tree(RIGHT, ty, l->kids[0], +					simplify(ADD+P, ty, l->kids[1], r)); +			else if (l->op == RIGHT && l->kids[0]) +				return tree(RIGHT, ty, +					simplify(ADD+P, ty, l->kids[0], r), NULL); +			break; + +		case ADD+F: +			xfoldcnst(F,d,+,addd); +			commute(r,l); +			break; +		case AND+I: +			op = AND; +			ufoldcnst(I,l->u.v.i ? cond(r) : l);	/* 0&&r => 0, 1&&r => r */ +			break; +		case OR+I: +			op = OR; +			/* 0||r => r, 1||r => 1 */ +			ufoldcnst(I,l->u.v.i ? cnsttree(ty, 1L) : cond(r)); +			break; +		case BCOM+I: +			ufoldcnst(I,cnsttree(ty, (long)extend((~l->u.v.i)&ones(8*ty->size), ty))); +			idempotent(BCOM+U); +			break; +		case BCOM+U: +			ufoldcnst(U,cnsttree(ty, (unsigned long)((~l->u.v.u)&ones(8*ty->size)))); +			idempotent(BCOM+U); +			break; +		case BOR+U: +			foldcnst(U,u,|); +			commute(r,l); +			identity(r,l,U,u,0); +			break; +		case BOR+I: +			foldcnst(I,i,|); +			commute(r,l); +			identity(r,l,I,i,0); +			break; +		case BXOR+U: +			foldcnst(U,u,^); +			commute(r,l); +			identity(r,l,U,u,0); +			break; +		case BXOR+I: +			foldcnst(I,i,^); +			commute(r,l); +			identity(r,l,I,i,0); +			break; +		case DIV+F: +			xfoldcnst(F,d,/,divd); +			break; +		case DIV+I: +			identity(r,l,I,i,1); +			if ((r->op == CNST+I && r->u.v.i == 0) +			||  (l->op == CNST+I && l->u.v.i == ty->u.sym->u.limits.min.i +			&&  r->op == CNST+I && r->u.v.i == -1)) +				break; +			xfoldcnst(I,i,/,divi); +			break; +		case DIV+U:		 +			identity(r,l,U,u,1); +			if (r->op == CNST+U && r->u.v.u == 0) +				break; +			if (r->op == CNST+U && (n = ispow2(r->u.v.u)) != 0) +				return simplify(RSH, ty, l, cnsttree(inttype, (long)n)); +			foldcnst(U,u,/); +			break; +		case EQ+F: +			cfoldcnst(F,d,==); +			commute(r,l); +			break; +		case EQ+U: +			cfoldcnst(U,u,==); +			commute(r,l); +			zerofield(EQ,U,u); +			break; +		case GE+F: cfoldcnst(F,d,>=); break; +		case GE+I: cfoldcnst(I,i,>=); break; +		case GE+U: +			geu(l,r,1);	/* l >= 0 => (l,1) */ +			cfoldcnst(U,u,>=); +			if (l->op == CNST+U && l->u.v.u == 0)	/* 0 >= r => r == 0 */ +				return eqtree(EQ, r, l); +			break; +		case GT+F: cfoldcnst(F,d, >); break; +		case GT+I: cfoldcnst(I,i, >); break; +		case GT+U: +			geu(r,l,0);	/* 0 > r => (r,0) */ +			cfoldcnst(U,u, >); +			if (r->op == CNST+U && r->u.v.u == 0)	/* l > 0 => l != 0 */ +				return eqtree(NE, l, r); +			break; +		case LE+F: cfoldcnst(F,d,<=); break; +		case LE+I: cfoldcnst(I,i,<=); break; +		case LE+U: +			geu(r,l,1);	/* 0 <= r => (r,1) */ +			cfoldcnst(U,u,<=); +			if (r->op == CNST+U && r->u.v.u == 0)	/* l <= 0 => l == 0 */ +				return eqtree(EQ, l, r); +			break; +		case LSH+I: +			identity(r,l,I,i,0); +			if (l->op == CNST+I && r->op == CNST+I +			&& r->u.v.i >= 0 && r->u.v.i < 8*l->type->size +			&& muli(l->u.v.i, 1<<r->u.v.i, ty->u.sym->u.limits.min.i, ty->u.sym->u.limits.max.i, needconst)) +				return cnsttree(ty, (long)(l->u.v.i<<r->u.v.i)); +			if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) { +				warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i); +				break; +			} + +			break; +		case LSH+U: +			identity(r,l,I,i,0); +			sfoldcnst(<<); +			if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) { +				warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i); +				break; +			} + +			break; + +		case LT+F: cfoldcnst(F,d, <); break; +		case LT+I: cfoldcnst(I,i, <); break; +		case LT+U: +			geu(l,r,0);	/* l < 0 => (l,0) */ +			cfoldcnst(U,u, <); +			if (l->op == CNST+U && l->u.v.u == 0)	/* 0 < r => r != 0 */ +				return eqtree(NE, r, l); +			break; +		case MOD+I: +			if (r->op == CNST+I && r->u.v.i == 1)	/* l%1 => (l,0) */ +				return tree(RIGHT, ty, root(l), cnsttree(ty, 0L)); +			if ((r->op == CNST+I && r->u.v.i == 0) +			||  (l->op == CNST+I && l->u.v.i == ty->u.sym->u.limits.min.i +			&&  r->op == CNST+I && r->u.v.i == -1)) +				break; +			xfoldcnst(I,i,%,divi); +			break; +		case MOD+U:		 +			if (r->op == CNST+U && ispow2(r->u.v.u)) /* l%2^n => l&(2^n-1) */ +				return bittree(BAND, l, cnsttree(ty, r->u.v.u - 1)); +			if (r->op == CNST+U && r->u.v.u == 0) +				break; +			foldcnst(U,u,%); +			break; +		case MUL+F: +			xfoldcnst(F,d,*,muld); +			commute(l,r); +			break; +		case MUL+I: +			commute(l,r); +			xfoldcnst(I,i,*,muli); +			if (l->op == CNST+I && r->op == ADD+I && r->kids[1]->op == CNST+I) +				/* c1*(x + c2) => c1*x + c1*c2 */ +				return simplify(ADD, ty, simplify(MUL, ty, l, r->kids[0]), +					simplify(MUL, ty, l, r->kids[1])); +			if (l->op == CNST+I && r->op == SUB+I && r->kids[1]->op == CNST+I) +				/* c1*(x - c2) => c1*x - c1*c2 */ +				return simplify(SUB, ty, simplify(MUL, ty, l, r->kids[0]), +					simplify(MUL, ty, l, r->kids[1])); +			if (l->op == CNST+I && l->u.v.i > 0 && (n = ispow2(l->u.v.i)) != 0) +				/* 2^n * r => r<<n */ +				return simplify(LSH, ty, r, cnsttree(inttype, (long)n)); +			identity(r,l,I,i,1); +			break; +		case NE+F: +			cfoldcnst(F,d,!=); +			commute(r,l); +			break; +		case NE+U: +			cfoldcnst(U,u,!=); +			commute(r,l); +			zerofield(NE,U,u); +			break; +		case NEG+F: +			ufoldcnst(F,cnsttree(ty, -l->u.v.d)); +			idempotent(NEG+F); +			break; +		case NEG+I: +			if (l->op == CNST+I) { +				if (needconst && l->u.v.i == ty->u.sym->u.limits.min.i) +					warning("overflow in constant expression\n"); +				if (needconst || l->u.v.i != ty->u.sym->u.limits.min.i) +					return cnsttree(ty, -l->u.v.i); +			} +			idempotent(NEG+I); +			break; +		case NOT+I: +			op = NOT; +			ufoldcnst(I,cnsttree(ty, !l->u.v.i)); +			break; +		case RSH+I: +			identity(r,l,I,i,0); +			if (l->op == CNST+I && r->op == CNST+I +			&& r->u.v.i >= 0 && r->u.v.i < 8*l->type->size) { +				long n = l->u.v.i>>r->u.v.i; +				if (l->u.v.i < 0) +					n |= ~0UL<<(8*l->type->size - r->u.v.i); +				return cnsttree(ty, n); +			} +			if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) { +				warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i); +				break; +			} + +			break; +		case RSH+U: +			identity(r,l,I,i,0); +			sfoldcnst(>>); +			if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) { +				warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i); +				break; +			} + +			break; +		case SUB+F: +			xfoldcnst(F,d,-,subd); +			break; +		case SUB+I: +			xfoldcnst(I,i,-,subi); +			identity(r,l,I,i,0); +			break; +		case SUB+U: +			foldcnst(U,u,-); +			identity(r,l,U,u,0); +			break; +		case SUB+P: +			if (l->op == CNST+P && r->op == CNST+P) +				return cnsttree(ty, (long)((char *)l->u.v.p - (char *)r->u.v.p)); +			if (r->op == CNST+I || r->op == CNST+U) +				return simplify(ADD, ty, l, +					cnsttree(inttype, r->op == CNST+I ? -r->u.v.i : -(long)r->u.v.u)); +			if (isaddrop(l->op) && r->op == ADD+I && r->kids[1]->op == CNST+I) +				/* l - (x + c) => l-c - x */ +				return simplify(SUB, ty, +					simplify(SUB, ty, l, r->kids[1]), r->kids[0]); +			break; +		default:assert(0); +	} +	return tree(op, ty, l, r); +} +/* ispow2 - if u > 1 && u == 2^n, return n, otherwise return 0 */ +int ispow2(unsigned long u) { +	int n; + +	if (u > 1 && (u&(u-1)) == 0) +		for (n = 0; u; u >>= 1, n++) +			if (u&1) +				return n; +	return 0; +} + diff --git a/src/tools/lcc/src/stmt.c b/src/tools/lcc/src/stmt.c new file mode 100644 index 0000000..9c3bdbe --- /dev/null +++ b/src/tools/lcc/src/stmt.c @@ -0,0 +1,696 @@ +#include "c.h" + + +#define SWSIZE 512 + +#define den(i,j) ((j-buckets[i]+1.0)/(v[j]-v[buckets[i]]+1)) + +struct code codehead = { Start }; +Code codelist = &codehead; +float density = 0.5; +Table stmtlabs; + +static int foldcond(Tree e1, Tree e2); +static void caselabel(Swtch, long, int); +static void cmp(int, Symbol, long, int); +static Tree conditional(int); +static void dostmt(int, Swtch, int); +static int equal(Symbol, Symbol); +static void forstmt(int, Swtch, int); +static void ifstmt(int, int, Swtch, int); +static Symbol localaddr(Tree); +static void stmtlabel(void); +static void swstmt(int, int, int); +static void whilestmt(int, Swtch, int); +Code code(int kind) { +	Code cp; + +	if (!reachable(kind)) +		warning("unreachable code\n"); + +	NEW(cp, FUNC); +	cp->kind = kind; +	cp->prev = codelist; +	cp->next = NULL; +	codelist->next = cp; +	codelist = cp; +	return cp; +} +int reachable(int kind) { + +	if (kind > Start) { +		Code cp; +		for (cp = codelist; cp->kind < Label; ) +			cp = cp->prev; +		if (cp->kind == Jump || cp->kind == Switch) +			return 0; +	} +	return 1; +} +void addlocal(Symbol p) { +	if (!p->defined) { +		code(Local)->u.var = p; +		p->defined = 1; +		p->scope = level; +	} +} +void definept(Coordinate *p) { +	Code cp = code(Defpoint); + +	cp->u.point.src = p ? *p : src; +	cp->u.point.point = npoints; +	if (ncalled > 0) { +		int n = findcount(cp->u.point.src.file, +			cp->u.point.src.x, cp->u.point.src.y); +		if (n > 0) +			refinc = (float)n/ncalled; +	} +	if (glevel > 2)	locus(identifiers, &cp->u.point.src); +	if (events.points && reachable(Gen)) +		{ +			Tree e = NULL; +			apply(events.points, &cp->u.point.src, &e); +			if (e) +				listnodes(e, 0, 0); +		} +} +void statement(int loop, Swtch swp, int lev) { +	float ref = refinc; + +	if (Aflag >= 2 && lev == 15) +		warning("more than 15 levels of nested statements\n"); +	switch (t) { +	case IF:       ifstmt(genlabel(2), loop, swp, lev + 1); + break; +	case WHILE:    whilestmt(genlabel(3), swp, lev + 1); break; +	case DO:       dostmt(genlabel(3), swp, lev + 1); expect(';'); +					break; + +	case FOR:      forstmt(genlabel(4), swp, lev + 1); + break; +	case BREAK:    walk(NULL, 0, 0); +		       definept(NULL); +		       if (swp && swp->lab > loop) +		       	branch(swp->lab + 1); +		       else if (loop) +		       	branch(loop + 2); +		       else +		       	error("illegal break statement\n"); +		       t = gettok(); expect(';'); +					   break; + +	case CONTINUE: walk(NULL, 0, 0); +		       definept(NULL); +		       if (loop) +		       	branch(loop + 1); +		       else +		       	error("illegal continue statement\n"); +		       t = gettok(); expect(';'); +					      break; + +	case SWITCH:   swstmt(loop, genlabel(2), lev + 1); + break; +	case CASE:     { +		       	int lab = genlabel(1); +		       	if (swp == NULL) +		       		error("illegal case label\n"); +		       	definelab(lab); +		       	while (t == CASE) { +		       		static char stop[] = { IF, ID, 0 }; +		       		Tree p; +		       		t = gettok(); +		       		p = constexpr(0); +		       		if (generic(p->op) == CNST && isint(p->type)) { +		       			if (swp) { +		       				needconst++; +		       				p = cast(p, swp->sym->type); +		       				if (p->type->op == UNSIGNED) +		       					p->u.v.i = extend(p->u.v.u, p->type); +		       				needconst--; +		       				caselabel(swp, p->u.v.i, lab); +		       			} +		       		} else +		       			error("case label must be a constant integer expression\n"); + +		       		test(':', stop); +		       	} +		       	statement(loop, swp, lev); +		       } break; +	case DEFAULT:  if (swp == NULL) +		       	error("illegal default label\n"); +		       else if (swp->deflab) +		       	error("extra default label\n"); +		       else { +		       	swp->deflab = findlabel(swp->lab); +		       	definelab(swp->deflab->u.l.label); +		       } +		       t = gettok(); +		       expect(':'); +		       statement(loop, swp, lev); break; +	case RETURN:   { +		       	Type rty = freturn(cfunc->type); +		       	t = gettok(); +		       	definept(NULL); +		       	if (t != ';') +		       		if (rty == voidtype) { +		       			error("extraneous return value\n"); +		       			expr(0); +		       			retcode(NULL); +		       		} else +		       			retcode(expr(0)); +		       	else { +		       		if (rty != voidtype) +		       			warning("missing return value\n"); +		       		retcode(NULL); +		       	} +		       	branch(cfunc->u.f.label); +		       } expect(';'); +					    break; + +	case '{':      compound(loop, swp, lev + 1); break; +	case ';':      definept(NULL); t = gettok(); break; +	case GOTO:     walk(NULL, 0, 0); +		       definept(NULL); +		       t = gettok(); +		       if (t == ID) { +		       	Symbol p = lookup(token, stmtlabs); +		       	if (p == NULL) { +				p = install(token, &stmtlabs, 0, FUNC); +				p->scope = LABELS; +				p->u.l.label = genlabel(1); +				p->src = src; +			} +		       	use(p, src); +		       	branch(p->u.l.label); +		       	t = gettok(); +		       } else +		       	error("missing label in goto\n"); expect(';'); +					  break; + +	case ID:       if (getchr() == ':') { +		       	stmtlabel(); +		       	statement(loop, swp, lev); +		       	break; +		       } +	default:       definept(NULL); +		       if (kind[t] != ID) { +		       	error("unrecognized statement\n"); +		       	t = gettok(); +		       } else { +		       	Tree e = expr0(0); +		       	listnodes(e, 0, 0); +		       	if (nodecount == 0 || nodecount > 200) +		       		walk(NULL, 0, 0); +		       	else if (glevel) walk(NULL, 0, 0); +		       	deallocate(STMT); +		       } expect(';'); +						break; + +	} +	if (kind[t] != IF && kind[t] != ID +	&& t != '}' && t != EOI) { +		static char stop[] = { IF, ID, '}', 0 }; +		error("illegal statement termination\n"); +		skipto(0, stop); +	} +	refinc = ref; +} + +static void ifstmt(int lab, int loop, Swtch swp, int lev) { +	t = gettok(); +	expect('('); +	definept(NULL); +	walk(conditional(')'), 0, lab); +	refinc /= 2.0; +	statement(loop, swp, lev); +	if (t == ELSE) { +		branch(lab + 1); +		t = gettok(); +		definelab(lab); +		statement(loop, swp, lev); +		if (findlabel(lab + 1)->ref) +			definelab(lab + 1); +	} else +		definelab(lab); +} +static Tree conditional(int tok) { +	Tree p = expr(tok); + +	if (Aflag > 1 && isfunc(p->type)) +		warning("%s used in a conditional expression\n", +			funcname(p)); +	return cond(p); +} +static void stmtlabel(void) { +	Symbol p = lookup(token, stmtlabs); + +	if (p == NULL) { +		p = install(token, &stmtlabs, 0, FUNC); +		p->scope = LABELS; +		p->u.l.label = genlabel(1); +		p->src = src; +	} +	if (p->defined) +		error("redefinition of label `%s' previously defined at %w\n", p->name, &p->src); + +	p->defined = 1; +	definelab(p->u.l.label); +	t = gettok(); +	expect(':'); +} +static void forstmt(int lab, Swtch swp, int lev) { +	int once = 0; +	Tree e1 = NULL, e2 = NULL, e3 = NULL; +	Coordinate pt2, pt3; +	 +	t = gettok(); +	expect('('); +	definept(NULL); +	if (kind[t] == ID) +		e1 = texpr(expr0, ';', FUNC); +	else +		expect(';'); +	walk(e1, 0, 0); +	pt2 = src; +	refinc *= 10.0; +	if (kind[t] == ID) +		e2 = texpr(conditional, ';', FUNC); +	else +		expect(';'); +	pt3 = src; +	if (kind[t] == ID) +		e3 = texpr(expr0, ')', FUNC); +	else { +		static char stop[] = { IF, ID, '}', 0 }; +		test(')', stop); +	} +	if (e2) { +		once = foldcond(e1, e2); +		if (!once) +			branch(lab + 3); +	} +	definelab(lab); +	statement(lab, swp, lev); +	definelab(lab + 1); +	definept(&pt3); +	if (e3) +		walk(e3, 0, 0); +	if (e2) { +		if (!once) +			definelab(lab + 3); +		definept(&pt2); +		walk(e2, lab, 0); +	} else { +		definept(&pt2); +		branch(lab); +	} +	if (findlabel(lab + 2)->ref) +		definelab(lab + 2); +} +static void swstmt(int loop, int lab, int lev) { +	Tree e; +	struct swtch sw; +	Code head, tail; + +	t = gettok(); +	expect('('); +	definept(NULL); +	e = expr(')'); +	if (!isint(e->type)) { +		error("illegal type `%t' in switch expression\n", +			e->type); +		e = retype(e, inttype); +	} +	e = cast(e, promote(e->type)); +	if (generic(e->op) == INDIR && isaddrop(e->kids[0]->op) +	&& e->kids[0]->u.sym->type == e->type +	&& !isvolatile(e->kids[0]->u.sym->type)) { +		sw.sym = e->kids[0]->u.sym; +		walk(NULL, 0, 0); +	} else { +		sw.sym = genident(REGISTER, e->type, level); +		addlocal(sw.sym); +		walk(asgn(sw.sym, e), 0, 0); +	} +	head = code(Switch); +	sw.lab = lab; +	sw.deflab = NULL; +	sw.ncases = 0; +	sw.size = SWSIZE; +	sw.values = newarray(SWSIZE, sizeof *sw.values, FUNC); +	sw.labels = newarray(SWSIZE, sizeof *sw.labels, FUNC); +	refinc /= 10.0; +	statement(loop, &sw, lev); +	if (sw.deflab == NULL) { +		sw.deflab = findlabel(lab); +		definelab(lab); +		if (sw.ncases == 0) +			warning("switch statement with no cases\n"); +	} +	if (findlabel(lab + 1)->ref) +		definelab(lab + 1); +	tail = codelist; +	codelist = head->prev; +	codelist->next = head->prev = NULL; +	if (sw.ncases > 0) +		swgen(&sw); +	branch(lab); +	head->next->prev = codelist; +	codelist->next = head->next; +	codelist = tail; +} +static void caselabel(Swtch swp, long val, int lab) { +	int k; + +	if (swp->ncases >= swp->size) +		{ +		long   *vals = swp->values; +		Symbol *labs = swp->labels; +		swp->size *= 2; +		swp->values = newarray(swp->size, sizeof *swp->values, FUNC); +		swp->labels = newarray(swp->size, sizeof *swp->labels, FUNC); +		for (k = 0; k < swp->ncases; k++) { +			swp->values[k] = vals[k]; +			swp->labels[k] = labs[k]; +		} +		} +	k = swp->ncases; +	for ( ; k > 0 && swp->values[k-1] >= val; k--) { +		swp->values[k] = swp->values[k-1]; +		swp->labels[k] = swp->labels[k-1]; +	} +	if (k < swp->ncases && swp->values[k] == val) +		error("duplicate case label `%d'\n", val); +	swp->values[k] = val; +	swp->labels[k] = findlabel(lab); +	++swp->ncases; +	if (Aflag >= 2 && swp->ncases == 258) +		warning("more than 257 cases in a switch\n"); +} +void swgen(Swtch swp) { +	int *buckets, k, n; +	long *v = swp->values; + +	buckets = newarray(swp->ncases + 1, +		sizeof *buckets, FUNC); +	for (n = k = 0; k < swp->ncases; k++, n++) { +		buckets[n] = k; +		while (n > 0 && den(n-1, k) >= density) +			n--; +	} +	buckets[n] = swp->ncases; +	swcode(swp, buckets, 0, n - 1); +} +void swcode(Swtch swp, int b[], int lb, int ub) { +	int hilab, lolab, l, u, k = (lb + ub)/2; +	long *v = swp->values; + +	if (k > lb && k < ub) { +		lolab = genlabel(1); +		hilab = genlabel(1); +	} else if (k > lb) { +		lolab = genlabel(1); +		hilab = swp->deflab->u.l.label; +	} else if (k < ub) { +		lolab = swp->deflab->u.l.label; +		hilab = genlabel(1); +	} else +		lolab = hilab = swp->deflab->u.l.label; +	l = b[k]; +	u = b[k+1] - 1; +	if (u - l + 1 <= 3) +		{ +			int i; +			for (i = l; i <= u; i++) +				cmp(EQ, swp->sym, v[i], swp->labels[i]->u.l.label); +			if (k > lb && k < ub) +				cmp(GT, swp->sym, v[u], hilab); +			else if (k > lb) +				cmp(GT, swp->sym, v[u], hilab); +			else if (k < ub) +				cmp(LT, swp->sym, v[l], lolab); +			else +				assert(lolab == hilab), +				branch(lolab); +			walk(NULL, 0, 0); +		} +	else { +		Tree e; +		Type ty = signedint(swp->sym->type); +		Symbol table = genident(STATIC, +			array(voidptype, u - l + 1, 0), GLOBAL); +		(*IR->defsymbol)(table); +		if (!isunsigned(swp->sym->type) || v[l] != 0) +			cmp(LT, swp->sym, v[l], lolab); +		cmp(GT, swp->sym, v[u], hilab); +		e = (*optree['-'])(SUB, cast(idtree(swp->sym), ty), cnsttree(ty, v[l])); +		if (e->type->size < unsignedptr->size) +			e = cast(e, unsignedlong); +		walk(tree(JUMP, voidtype, +			rvalue((*optree['+'])(ADD, pointer(idtree(table)), e)), NULL), +			0, 0); +		code(Switch); +		codelist->u.swtch.table = table; +		codelist->u.swtch.sym = swp->sym; +		codelist->u.swtch.deflab = swp->deflab; +		codelist->u.swtch.size = u - l + 1; +		codelist->u.swtch.values = &v[l]; +		codelist->u.swtch.labels = &swp->labels[l]; +		if (v[u] - v[l] + 1 >= 10000) +			warning("switch generates a huge table\n"); +	} +	if (k > lb) { +		assert(lolab != swp->deflab->u.l.label); +		definelab(lolab); +		swcode(swp, b, lb, k - 1); +	} +	if (k < ub) { +		assert(hilab != swp->deflab->u.l.label); +		definelab(hilab); +		swcode(swp, b, k + 1, ub); +	} +} +static void cmp(int op, Symbol p, long n, int lab) { +	Type ty = signedint(p->type); + +	listnodes(eqtree(op, +			cast(idtree(p), ty), +			cnsttree(ty, n)), +		lab, 0); +} +void retcode(Tree p) { +	Type ty; + +	if (p == NULL) { +		if (events.returns) +			apply(events.returns, cfunc, NULL); +		return; +	} +	p = pointer(p); +	ty = assign(freturn(cfunc->type), p); +	if (ty == NULL) { +		error("illegal return type; found `%t' expected `%t'\n", +			p->type, freturn(cfunc->type)); +		return; +	} +	p = cast(p, ty); +	if (retv) +		{ +			if (iscallb(p)) +				p = tree(RIGHT, p->type, +					tree(CALL+B, p->type, +						p->kids[0]->kids[0], idtree(retv)), +					rvalue(idtree(retv))); +			else +				p = asgntree(ASGN, rvalue(idtree(retv)), p); +			walk(p, 0, 0); +			if (events.returns) +				apply(events.returns, cfunc, rvalue(idtree(retv))); +			return; +		} +	if (events.returns) +		{ +			Symbol t1 = genident(AUTO, p->type, level); +			addlocal(t1); +			walk(asgn(t1, p), 0, 0); +			apply(events.returns, cfunc, idtree(t1)); +			p = idtree(t1); +		} +	if (!isfloat(p->type)) +		p = cast(p, promote(p->type)); +	if (isptr(p->type)) +		{ +			Symbol q = localaddr(p); +			if (q && (q->computed || q->generated)) +				warning("pointer to a %s is an illegal return value\n", +					q->scope == PARAM ? "parameter" : "local"); +			else if (q) +				warning("pointer to %s `%s' is an illegal return value\n", +					q->scope == PARAM ? "parameter" : "local", q->name); +		} +	walk(tree(mkop(RET,p->type), p->type, p, NULL), 0, 0); +} +void definelab(int lab) { +	Code cp; +	Symbol p = findlabel(lab); + +	assert(lab); +	walk(NULL, 0, 0); +	code(Label)->u.forest = newnode(LABEL+V, NULL, NULL, p); +	for (cp = codelist->prev; cp->kind <= Label; ) +		cp = cp->prev; +	while (   cp->kind == Jump +	       && cp->u.forest->kids[0] +	       && specific(cp->u.forest->kids[0]->op) == ADDRG+P +	       && cp->u.forest->kids[0]->syms[0] == p) { +		assert(cp->u.forest->kids[0]->syms[0]->u.l.label == lab); +		p->ref--; +		assert(cp->next); +		assert(cp->prev); +		cp->prev->next = cp->next; +		cp->next->prev = cp->prev; +		cp = cp->prev; +		while (cp->kind <= Label) +			cp = cp->prev; +	} +} +Node jump(int lab) { +	Symbol p = findlabel(lab); + +	p->ref++; +	return newnode(JUMP+V, newnode(ADDRG+ttob(voidptype), NULL, NULL, p), +		NULL, NULL); +} +void branch(int lab) { +	Code cp; +	Symbol p = findlabel(lab); + +	assert(lab); +	walk(NULL, 0, 0); +	code(Label)->u.forest = jump(lab); +	for (cp = codelist->prev; cp->kind < Label; ) +		cp = cp->prev; +	while (   cp->kind == Label +	       && cp->u.forest->op == LABEL+V +	       && !equal(cp->u.forest->syms[0], p)) { +		equatelab(cp->u.forest->syms[0], p); +		assert(cp->next); +		assert(cp->prev); +		cp->prev->next = cp->next; +		cp->next->prev = cp->prev; +		cp = cp->prev; +		while (cp->kind < Label) +			cp = cp->prev; +	} +	if (cp->kind == Jump || cp->kind == Switch) { +		p->ref--; +		codelist->prev->next = NULL; +		codelist = codelist->prev; +	} else { +		codelist->kind = Jump; +		if (cp->kind == Label +		&&  cp->u.forest->op == LABEL+V +		&&  equal(cp->u.forest->syms[0], p)) +			warning("source code specifies an infinite loop"); +	} +} +void equatelab(Symbol old, Symbol new) { +	assert(old->u.l.equatedto == NULL); +	old->u.l.equatedto = new; +	new->ref++; +} +static int equal(Symbol lprime, Symbol dst) { +	assert(dst && lprime); +	for ( ; dst; dst = dst->u.l.equatedto) +		if (lprime == dst) +			return 1; +	return 0; +} +/* dostmt - do statement while ( expression ) */ +static void dostmt(int lab, Swtch swp, int lev) { +	refinc *= 10.0; +	t = gettok(); +	definelab(lab); +	statement(lab, swp, lev); +	definelab(lab + 1); +	expect(WHILE); +	expect('('); +	definept(NULL); +	walk(conditional(')'), lab, 0); +	if (findlabel(lab + 2)->ref) +		definelab(lab + 2); +} + +/* foldcond - check if initial test in for(e1;e2;e3) S is necessary */ +static int foldcond(Tree e1, Tree e2) { +	int op = generic(e2->op); +	Symbol v; + +	if (e1 == 0 || e2 == 0) +		return 0; +	if (generic(e1->op) == ASGN && isaddrop(e1->kids[0]->op) +	&& generic(e1->kids[1]->op) == CNST) { +		v = e1->kids[0]->u.sym; +		e1 = e1->kids[1]; +	} else +		return 0; +	if ((op==LE || op==LT || op==EQ || op==NE || op==GT || op==GE) +	&& generic(e2->kids[0]->op) == INDIR +	&& e2->kids[0]->kids[0]->u.sym == v +	&& e2->kids[1]->op == e1->op) { +		e1 = simplify(op, e2->type, e1, e2->kids[1]); +		if (e1->op == CNST+I) +			return e1->u.v.i; +	} +	return 0; +} + +/* localaddr - returns q if p yields the address of local/parameter q; otherwise returns 0 */ +static Symbol localaddr(Tree p) { +	if (p == NULL) +		return NULL; +	switch (generic(p->op)) { +	case INDIR: case CALL: case ARG: +		return NULL; +	case ADDRL: case ADDRF: +		return p->u.sym; +	case RIGHT: case ASGN: +		if (p->kids[1]) +			return localaddr(p->kids[1]); +		return localaddr(p->kids[0]); +	case COND: { +		Symbol q; +		assert(p->kids[1] && p->kids[1]->op == RIGHT); +		if ((q = localaddr(p->kids[1]->kids[0])) != NULL) +			return q; +		return localaddr(p->kids[1]->kids[1]); +		} +	default: { +		Symbol q; +		if (p->kids[0] && (q = localaddr(p->kids[0])) != NULL) +			return q; +		return localaddr(p->kids[1]); +		} +	} +} + +/* whilestmt - while ( expression ) statement */ +static void whilestmt(int lab, Swtch swp, int lev) { +	Coordinate pt; +	Tree e; + +	refinc *= 10.0; +	t = gettok(); +	expect('('); +	walk(NULL, 0, 0); +	pt = src; +	e = texpr(conditional, ')', FUNC); +	branch(lab + 1); +	definelab(lab); +	statement(lab, swp, lev); +	definelab(lab + 1); +	definept(&pt); +	walk(e, lab, 0); +	if (findlabel(lab + 2)->ref) +		definelab(lab + 2); +} diff --git a/src/tools/lcc/src/string.c b/src/tools/lcc/src/string.c new file mode 100644 index 0000000..73cfc85 --- /dev/null +++ b/src/tools/lcc/src/string.c @@ -0,0 +1,122 @@ +#include "c.h" + + +static struct string { +	char *str; +	int len; +	struct string *link; +} *buckets[1024]; +static int scatter[] = {	/* map characters to random values */ +	2078917053, 143302914, 1027100827, 1953210302, 755253631, +	2002600785, 1405390230, 45248011, 1099951567, 433832350, +	2018585307, 438263339, 813528929, 1703199216, 618906479, +	573714703, 766270699, 275680090, 1510320440, 1583583926, +	1723401032, 1965443329, 1098183682, 1636505764, 980071615, +	1011597961, 643279273, 1315461275, 157584038, 1069844923, +	471560540, 89017443, 1213147837, 1498661368, 2042227746, +	1968401469, 1353778505, 1300134328, 2013649480, 306246424, +	1733966678, 1884751139, 744509763, 400011959, 1440466707, +	1363416242, 973726663, 59253759, 1639096332, 336563455, +	1642837685, 1215013716, 154523136, 593537720, 704035832, +	1134594751, 1605135681, 1347315106, 302572379, 1762719719, +	269676381, 774132919, 1851737163, 1482824219, 125310639, +	1746481261, 1303742040, 1479089144, 899131941, 1169907872, +	1785335569, 485614972, 907175364, 382361684, 885626931, +	200158423, 1745777927, 1859353594, 259412182, 1237390611, +	48433401, 1902249868, 304920680, 202956538, 348303940, +	1008956512, 1337551289, 1953439621, 208787970, 1640123668, +	1568675693, 478464352, 266772940, 1272929208, 1961288571, +	392083579, 871926821, 1117546963, 1871172724, 1771058762, +	139971187, 1509024645, 109190086, 1047146551, 1891386329, +	994817018, 1247304975, 1489680608, 706686964, 1506717157, +	579587572, 755120366, 1261483377, 884508252, 958076904, +	1609787317, 1893464764, 148144545, 1415743291, 2102252735, +	1788268214, 836935336, 433233439, 2055041154, 2109864544, +	247038362, 299641085, 834307717, 1364585325, 23330161, +	457882831, 1504556512, 1532354806, 567072918, 404219416, +	1276257488, 1561889936, 1651524391, 618454448, 121093252, +	1010757900, 1198042020, 876213618, 124757630, 2082550272, +	1834290522, 1734544947, 1828531389, 1982435068, 1002804590, +	1783300476, 1623219634, 1839739926, 69050267, 1530777140, +	1802120822, 316088629, 1830418225, 488944891, 1680673954, +	1853748387, 946827723, 1037746818, 1238619545, 1513900641, +	1441966234, 367393385, 928306929, 946006977, 985847834, +	1049400181, 1956764878, 36406206, 1925613800, 2081522508, +	2118956479, 1612420674, 1668583807, 1800004220, 1447372094, +	523904750, 1435821048, 923108080, 216161028, 1504871315, +	306401572, 2018281851, 1820959944, 2136819798, 359743094, +	1354150250, 1843084537, 1306570817, 244413420, 934220434, +	672987810, 1686379655, 1301613820, 1601294739, 484902984, +	139978006, 503211273, 294184214, 176384212, 281341425, +	228223074, 147857043, 1893762099, 1896806882, 1947861263, +	1193650546, 273227984, 1236198663, 2116758626, 489389012, +	593586330, 275676551, 360187215, 267062626, 265012701, +	719930310, 1621212876, 2108097238, 2026501127, 1865626297, +	894834024, 552005290, 1404522304, 48964196, 5816381, +	1889425288, 188942202, 509027654, 36125855, 365326415, +	790369079, 264348929, 513183458, 536647531, 13672163, +	313561074, 1730298077, 286900147, 1549759737, 1699573055, +	776289160, 2143346068, 1975249606, 1136476375, 262925046, +	92778659, 1856406685, 1884137923, 53392249, 1735424165, +	1602280572 +}; +char *string(const char *str) { +	const char *s; + +	for (s = str; *s; s++) +		; +	return stringn(str, s - str); +} +char *stringd(long n) { +	char str[25], *s = str + sizeof (str); +	unsigned long m; + +	if (n == LONG_MIN) +		m = (unsigned long)LONG_MAX + 1; +	else if (n < 0) +		m = -n; +	else +		m = n; +	do +		*--s = m%10 + '0'; +	while ((m /= 10) != 0); +	if (n < 0) +		*--s = '-'; +	return stringn(s, str + sizeof (str) - s); +} +char *stringn(const char *str, int len) { +	int i; +	unsigned int h; +	const char *end; +	struct string *p; + +	assert(str); +	for (h = 0, i = len, end = str; i > 0; i--) +		h = (h<<1) + scatter[*(unsigned char *)end++]; +	h &= NELEMS(buckets)-1; +	for (p = buckets[h]; p; p = p->link) +		if (len == p->len) { +			const char *s1 = str; +			char *s2 = p->str; +			do { +				if (s1 == end) +					return p->str; +			} while (*s1++ == *s2++); +		} +	{ +		static char *next, *strlimit; +		if (len + 1 >= strlimit - next) { +			int n = len + 4*1024; +			next = allocate(n, PERM); +			strlimit = next + n; +		} +		NEW(p, PERM); +		p->len = len; +		for (p->str = next; str < end; ) +			*next++ = *str++; +		*next++ = 0; +		p->link = buckets[h]; +		buckets[h] = p; +		return p->str; +	} +} diff --git a/src/tools/lcc/src/sym.c b/src/tools/lcc/src/sym.c new file mode 100644 index 0000000..2a1cfeb --- /dev/null +++ b/src/tools/lcc/src/sym.c @@ -0,0 +1,314 @@ +#include "c.h" +#include <stdio.h> + + +#define equalp(x) v.x == p->sym.u.c.v.x + +struct table { +	int level; +	Table previous; +	struct entry { +		struct symbol sym; +		struct entry *link; +	} *buckets[256]; +	Symbol all; +}; +#define HASHSIZE NELEMS(((Table)0)->buckets) +static struct table +	cns = { CONSTANTS }, +	ext = { GLOBAL }, +	ids = { GLOBAL }, +	tys = { GLOBAL }; +Table constants   = &cns; +Table externals   = &ext; +Table identifiers = &ids; +Table globals     = &ids; +Table types       = &tys; +Table labels; +int level = GLOBAL; +static int tempid; +List loci, symbols; + +Table table(Table tp, int level) { +	Table new; + +	NEW0(new, FUNC); +	new->previous = tp; +	new->level = level; +	if (tp) +		new->all = tp->all; +	return new; +} +void foreach(Table tp, int lev, void (*apply)(Symbol, void *), void *cl) { +	assert(tp); +	while (tp && tp->level > lev) +		tp = tp->previous; +	if (tp && tp->level == lev) { +		Symbol p; +		Coordinate sav; +		sav = src; +		for (p = tp->all; p && p->scope == lev; p = p->up) { +			src = p->src; +			(*apply)(p, cl); +		} +		src = sav; +	} +} +void enterscope(void) { +	if (++level == LOCAL) +		tempid = 0; +} +void exitscope(void) { +	rmtypes(level); +	if (types->level == level) +		types = types->previous; +	if (identifiers->level == level) { +		if (Aflag >= 2) { +			int n = 0; +			Symbol p; +			for (p = identifiers->all; p && p->scope == level; p = p->up) +				if (++n > 127) { +					warning("more than 127 identifiers declared in a block\n"); +					break; +				} +		} +		identifiers = identifiers->previous; +	} +	assert(level >= GLOBAL); +	--level; +} +Symbol install(const char *name, Table *tpp, int level, int arena) { +	Table tp = *tpp; +	struct entry *p; +	unsigned h = (unsigned long)name&(HASHSIZE-1); + +	assert(level == 0 || level >= tp->level); +	if (level > 0 && tp->level < level) +		tp = *tpp = table(tp, level); +	NEW0(p, arena); +	p->sym.name = (char *)name; +	p->sym.scope = level; +	p->sym.up = tp->all; +	tp->all = &p->sym; +	p->link = tp->buckets[h]; +	tp->buckets[h] = p; +	return &p->sym; +} +Symbol relocate(const char *name, Table src, Table dst) { +	struct entry *p, **q; +	Symbol *r; +	unsigned h = (unsigned long)name&(HASHSIZE-1); + +	for (q = &src->buckets[h]; *q; q = &(*q)->link) +		if (name == (*q)->sym.name) +			break; +	assert(*q); +	/* +	 Remove the entry from src's hash chain +	  and from its list of all symbols. +	*/ +	p = *q; +	*q = (*q)->link; +	for (r = &src->all; *r && *r != &p->sym; r = &(*r)->up) +		; +	assert(*r == &p->sym); +	*r = p->sym.up; +	/* +	 Insert the entry into dst's hash chain +	  and into its list of all symbols. +	  Return the symbol-table entry. +	*/ +	p->link = dst->buckets[h]; +	dst->buckets[h] = p; +	p->sym.up = dst->all; +	dst->all = &p->sym; +	return &p->sym; +} +Symbol lookup(const char *name, Table tp) { +	struct entry *p; +	unsigned h = (unsigned long)name&(HASHSIZE-1); + +	assert(tp); +	do +		for (p = tp->buckets[h]; p; p = p->link) +			if (name == p->sym.name) +				return &p->sym; +	while ((tp = tp->previous) != NULL); +	return NULL; +} +int genlabel(int n) { +	static int label = 1; + +	label += n; +	return label - n; +} +Symbol findlabel(int lab) { +	struct entry *p; +	unsigned h = lab&(HASHSIZE-1); + +	for (p = labels->buckets[h]; p; p = p->link) +		if (lab == p->sym.u.l.label) +			return &p->sym; +	NEW0(p, FUNC); +	p->sym.name = stringd(lab); +	p->sym.scope = LABELS; +	p->sym.up = labels->all; +	labels->all = &p->sym; +	p->link = labels->buckets[h]; +	labels->buckets[h] = p; +	p->sym.generated = 1; +	p->sym.u.l.label = lab; +	(*IR->defsymbol)(&p->sym); +	return &p->sym; +} +Symbol constant(Type ty, Value v) { +	struct entry *p; +	unsigned h = v.u&(HASHSIZE-1); + +	ty = unqual(ty); +	for (p = constants->buckets[h]; p; p = p->link) +		if (eqtype(ty, p->sym.type, 1)) +			switch (ty->op) { +			case INT:      if (equalp(i)) return &p->sym; break; +			case UNSIGNED: if (equalp(u)) return &p->sym; break; +			case FLOAT:    if (equalp(d)) return &p->sym; break; +			case FUNCTION: if (equalp(g)) return &p->sym; break; +			case ARRAY: +			case POINTER:  if (equalp(p)) return &p->sym; break; +			default: assert(0); +			} +	NEW0(p, PERM); +	p->sym.name = vtoa(ty, v); +	p->sym.scope = CONSTANTS; +	p->sym.type = ty; +	p->sym.sclass = STATIC; +	p->sym.u.c.v = v; +	p->link = constants->buckets[h]; +	p->sym.up = constants->all; +	constants->all = &p->sym; +	constants->buckets[h] = p; +	if (ty->u.sym && !ty->u.sym->addressed) +		(*IR->defsymbol)(&p->sym); +	p->sym.defined = 1; +	return &p->sym; +} +Symbol intconst(int n) { +	Value v; + +	v.i = n; +	return constant(inttype, v); +} +Symbol genident(int scls, Type ty, int lev) { +	Symbol p; + +	NEW0(p, lev >= LOCAL ? FUNC : PERM); +	p->name = stringd(genlabel(1)); +	p->scope = lev; +	p->sclass = scls; +	p->type = ty; +	p->generated = 1; +	if (lev == GLOBAL) +		(*IR->defsymbol)(p); +	return p; +} + +Symbol temporary(int scls, Type ty) { +	Symbol p; + +	NEW0(p, FUNC); +	p->name = stringd(++tempid); +	p->scope = level < LOCAL ? LOCAL : level; +	p->sclass = scls; +	p->type = ty; +	p->temporary = 1; +	p->generated = 1; +	return p; +} +Symbol newtemp(int sclass, int tc, int size) { +	Symbol p = temporary(sclass, btot(tc, size)); + +	(*IR->local)(p); +	p->defined = 1; +	return p; +} + +Symbol allsymbols(Table tp) { +	return tp->all; +} + +void locus(Table tp, Coordinate *cp) { +	loci    = append(cp, loci); +	symbols = append(allsymbols(tp), symbols); +} + +void use(Symbol p, Coordinate src) { +	Coordinate *cp; + +	NEW(cp, PERM); +	*cp = src; +	p->uses = append(cp, p->uses); +} +/* findtype - find type ty in identifiers */ +Symbol findtype(Type ty) { +	Table tp = identifiers; +	int i; +	struct entry *p; + +	assert(tp); +	do +		for (i = 0; i < HASHSIZE; i++) +			for (p = tp->buckets[i]; p; p = p->link) +				if (p->sym.type == ty && p->sym.sclass == TYPEDEF) +					return &p->sym; +	while ((tp = tp->previous) != NULL); +	return NULL; +} + +/* mkstr - make a string constant */ +Symbol mkstr(char *str) { +	Value v; +	Symbol p; + +	v.p = str; +	p = constant(array(chartype, strlen(v.p) + 1, 0), v); +	if (p->u.c.loc == NULL) +		p->u.c.loc = genident(STATIC, p->type, GLOBAL); +	return p; +} + +/* mksymbol - make a symbol for name, install in &globals if sclass==EXTERN */ +Symbol mksymbol(int sclass, const char *name, Type ty) { +	Symbol p; + +	if (sclass == EXTERN) +		p = install(string(name), &globals, GLOBAL, PERM); +	else { +		NEW0(p, PERM); +		p->name = string(name); +		p->scope = GLOBAL; +	} +	p->sclass = sclass; +	p->type = ty; +	(*IR->defsymbol)(p); +	p->defined = 1; +	return p; +} + +/* vtoa - return string for the constant v of type ty */ +char *vtoa(Type ty, Value v) { + +	ty = unqual(ty); +	switch (ty->op) { +	case INT:      return stringd(v.i); +	case UNSIGNED: return stringf((v.u&~0x7FFF) ? "0x%X" : "%U", v.u); +	case FLOAT:    return stringf("%g", (double)v.d); +	case ARRAY: +		if (ty->type == chartype || ty->type == signedchar +		||  ty->type == unsignedchar) +			return v.p; +		return stringf("%p", v.p); +	case POINTER:  return stringf("%p", v.p); +	case FUNCTION: return stringf("%p", v.g); +	} +	assert(0); return NULL; +} diff --git a/src/tools/lcc/src/symbolic.c b/src/tools/lcc/src/symbolic.c new file mode 100644 index 0000000..affa67a --- /dev/null +++ b/src/tools/lcc/src/symbolic.c @@ -0,0 +1,494 @@ +#include <time.h> +#include <ctype.h> +#include "c.h" + +#define I(f) s_##f + +static Node *tail; +static int off, maxoff, uid = 0, verbose = 0, html = 0; + +static const char *yyBEGIN(const char *tag) { +	if (html) +		print("<%s>", tag); +	return tag; +} + +static void yyEND(const char *tag) { +	if (html) +		print("</%s>", tag); +	if (isupper(*tag)) +		print("\n"); +} + +#define BEGIN(tag) do { const char *yytag=yyBEGIN(#tag); +#define END yyEND(yytag); } while (0) +#define ITEM BEGIN(li) +#define START BEGIN(LI) +#define ANCHOR(attr,code) do { const char *yytag="a"; if (html) { printf("<a " #attr "=\""); code; print("\">"); } +#define NEWLINE print(html ? "<br>\n" : "\n") + +static void emitCoord(Coordinate src) { +	if (src.file && *src.file) { +		ANCHOR(href,print("%s", src.file)); print("%s", src.file); END; +		print(":"); +	} +	print("%d.%d", src.y, src.x); +} + +static void emitString(int len, const char *s) { +	for ( ; len-- > 0; s++) +		if (*s == '&' && html) +			print("&"); +		else if (*s == '<' && html) +			print("<"); +		else if (*s == '>' && html) +			print("<"); +		else if (*s == '"' || *s == '\\') +			print("\\%c", *s); +		else if (*s >= ' ' && *s < 0177) +			print("%c", *s); +		else +			print("\\%d%d%d", (*s>>6)&3, (*s>>3)&7, *s&7); +} + +static void emitSymRef(Symbol p) { +	(*IR->defsymbol)(p); +	ANCHOR(href,print("#%s", p->x.name)); BEGIN(code); print("%s", p->name); END; END; +} + +static void emitSymbol(Symbol p) { +	(*IR->defsymbol)(p); +	ANCHOR(name,print("%s", p->x.name)); BEGIN(code); print("%s", p->name); END; END; +	BEGIN(ul); +#define xx(field,code) ITEM; if (!html) print(" "); print(#field "="); code; END +	if (verbose && (src.y || src.x)) +		xx(src,emitCoord(p->src)); +	xx(type,print("%t", p->type)); +	xx(sclass,print("%k", p->sclass)); +	switch (p->scope) { +	case CONSTANTS: xx(scope,print("CONSTANTS")); break; +	case LABELS:    xx(scope,print("LABELS"));    break; +	case GLOBAL:    xx(scope,print("GLOBAL"));    break; +	case PARAM:     xx(scope,print("PARAM"));     break; +	case LOCAL:     xx(scope,print("LOCAL"));     break; +	default: +		if (p->scope > LOCAL) +			xx(scope,print("LOCAL+%d", p->scope-LOCAL)); +		else +			xx(scope,print("%d", p->scope)); +	} +	if (p->scope >= PARAM && p->sclass != STATIC) +		xx(offset,print("%d", p->x.offset)); +	xx(ref,print("%f", p->ref)); +	if (p->temporary && p->u.t.cse) +		xx(u.t.cse,print("%p", p->u.t.cse)); +	END; +#undef xx +} + +/* address - initialize q for addressing expression p+n */ +static void I(address)(Symbol q, Symbol p, long n) { +	q->name = stringf("%s%s%D", p->name, n > 0 ? "+" : "", n); +	(*IR->defsymbol)(q); +	START; print("address "); emitSymbol(q); END; +} + +/* blockbeg - start a block */ +static void I(blockbeg)(Env *e) { +	e->offset = off; +	START; print("blockbeg off=%d", off); END; +} + +/* blockend - start a block */ +static void I(blockend)(Env *e) { +	if (off > maxoff) +		maxoff = off; +	START; print("blockend off=%d", off); END; +	off = e->offset; +} + +/* defaddress - initialize an address */ +static void I(defaddress)(Symbol p){ +	START; print("defaddress "); emitSymRef(p); END; +} + +/* defconst - define a constant */ +static void I(defconst)(int suffix, int size, Value v) { +	START; +	print("defconst "); +	switch (suffix) { +	case I: +		print("int.%d ", size); +		BEGIN(code); +		if (size > sizeof (int)) +			print("%D", v.i); +		else +			print("%d", (int)v.i); +		END; +		break; +	case U: +		print("unsigned.%d ", size); +		BEGIN(code); +		if (size > sizeof (unsigned)) +			print("%U", v.u); +		else +			print("%u", (unsigned)v.u); +		END; +		break; +	case P: print("void*.%d ", size); BEGIN(code); print("%p", v.p); END; break; +	case F: print("float.%d ", size); BEGIN(code); print("%g", (double)v.d); END; break; +	default: assert(0); +	} +	END; +} + +/* defstring - emit a string constant */ +static void I(defstring)(int len, char *s) { +	START; print("defstring "); +	BEGIN(code); print("\""); emitString(len, s); print("\""); END; +	END; +} + +/* defsymbol - define a symbol: initialize p->x */ +static void I(defsymbol)(Symbol p) { +	if (p->x.name == NULL) +		p->x.name = stringd(++uid); +} + +/* emit - emit the dags on list p */ +static void I(emit)(Node p){ +	ITEM; +	if (!html) +		print(" "); +	for (; p; p = p->x.next) { +		if (p->op == LABEL+V) { +			assert(p->syms[0]); +			ANCHOR(name,print("%s", p->syms[0]->x.name)); +			BEGIN(code); print("%s", p->syms[0]->name); END; +			END; +			print(":"); +		} else { +			int i; +			if (p->x.listed) { +				BEGIN(strong); print("%d", p->x.inst); END; print("'"); +				print(" %s", opname(p->op)); +			} else +				print("%d. %s", p->x.inst, opname(p->op)); +			if (p->count > 1) +				print(" count=%d", p->count); +			for (i = 0; i < NELEMS(p->kids) && p->kids[i]; i++) +				print(" #%d", p->kids[i]->x.inst); +			if (generic(p->op) == CALL && p->syms[0] && p->syms[0]->type) +				print(" {%t}", p->syms[0]->type); +			else +				for (i = 0; i < NELEMS(p->syms) && p->syms[i]; i++) { +					print(" "); +					if (p->syms[i]->scope == CONSTANTS) +						print(p->syms[i]->name); +					else +						emitSymRef(p->syms[i]); +				} +		} +		NEWLINE; +	} +	END; +} + +/* export - announce p as exported */ +static void I(export)(Symbol p) { +	START; print("export "); emitSymRef(p); END; +} + +/* function - generate code for a function */ +static void I(function)(Symbol f, Symbol caller[], Symbol callee[], int ncalls) { +	int i; + +	(*IR->defsymbol)(f); +	off = 0; +	for (i = 0; caller[i] && callee[i]; i++) { +		off = roundup(off, caller[i]->type->align); +		caller[i]->x.offset = callee[i]->x.offset = off; +		off += caller[i]->type->size; +	} +	if (!html) { +		print("function "); +		emitSymbol(f); +		print(" ncalls=%d\n", ncalls); +		for (i = 0; caller[i]; i++) +			START; print("caller "); emitSymbol(caller[i]); END; +		for (i = 0; callee[i]; i++) +			START; print("callee "); emitSymbol(callee[i]); END; +	} else { +		START; +		print("function"); +		BEGIN(UL); +#define xx(field,code) ITEM; print(#field "="); code; END +		xx(f,emitSymbol(f)); +		xx(ncalls,print("%d", ncalls)); +		if (caller[0]) { +			ITEM; print("caller"); BEGIN(OL); +			for (i = 0; caller[i]; i++) +				ITEM; emitSymbol(caller[i]); END; +			END; END; +			ITEM; print("callee"); BEGIN(OL); +			for (i = 0; callee[i]; i++) +				ITEM; emitSymbol(callee[i]); END; +			END; END; +		} else { +			xx(caller,BEGIN(em); print("empty"); END); +			xx(callee,BEGIN(em); print("empty"); END); +		} +		END; +		END; +	} +	maxoff = off = 0; +	gencode(caller, callee); +	if (html) +		START; print("emitcode"); BEGIN(ul); emitcode(); END; END; +	else +		emitcode(); +	START; print("maxoff=%d", maxoff); END; +#undef xx +} + +/* visit - generate code for *p */ +static int visit(Node p, int n) { +	if (p && p->x.inst == 0) { +		p->x.inst = ++n; +		n = visit(p->kids[0], n); +		n = visit(p->kids[1], n); +		*tail = p; +		tail = &p->x.next; +	} +	return n; +} + +/* gen0 - generate code for the dags on list p */ +static Node I(gen)(Node p) { +	int n; +	Node nodelist; + +	tail = &nodelist; +	for (n = 0; p; p = p->link) { +		switch (generic(p->op)) {	/* check for valid forest */ +		case CALL: +			assert(IR->wants_dag || p->count == 0); +			break; +		case ARG: +		case ASGN: case JUMP: case LABEL: case RET: +		case EQ: case GE: case GT: case LE: case LT: case NE: +			assert(p->count == 0); +			break; +		case INDIR: +			assert(IR->wants_dag && p->count > 0); +			break; +		default: +			assert(0); +		} +		check(p); +		p->x.listed = 1; +		n = visit(p, n); +	} +	*tail = 0; +	return nodelist; +} + +/* global - announce a global */ +static void I(global)(Symbol p) { +	START; print("global "); emitSymbol(p); END; +} + +/* import - import a symbol */ +static void I(import)(Symbol p) { +	START; print("import "); emitSymRef(p); END; +} + +/* local - local variable */ +static void I(local)(Symbol p) { +	if (p->temporary) +		p->name = stringf("t%s", p->name); +	(*IR->defsymbol)(p); +	off = roundup(off, p->type->align); +	p->x.offset = off; +	off += p->type->size; +	START; print(p->temporary ? "temporary " : "local "); emitSymbol(p); END; +} + +/* progbeg - beginning of program */ +static void I(progbeg)(int argc, char *argv[]) { +	int i; + +	for (i = 1; i < argc; i++) +		if (strcmp(argv[i], "-v") == 0) +			verbose++; +		else if (strcmp(argv[i], "-html") == 0) +			html++; +	if (html) { +		print("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n"); +		print("<html>"); +		BEGIN(head); +		if (firstfile && *firstfile) +			BEGIN(title); emitString(strlen(firstfile), firstfile);	END; +		print("<link rev=made href=\"mailto:drh@microsoft.com\">\n"); +		END; +		print("<body>\n"); +		if (firstfile && *firstfile) +			BEGIN(h1); emitString(strlen(firstfile), firstfile); END; +		BEGIN(P); BEGIN(em); +		print("Links lead from uses of identifiers and labels to their definitions."); +		END; END; +		print("<ul>\n"); +		START; +		print("progbeg"); +		BEGIN(ol); +		for (i = 1; i < argc; i++) { +			ITEM; +			BEGIN(code); print("\""); emitString(strlen(argv[i]), argv[i]); print("\""); END; +			END; +		} +		END; +		END; +	} +} + +/* progend - end of program */ +static void I(progend)(void) { +	START; print("progend"); END; +	if (html) { +		time_t t; +		print("</ul>\n"); +		time(&t); +		print("<hr><address>%s</address>\n", ctime(&t)); +		print("</body></html>\n"); +	} +} + +/* segment - switch to segment s */ +static void I(segment)(int s) { +	START; print("segment %s", &"text\0bss\0.data\0lit\0.sym\0."[5*s-5]); END; +} + +/* space - initialize n bytes of space */ +static void I(space)(int n) { +	START; print("space %d", n); END; +} + +static void I(stabblock)(int brace, int lev, Symbol *p) {} + +/* stabend - finalize stab output */ +static void I(stabend)(Coordinate *cp, Symbol p, Coordinate **cpp, Symbol *sp, Symbol *stab) { +	int i; + +	if (p) +		emitSymRef(p); +	print("\n"); +	if (cpp && sp) +		for (i = 0; cpp[i] && sp[i]; i++) { +			print("%w.%d: ", cpp[i], cpp[i]->x); +			emitSymRef(sp[i]); +			print("\n"); +		} +} + +static void I(stabfend)(Symbol p, int lineno) {} +static void I(stabinit)(char *file, int argc, char *argv[]) {} + +/* stabline - emit line number information for source coordinate *cp */ +static void I(stabline)(Coordinate *cp) { +	if (cp->file) +		print("%s:", cp->file); +	print("%d.%d:\n", cp->y, cp->x); +} + +static void I(stabsym)(Symbol p) {} +static void I(stabtype)(Symbol p) {} + +Interface symbolicIR = { +	{1, 1, 0},	/* char */ +	{2, 2, 0},	/* short */ +	{4, 4, 0},	/* int */ +	{4, 4, 0},	/* long */ +	{4, 4, 0},	/* long long */ +	{4, 4, 1},	/* float */ +	{8, 8, 1},	/* double */ +	{8, 8, 1},	/* long double */ +	{4, 4, 0},	/* T* */ +	{0, 4, 0},	/* struct */ +	0,		/* little_endian */ +	0,		/* mulops_calls */ +	0,		/* wants_callb */ +	1,		/* wants_argb */ +	1,		/* left_to_right */ +	1,		/* wants_dag */ +	0,		/* unsigned_char */ +	I(address), +	I(blockbeg), +	I(blockend), +	I(defaddress), +	I(defconst), +	I(defstring), +	I(defsymbol), +	I(emit), +	I(export), +	I(function), +	I(gen), +	I(global), +	I(import), +	I(local), +	I(progbeg), +	I(progend), +	I(segment), +	I(space), +	I(stabblock), +	I(stabend), +	I(stabfend), +	I(stabinit), +	I(stabline), +	I(stabsym), +	I(stabtype) +}; + +Interface symbolic64IR = { +	{1, 1, 0},	/* char */ +	{2, 2, 0},	/* short */ +	{4, 4, 0},	/* int */ +	{8, 8, 0},	/* long */ +	{8, 8, 0},	/* long long */ +	{4, 4, 1},	/* float */ +	{8, 8, 1},	/* double */ +	{8, 8, 1},	/* long double */ +	{8, 8, 0},	/* T* */ +	{0, 1, 0},	/* struct */ +	1,		/* little_endian */ +	0,		/* mulops_calls */ +	0,		/* wants_callb */ +	1,		/* wants_argb */ +	1,		/* left_to_right */ +	1,		/* wants_dag */ +	0,		/* unsigned_char */ +	I(address), +	I(blockbeg), +	I(blockend), +	I(defaddress), +	I(defconst), +	I(defstring), +	I(defsymbol), +	I(emit), +	I(export), +	I(function), +	I(gen), +	I(global), +	I(import), +	I(local), +	I(progbeg), +	I(progend), +	I(segment), +	I(space), +	I(stabblock), +	I(stabend), +	I(stabfend), +	I(stabinit), +	I(stabline), +	I(stabsym), +	I(stabtype) +}; diff --git a/src/tools/lcc/src/token.h b/src/tools/lcc/src/token.h new file mode 100644 index 0000000..d309f9b --- /dev/null +++ b/src/tools/lcc/src/token.h @@ -0,0 +1,133 @@ +/* +xx(symbol,	value,	prec,	op,	optree,	kind,	string) +*/ +yy(0,         0, 0,  0,    0,      0,      0) +xx(FLOAT,     1, 0,  0,    0,      CHAR,   "float") +xx(DOUBLE,    2, 0,  0,    0,      CHAR,   "double") +xx(CHAR,      3, 0,  0,    0,      CHAR,   "char") +xx(SHORT,     4, 0,  0,    0,      CHAR,   "short") +xx(INT,       5, 0,  0,    0,      CHAR,   "int") +xx(UNSIGNED,  6, 0,  0,    0,      CHAR,   "unsigned") +xx(POINTER,   7, 0,  0,    0,      0,      "pointer") +xx(VOID,      8, 0,  0,    0,      CHAR,   "void") +xx(STRUCT,    9, 0,  0,    0,      CHAR,   "struct") +xx(UNION,    10, 0,  0,    0,      CHAR,   "union") +xx(FUNCTION, 11, 0,  0,    0,      0,      "function") +xx(ARRAY,    12, 0,  0,    0,      0,      "array") +xx(ENUM,     13, 0,  0,    0,      CHAR,   "enum") +xx(LONG,     14, 0,  0,    0,      CHAR,   "long") +xx(CONST,    15, 0,  0,    0,      CHAR,   "const") +xx(VOLATILE, 16, 0,  0,    0,      CHAR,   "volatile") +yy(0,        17,     0,      0,    0,      0,      0) +yy(0,        18,     0,      0,    0,      0,      0) +yy(0,        19,     0,      0,    0,      0,      0) +yy(0,        20,     0,      0,    0,      0,      0) +yy(0,        21,     0,      0,    0,      0,      0) +yy(0,        22,     0,      0,    0,      0,      0) +yy(0,        23,     0,      0,    0,      0,      0) +yy(0,        24,     0,      0,    0,      0,      0) +yy(0,        25,     0,      0,    0,      0,      0) +yy(0,        26,     0,      0,    0,      0,      0) +yy(0,        27,     0,      0,    0,      0,      0) +yy(0,        28,     0,      0,    0,      0,      "long long") +yy(0,        29,     0,      0,    0,      0,      0) +yy(0,        30,     0,      0,    0,      0,      0) +yy(0,        31,     0,      0,    0,      0,      "const volatile") +xx(ID,       32,     0,      0,    0,      ID,     "identifier") +yy(0,        33,     0,      0,    0,      ID,     "!") +xx(FCON,     34,     0,      0,    0,      ID,     "floating constant") +xx(ICON,     35,     0,      0,    0,      ID,     "integer constant") +xx(SCON,     36,     0,      0,    0,      ID,     "string constant") +yy(0,        37,     13,     MOD,  bittree,'%',    "%") +yy(0,        38,     8,      BAND, bittree,ID,     "&") +xx(INCR,     39,     0,      ADD,  addtree,ID,     "++") +yy(0,        40,     0,      0,    0,      ID,     "(") +yy(0,        41,     0,      0,    0,      ')',    ")") +yy(0,        42, 13, MUL,  multree,ID,     "*") +yy(0,        43, 12, ADD,  addtree,ID,     "+") +yy(0,        44, 1,  0,    0,      ',',    ",") +yy(0,        45, 12, SUB,  subtree,ID,     "-") +yy(0,        46, 0,  0,    0,      '.',    ".") +yy(0,        47, 13, DIV,  multree,'/',    "/") +xx(DECR,     48, 0,  SUB,  subtree,ID,     "--") +xx(DEREF,    49, 0,  0,    0,      DEREF,  "->") +xx(ANDAND,   50, 5,  AND,  andtree,ANDAND, "&&") +xx(OROR,     51, 4,  OR,   andtree,OROR,   "||") +xx(LEQ,      52, 10, LE,   cmptree,LEQ,    "<=") +xx(EQL,         53,     9,      EQ,     eqtree, EQL,    "==") +xx(NEQ,         54,     9,      NE,     eqtree, NEQ,    "!=") +xx(GEQ,         55,     10,     GE,     cmptree,GEQ,    ">=") +xx(RSHIFT,      56,     11,     RSH,    shtree, RSHIFT, ">>") +xx(LSHIFT,      57,     11,     LSH,    shtree, LSHIFT, "<<") +yy(0,           58,     0,      0,      0,      ':',    ":") +yy(0,           59,     0,      0,      0,      IF,     ";") +yy(0,           60,     10,     LT,     cmptree,'<',    "<") +yy(0,           61,     2,      ASGN,   asgntree,'=',   "=") +yy(0,           62,     10,     GT,     cmptree,'>',    ">") +yy(0,           63,     0,      0,      0,      '?',    "?") +xx(ELLIPSIS,    64,     0,      0,      0,      ELLIPSIS,"...") +xx(SIZEOF,      65,     0,      0,      0,      ID,     "sizeof") +yy(0,           66,     0,      0,      0,      0,      0) +xx(AUTO,        67,     0,      0,      0,      STATIC, "auto") +xx(BREAK,       68,     0,      0,      0,      IF,     "break") +xx(CASE,        69,     0,      0,      0,      IF,     "case") +xx(CONTINUE,    70,     0,      0,      0,      IF,     "continue") +xx(DEFAULT,     71,     0,      0,      0,      IF,     "default") +xx(DO,          72,     0,      0,      0,      IF,     "do") +xx(ELSE,        73,     0,      0,      0,      IF,     "else") +xx(EXTERN,      74,     0,      0,      0,      STATIC, "extern") +xx(FOR,         75,     0,      0,      0,      IF,     "for") +xx(GOTO,        76,     0,      0,      0,      IF,     "goto") +xx(IF,          77,     0,      0,      0,      IF,     "if") +xx(REGISTER,    78,     0,      0,      0,      STATIC, "register") +xx(RETURN,      79,     0,      0,      0,      IF,     "return") +xx(SIGNED,      80,     0,      0,      0,      CHAR,   "signed") +xx(STATIC,      81,     0,      0,      0,      STATIC, "static") +xx(SWITCH,      82,     0,      0,      0,      IF,     "switch") +xx(TYPEDEF,     83,     0,      0,      0,      STATIC, "typedef") +xx(WHILE,       84,     0,      0,      0,      IF,     "while") +xx(TYPECODE,    85,     0,      0,      0,      ID,     "__typecode") +xx(FIRSTARG,    86,     0,      0,      0,      ID,     "__firstarg") +yy(0,           87,     0,      0,      0,      0,      0) +yy(0,           88,     0,      0,      0,      0,      0) +yy(0,           89,     0,      0,      0,      0,      0) +yy(0,           90,     0,      0,      0,      0,      0) +yy(0,           91,     0,      0,      0,      '[',    "[") +yy(0,           92,     0,      0,      0,      0,      0) +yy(0,           93,     0,      0,      0,      ']',    "]") +yy(0,           94,     7,      BXOR,   bittree,'^',    "^") +yy(0,           95,     0,      0,      0,      0,      0) +yy(0,           96,     0,      0,      0,      0,      0) +yy(0,           97,     0,      0,      0,      0,      0) +yy(0,           98,     0,      0,      0,      0,      0) +yy(0,           99,     0,      0,      0,      0,      0) +yy(0,           100,    0,      0,      0,      0,      0) +yy(0,           101,    0,      0,      0,      0,      0) +yy(0,           102,    0,      0,      0,      0,      0) +yy(0,           103,    0,      0,      0,      0,      0) +yy(0,           104,    0,      0,      0,      0,      0) +yy(0,           105,    0,      0,      0,      0,      0) +yy(0,           106,    0,      0,      0,      0,      0) +yy(0,           107,    0,      0,      0,      0,      0) +yy(0,           108,    0,      0,      0,      0,      0) +yy(0,           109,    0,      0,      0,      0,      0) +yy(0,           110,    0,      0,      0,      0,      0) +yy(0,           111,    0,      0,      0,      0,      0) +yy(0,           112,    0,      0,      0,      0,      0) +yy(0,           113,    0,      0,      0,      0,      0) +yy(0,           114,    0,      0,      0,      0,      0) +yy(0,           115,    0,      0,      0,      0,      0) +yy(0,           116,    0,      0,      0,      0,      0) +yy(0,           117,    0,      0,      0,      0,      0) +yy(0,           118,    0,      0,      0,      0,      0) +yy(0,           119,    0,      0,      0,      0,      0) +yy(0,           120,    0,      0,      0,      0,      0) +yy(0,           121,    0,      0,      0,      0,      0) +yy(0,           122,    0,      0,      0,      0,      0) +yy(0,           123,    0,      0,      0,      IF,     "{") +yy(0,           124,    6,      BOR,    bittree,'|',    "|") +yy(0,           125,    0,      0,      0,      '}',    "}") +yy(0,           126,    0,      BCOM,   0,      ID,     "~") +xx(EOI,         127,    0,      0,      0,      EOI,    "end of input") +#undef xx +#undef yy diff --git a/src/tools/lcc/src/trace.c b/src/tools/lcc/src/trace.c new file mode 100644 index 0000000..3b9ba78 --- /dev/null +++ b/src/tools/lcc/src/trace.c @@ -0,0 +1,181 @@ +#include "c.h" + + +static char *fmt, *fp, *fmtend;	/* format string, current & limit pointer */ +static Tree args;		/* printf arguments */ +static Symbol frameno;		/* local holding frame number */ + +/* appendstr - append str to the evolving format string, expanding it if necessary */ +static void appendstr(char *str) { +	do +		if (fp == fmtend) { +			if (fp) { +				char *s = allocate(2*(fmtend - fmt), FUNC); +				strncpy(s, fmt, fmtend - fmt); +				fp = s + (fmtend - fmt); +				fmtend = s + 2*(fmtend - fmt); +				fmt = s; +			} else { +				fp = fmt = allocate(80, FUNC); +				fmtend = fmt + 80; +			} +		} +	while ((*fp++ = *str++) != 0); +	fp--; +} + +/* tracevalue - append format and argument to print the value of e */ +static void tracevalue(Tree e, int lev) { +	Type ty = unqual(e->type); + +	switch (ty->op) { +	case INT: +		if (ty == chartype || ty == signedchar) +			appendstr("'\\x%02x'"); +		else if (ty == longtype) +			appendstr("0x%ld"); +		else +			appendstr("0x%d"); +		break; +	case UNSIGNED: +		if (ty == chartype || ty == unsignedchar) +			appendstr("'\\x%02x'"); +		else if (ty == unsignedlong) +			appendstr("0x%lx"); +		else +			appendstr("0x%x"); +		break; +	case FLOAT: +		if (ty == longdouble) +			appendstr("%Lg"); +		else +			appendstr("%g"); +		break; +	case POINTER: +		if (unqual(ty->type) == chartype +		||  unqual(ty->type) == signedchar +		||  unqual(ty->type) == unsignedchar) { +			static Symbol null; +			if (null == NULL) +				null = mkstr("(null)"); +			tracevalue(cast(e, unsignedtype), lev + 1); +			appendstr(" \"%.30s\""); +			e = condtree(e, e, pointer(idtree(null->u.c.loc))); +		} else { +			appendstr("("); appendstr(typestring(ty, "")); appendstr(")0x%x"); +		} +		break; +	case STRUCT: { +		Field q; +		appendstr("("); appendstr(typestring(ty, "")); appendstr("){"); +		for (q = ty->u.sym->u.s.flist; q; q = q->link) { +			appendstr(q->name); appendstr("="); +			tracevalue(field(addrof(e), q->name), lev + 1); +			if (q->link) +				appendstr(","); +		} +		appendstr("}"); +		return; +		} +	case UNION: +		appendstr("("); appendstr(typestring(ty, "")); appendstr("){...}"); +		return; +	case ARRAY: +		if (lev && ty->type->size > 0) { +			int i; +			e = pointer(e); +			appendstr("{"); +			for (i = 0; i < ty->size/ty->type->size; i++) { +				Tree p = (*optree['+'])(ADD, e, consttree(i, inttype)); +				if (isptr(p->type) && isarray(p->type->type)) +					p = retype(p, p->type->type); +				else +					p = rvalue(p); +				if (i) +					appendstr(","); +				tracevalue(p, lev + 1); +			} +			appendstr("}"); +		} else +			appendstr(typestring(ty, "")); +		return; +	default: +		assert(0); +	} +	e = cast(e, promote(ty)); +	args = tree(mkop(ARG,e->type), e->type, e, args); +} + +/* tracefinis - complete & generate the trace call to print */ +static void tracefinis(Symbol printer) { +	Tree *ap; +	Symbol p; + +	*fp = 0; +	p = mkstr(string(fmt)); +	for (ap = &args; *ap; ap = &(*ap)->kids[1]) +		; +	*ap = tree(ARG+P, charptype, pointer(idtree(p->u.c.loc)), 0); +	walk(calltree(pointer(idtree(printer)), freturn(printer->type), args, NULL), 0, 0); +	args = 0; +	fp = fmtend = 0; +} + +/* tracecall - generate code to trace entry to f */ +static void tracecall(Symbol printer, Symbol f) { +	int i; +	Symbol counter = genident(STATIC, inttype, GLOBAL); + +	defglobal(counter, BSS); +	(*IR->space)(counter->type->size); +	frameno = genident(AUTO, inttype, level); +	addlocal(frameno); +	appendstr(f->name); appendstr("#"); +	tracevalue(asgn(frameno, incr(INCR, idtree(counter), consttree(1, inttype))), 0); +	appendstr("("); +	for (i = 0; f->u.f.callee[i]; i++) { +		if (i) +			appendstr(","); +		appendstr(f->u.f.callee[i]->name); appendstr("="); +		tracevalue(idtree(f->u.f.callee[i]), 0); +	} +	if (variadic(f->type)) +		appendstr(",..."); +	appendstr(") called\n"); +	tracefinis(printer); +} + +/* tracereturn - generate code to trace return e */ +static void tracereturn(Symbol printer, Symbol f, Tree e) { +	appendstr(f->name); appendstr("#"); +	tracevalue(idtree(frameno), 0); +	appendstr(" returned"); +	if (freturn(f->type) != voidtype && e) { +		appendstr(" "); +		tracevalue(e, 0); +	} +	appendstr("\n"); +	tracefinis(printer); +} + +/* trace_init - initialize for tracing */ +void trace_init(int argc, char *argv[]) { +	int i; +	static int inited; + +	if (inited) +		return; +	inited = 1; +	type_init(argc, argv); +	if (IR) +		for (i = 1; i < argc; i++) +			if (strncmp(argv[i], "-t", 2) == 0 &&  strchr(argv[i], '=') == NULL) { +				Symbol printer = mksymbol(EXTERN, +					argv[i][2] ? &argv[i][2] : "printf", +				ftype(inttype, ptr(qual(CONST, chartype)))); +				printer->defined = 0; +				attach((Apply)tracecall,   printer, &events.entry); +				attach((Apply)tracereturn, printer, &events.returns); +				break; +			} +} diff --git a/src/tools/lcc/src/tree.c b/src/tools/lcc/src/tree.c new file mode 100644 index 0000000..d2b6a91 --- /dev/null +++ b/src/tools/lcc/src/tree.c @@ -0,0 +1,223 @@ +#include "c.h" + + +int where = STMT; +static int warn; +static int nid = 1;		/* identifies trees & nodes in debugging output */ +static struct nodeid { +	int printed; +	Tree node; +} ids[500];			/* if ids[i].node == p, then p's id is i */ + +static void printtree1(Tree, int, int); + +Tree tree(int op, Type type, Tree left, Tree right) { +	Tree p; + +	NEW0(p, where); +	p->op = op; +	p->type = type; +	p->kids[0] = left; +	p->kids[1] = right; +	return p; +} + +Tree texpr(Tree (*f)(int), int tok, int a) { +	int save = where; +	Tree p; + +	where = a; +	p = (*f)(tok); +	where = save; +	return p; +} +static Tree root1(Tree p) { +	if (p == NULL) +		return p; +	if (p->type == voidtype) +		warn++; +	switch (generic(p->op)) { +	case COND: { +		Tree q = p->kids[1]; +		assert(q && q->op == RIGHT); +		if (p->u.sym && q->kids[0] && generic(q->kids[0]->op) == ASGN) +			q->kids[0] = root1(q->kids[0]->kids[1]); +		else +			q->kids[0] = root1(q->kids[0]); +		if (p->u.sym && q->kids[1] && generic(q->kids[1]->op) == ASGN) +			q->kids[1] = root1(q->kids[1]->kids[1]); +		else +			q->kids[1] = root1(q->kids[1]); +		p->u.sym = 0; +		if (q->kids[0] == 0 && q->kids[1] == 0) +			p = root1(p->kids[0]); +		} +		break; +	case AND: case OR: +		if ((p->kids[1] = root1(p->kids[1])) == 0) +			p = root1(p->kids[0]); +		break; +	case NOT: +		if (warn++ == 0) +			warning("expression with no effect elided\n"); +		return root1(p->kids[0]); +	case RIGHT: +		if (p->kids[1] == 0) +			return root1(p->kids[0]); +		if (p->kids[0] && p->kids[0]->op == CALL+B +		&&  p->kids[1] && p->kids[1]->op == INDIR+B) +			/* avoid premature release of the CALL+B temporary */ +			return p->kids[0]; +		if (p->kids[0] && p->kids[0]->op == RIGHT +		&&  p->kids[1] == p->kids[0]->kids[0]) +			/* de-construct e++ construction */ +			return p->kids[0]->kids[1]; +		p = tree(RIGHT, p->type, root1(p->kids[0]), root1(p->kids[1])); +		return p->kids[0] || p->kids[1] ? p : (Tree)0; +	case EQ:  case NE:  case GT:   case GE:  case LE:  case LT:  +	case ADD: case SUB: case MUL:  case DIV: case MOD: +	case LSH: case RSH: case BAND: case BOR: case BXOR: +		if (warn++ == 0) +			warning("expression with no effect elided\n"); +		p = tree(RIGHT, p->type, root1(p->kids[0]), root1(p->kids[1])); +		return p->kids[0] || p->kids[1] ? p : (Tree)0; +	case INDIR: +		if (p->type->size == 0 && unqual(p->type) != voidtype) +			warning("reference to `%t' elided\n", p->type); +		if (isptr(p->kids[0]->type) && isvolatile(p->kids[0]->type->type)) +			warning("reference to `volatile %t' elided\n", p->type); +		/* fall thru */ +	case CVI: case CVF: case CVU: case CVP: +	case NEG: case BCOM: case FIELD: +		if (warn++ == 0) +			warning("expression with no effect elided\n"); +		return root1(p->kids[0]); +	case ADDRL: case ADDRG: case ADDRF: case CNST: +		if (needconst) +			return p; +		if (warn++ == 0) +			warning("expression with no effect elided\n"); +		return NULL; +	case ARG: case ASGN: case CALL: case JUMP: case LABEL: +		break; +	default: assert(0); +	} +	return p; +} + +Tree root(Tree p) { +	warn = 0; +	return root1(p); +} + +char *opname(int op) { +	static char *opnames[] = { +	"", +	"CNST", +	"ARG", +	"ASGN", +	"INDIR", +	"CVC", +	"CVD", +	"CVF", +	"CVI", +	"CVP", +	"CVS", +	"CVU", +	"NEG", +	"CALL", +	"*LOAD*", +	"RET", +	"ADDRG", +	"ADDRF", +	"ADDRL", +	"ADD", +	"SUB", +	"LSH", +	"MOD", +	"RSH", +	"BAND", +	"BCOM", +	"BOR", +	"BXOR", +	"DIV", +	"MUL", +	"EQ", +	"GE", +	"GT", +	"LE", +	"LT", +	"NE", +	"JUMP", +	"LABEL", +	"AND", +	"NOT", +	"OR", +	"COND", +	"RIGHT", +	"FIELD" +	}, *suffixes[] = { +		"0", "F", "D", "C", "S", "I", "U", "P", "V", "B", +		"10","11","12","13","14","15" +	}; + +	if (generic(op) >= AND && generic(op) <= FIELD && opsize(op) == 0) +		return opnames[opindex(op)]; +	return stringf("%s%s%s", +		opindex(op) > 0 && opindex(op) < NELEMS(opnames) ? +			opnames[opindex(op)] : stringd(opindex(op)), +		suffixes[optype(op)], opsize(op) > 0 ? stringd(opsize(op)) : ""); +} + +int nodeid(Tree p) { +	int i = 1; + +	ids[nid].node = p; +	while (ids[i].node != p) +		i++; +	if (i == nid) +		ids[nid++].printed = 0; +	return i; +} + +/* printed - return pointer to ids[id].printed */ +int *printed(int id) { +	if (id) +		return &ids[id].printed; +	nid = 1; +	return 0; +} + +/* printtree - print tree p on fd */ +void printtree(Tree p, int fd) { +	(void)printed(0); +	printtree1(p, fd, 1); +} + +/* printtree1 - recursively print tree p */ +static void printtree1(Tree p, int fd, int lev) { +	FILE *f = fd == 1 ? stdout : stderr; +	int i; +	static char blanks[] = "                                                   "; + +	if (p == 0 || *printed(i = nodeid(p))) +		return; +	fprint(f, "#%d%S%S", i, blanks, i < 10 ? 2 : i < 100 ? 1 : 0, blanks, lev); +	fprint(f, "%s %t", opname(p->op), p->type); +	*printed(i) = 1; +	for (i = 0; i < NELEMS(p->kids); i++) +		if (p->kids[i]) +			fprint(f, " #%d", nodeid(p->kids[i])); +	if (p->op == FIELD && p->u.field) +		fprint(f, " %s %d..%d", p->u.field->name, +			fieldsize(p->u.field) + fieldright(p->u.field), fieldright(p->u.field)); +	else if (generic(p->op) == CNST) +		fprint(f, " %s", vtoa(p->type, p->u.v)); +	else if (p->u.sym) +		fprint(f, " %s", p->u.sym->name); +	if (p->node) +		fprint(f, " node=%p", p->node); +	fprint(f, "\n"); +	for (i = 0; i < NELEMS(p->kids); i++) +		printtree1(p->kids[i], fd, lev + 1); +} diff --git a/src/tools/lcc/src/types.c b/src/tools/lcc/src/types.c new file mode 100644 index 0000000..4aa3d18 --- /dev/null +++ b/src/tools/lcc/src/types.c @@ -0,0 +1,748 @@ +#include "c.h" +#include <float.h> + + +static Field isfield(const char *, Field); +static Type type(int, Type, int, int, void *); + +static struct entry { +	struct type type; +	struct entry *link; +} *typetable[128]; +static int maxlevel; + +static Symbol pointersym; + +Type chartype;			/* char */ +Type doubletype;		/* double */ +Type floattype;			/* float */ +Type inttype;			/* signed int */ +Type longdouble;		/* long double */ +Type longtype;			/* long */ +Type longlong;			/* long long */ +Type shorttype;			/* signed short int */ +Type signedchar;		/* signed char */ +Type unsignedchar;		/* unsigned char */ +Type unsignedlong;		/* unsigned long int */ +Type unsignedlonglong;		/* unsigned long long int */ +Type unsignedshort;		/* unsigned short int */ +Type unsignedtype;		/* unsigned int */ +Type funcptype;			/* void (*)() */ +Type charptype;			/* char* */ +Type voidptype;			/* void* */ +Type voidtype;			/* basic types: void */ +Type unsignedptr;		/* unsigned type to hold void* */ +Type signedptr;			/* signed type to hold void* */ +Type widechar;			/* unsigned type that represents wchar_t */ + +static Type xxinit(int op, char *name, Metrics m) { +	Symbol p = install(string(name), &types, GLOBAL, PERM); +	Type ty = type(op, 0, m.size, m.align, p); + +	assert(ty->align == 0 || ty->size%ty->align == 0); +	p->type = ty; +	p->addressed = m.outofline; +	switch (ty->op) { +	case INT: +		p->u.limits.max.i = ones(8*ty->size)>>1; +		p->u.limits.min.i = -p->u.limits.max.i - 1; +		break; +	case UNSIGNED: +		p->u.limits.max.u = ones(8*ty->size); +		p->u.limits.min.u = 0; +		break; +	case FLOAT: +		if (ty->size == sizeof (float)) +			p->u.limits.max.d =  FLT_MAX; +		else if (ty->size == sizeof (double)) +			p->u.limits.max.d =  DBL_MAX; +		else +			p->u.limits.max.d = LDBL_MAX; +		p->u.limits.min.d = -p->u.limits.max.d; +		break; +	default: assert(0); +	} +	return ty; +} +static Type type(int op, Type ty, int size, int align, void *sym) { +	unsigned h = (op^((unsigned long)ty>>3)) +&(NELEMS(typetable)-1); +	struct entry *tn; + +	if (op != FUNCTION && (op != ARRAY || size > 0)) +		for (tn = typetable[h]; tn; tn = tn->link) +			if (tn->type.op    == op   && tn->type.type  == ty +			&&  tn->type.size  == size && tn->type.align == align +			&&  tn->type.u.sym == sym) +				return &tn->type; +	NEW0(tn, PERM); +	tn->type.op = op; +	tn->type.type = ty; +	tn->type.size = size; +	tn->type.align = align; +	tn->type.u.sym = sym; +	tn->link = typetable[h]; +	typetable[h] = tn; +	return &tn->type; +} +void type_init(int argc, char *argv[]) { +	static int inited; +	int i; + +	if (inited) +		return; +	inited = 1; +	if (!IR) +		return; +	for (i = 1; i < argc; i++) { +		int size, align, outofline; +		if (strncmp(argv[i], "-unsigned_char=", 15) == 0) +			IR->unsigned_char = argv[i][15] - '0'; +#define xx(name) \ +		else if (sscanf(argv[i], "-" #name "=%d,%d,%d", &size, &align, &outofline) == 3) { \ +			IR->name.size = size; IR->name.align = align; \ +			IR->name.outofline = outofline; } +	xx(charmetric) +	xx(shortmetric) +	xx(intmetric) +	xx(longmetric) +	xx(longlongmetric) +	xx(floatmetric) +	xx(doublemetric) +	xx(longdoublemetric) +	xx(ptrmetric) +	xx(structmetric) +#undef xx +	} +#define xx(v,name,op,metrics) v=xxinit(op,name,IR->metrics) +	xx(chartype,        "char",              IR->unsigned_char ? UNSIGNED : INT,charmetric); +	xx(doubletype,      "double",            FLOAT,   doublemetric); +	xx(floattype,       "float",             FLOAT,   floatmetric); +	xx(inttype,         "int",               INT,     intmetric); +	xx(longdouble,      "long double",       FLOAT,   longdoublemetric); +	xx(longtype,        "long int",          INT,     longmetric); +	xx(longlong,        "long long int",     INT,     longlongmetric); +	xx(shorttype,       "short",             INT,     shortmetric); +	xx(signedchar,      "signed char",       INT,     charmetric); +	xx(unsignedchar,    "unsigned char",     UNSIGNED,charmetric); +	xx(unsignedlong,    "unsigned long",     UNSIGNED,longmetric); +	xx(unsignedshort,   "unsigned short",    UNSIGNED,shortmetric); +	xx(unsignedtype,    "unsigned int",      UNSIGNED,intmetric); +	xx(unsignedlonglong,"unsigned long long",UNSIGNED,longlongmetric); +#undef xx +	{ +		Symbol p; +		p = install(string("void"), &types, GLOBAL, PERM); +		voidtype = type(VOID, NULL, 0, 0, p); +		p->type = voidtype; +	} +	pointersym = install(string("T*"), &types, GLOBAL, PERM); +	pointersym->addressed = IR->ptrmetric.outofline; +	pointersym->u.limits.max.p = (void*)ones(8*IR->ptrmetric.size); +	pointersym->u.limits.min.p = 0; +	voidptype = ptr(voidtype); +	funcptype = ptr(func(voidtype, NULL, 1)); +	charptype = ptr(chartype); +#define xx(v,t) if (v==NULL && t->size==voidptype->size && t->align==voidptype->align) v=t +	xx(unsignedptr,unsignedshort); +	xx(unsignedptr,unsignedtype); +	xx(unsignedptr,unsignedlong); +	xx(unsignedptr,unsignedlonglong); +	if (unsignedptr == NULL) +		unsignedptr = type(UNSIGNED, NULL, voidptype->size, voidptype->align, voidptype->u.sym); +	xx(signedptr,shorttype); +	xx(signedptr,inttype); +	xx(signedptr,longtype); +	xx(signedptr,longlong); +	if (signedptr == NULL) +		signedptr = type(INT, NULL, voidptype->size, voidptype->align, voidptype->u.sym); +#undef xx +	widechar = unsignedshort; +	for (i = 0; i < argc; i++) { +#define xx(name,type) \ +		if (strcmp(argv[i], "-wchar_t=" #name) == 0) \ +			widechar = type; +		xx(unsigned_char,unsignedchar) +		xx(unsigned_int,unsignedtype) +		xx(unsigned_short,unsignedshort) +	} +#undef xx +} +void rmtypes(int lev) { +	if (maxlevel >= lev) { +		int i; +		maxlevel = 0; +		for (i = 0; i < NELEMS(typetable); i++) { +			struct entry *tn, **tq = &typetable[i]; +			while ((tn = *tq) != NULL) +				if (tn->type.op == FUNCTION) +					tq = &tn->link; +				else if (tn->type.u.sym && tn->type.u.sym->scope >= lev) +					*tq = tn->link; +				else { +					if (tn->type.u.sym && tn->type.u.sym->scope > maxlevel) +						maxlevel = tn->type.u.sym->scope; +					tq = &tn->link; +				} + +		} +	} +} +Type ptr(Type ty) { +	return type(POINTER, ty, IR->ptrmetric.size, +		IR->ptrmetric.align, pointersym); +} +Type deref(Type ty) { +	if (isptr(ty)) +		ty = ty->type; +	else +		error("type error: %s\n", "pointer expected"); +	return isenum(ty) ? unqual(ty)->type : ty; +} +Type array(Type ty, int n, int a) { +	assert(ty); +	if (isfunc(ty)) { +		error("illegal type `array of %t'\n", ty); +		return array(inttype, n, 0); +	} +	if (isarray(ty) && ty->size == 0) +		error("missing array size\n"); +	if (ty->size == 0) { +		if (unqual(ty) == voidtype) +			error("illegal type `array of %t'\n", ty); +		else if (Aflag >= 2) +			warning("declaring type array of %t' is undefined\n", ty); + +	} else if (n > INT_MAX/ty->size) { +		error("size of `array of %t' exceeds %d bytes\n", +			ty, INT_MAX); +		n = 1; +	} +	return type(ARRAY, ty, n*ty->size, +		a ? a : ty->align, NULL); +} +Type atop(Type ty) { +	if (isarray(ty)) +		return ptr(ty->type); +	error("type error: %s\n", "array expected"); +	return ptr(ty); +} +Type qual(int op, Type ty) { +	if (isarray(ty)) +		ty = type(ARRAY, qual(op, ty->type), ty->size, +			ty->align, NULL); +	else if (isfunc(ty)) +		warning("qualified function type ignored\n"); +	else if ((isconst(ty)    && op == CONST) +	||       (isvolatile(ty) && op == VOLATILE)) +		error("illegal type `%k %t'\n", op, ty); +	else { +		if (isqual(ty)) { +			op += ty->op; +			ty = ty->type; +		} +		ty = type(op, ty, ty->size, ty->align, NULL); +	} +	return ty; +} +Type func(Type ty, Type *proto, int style) { +	if (ty && (isarray(ty) || isfunc(ty))) +		error("illegal return type `%t'\n", ty); +	ty = type(FUNCTION, ty, 0, 0, NULL); +	ty->u.f.proto = proto; +	ty->u.f.oldstyle = style; +	return ty; +} +Type freturn(Type ty) { +	if (isfunc(ty)) +		return ty->type; +	error("type error: %s\n", "function expected"); +	return inttype; +} +int variadic(Type ty) { +	if (isfunc(ty) && ty->u.f.proto) { +		int i; +		for (i = 0; ty->u.f.proto[i]; i++) +			; +		return i > 1 && ty->u.f.proto[i-1] == voidtype; +	} +	return 0; +} +Type newstruct(int op, char *tag) { +	Symbol p; + +	assert(tag); +	if (*tag == 0) +		tag = stringd(genlabel(1)); +	else +		if ((p = lookup(tag, types)) != NULL && (p->scope == level +		|| (p->scope == PARAM && level == PARAM+1))) { +			if (p->type->op == op && !p->defined) +				return p->type; +			error("redefinition of `%s' previously defined at %w\n", +				p->name, &p->src); +		} +	p = install(tag, &types, level, PERM); +	p->type = type(op, NULL, 0, 0, p); +	if (p->scope > maxlevel) +		maxlevel = p->scope; +	p->src = src; +	return p->type; +} +Field newfield(char *name, Type ty, Type fty) { +	Field p, *q = &ty->u.sym->u.s.flist; + +	if (name == NULL) +		name = stringd(genlabel(1)); +	for (p = *q; p; q = &p->link, p = *q) +		if (p->name == name) +			error("duplicate field name `%s' in `%t'\n", +				name, ty); +	NEW0(p, PERM); +	*q = p; +	p->name = name; +	p->type = fty; +	if (xref) {							/* omit */ +		if (ty->u.sym->u.s.ftab == NULL)			/* omit */ +			ty->u.sym->u.s.ftab = table(NULL, level);	/* omit */ +		install(name, &ty->u.sym->u.s.ftab, 0, PERM)->src = src;/* omit */ +	}								/* omit */ +	return p; +} +int eqtype(Type ty1, Type ty2, int ret) { +	if (ty1 == ty2) +		return 1; +	if (ty1->op != ty2->op) +		return 0; +	switch (ty1->op) { +	case ENUM: case UNION: case STRUCT: +	case UNSIGNED: case INT: case FLOAT: +		return 0; +	case POINTER:  return eqtype(ty1->type, ty2->type, 1); +	case VOLATILE: case CONST+VOLATILE: +	case CONST:    return eqtype(ty1->type, ty2->type, 1); +	case ARRAY:    if (eqtype(ty1->type, ty2->type, 1)) { +		       	if (ty1->size == ty2->size) +		       		return 1; +		       	if (ty1->size == 0 || ty2->size == 0) +		       		return ret; +		       } +		       return 0; +	case FUNCTION: if (eqtype(ty1->type, ty2->type, 1)) { +		       	Type *p1 = ty1->u.f.proto, *p2 = ty2->u.f.proto; +		       	if (p1 == p2) +		       		return 1; +		       	if (p1 && p2) { +		       		for ( ; *p1 && *p2; p1++, p2++) +					if (eqtype(unqual(*p1), unqual(*p2), 1) == 0) +						return 0; +				if (*p1 == NULL && *p2 == NULL) +					return 1; +		       	} else { +		       		if (variadic(p1 ? ty1 : ty2)) +					return 0; +				if (p1 == NULL) +					p1 = p2; +				for ( ; *p1; p1++) { +					Type ty = unqual(*p1); +					if (promote(ty) != (isenum(ty) ? ty->type : ty)) +						return 0; +				} +				return 1; +		       	} +		       } +		       return 0; +	} +	assert(0); return 0; +} +Type promote(Type ty) { +	ty = unqual(ty); +	switch (ty->op) { +	case ENUM: +		return inttype; +	case INT: +		if (ty->size < inttype->size) +			return inttype; +		break; +	case UNSIGNED: +		if (ty->size < inttype->size) +			return inttype; +		if (ty->size < unsignedtype->size) +			return unsignedtype; +		break; +	case FLOAT: +		if (ty->size < doubletype->size) +			return doubletype; +	} +	return ty; +} +Type signedint(Type ty) { +	if (ty->op == INT) +		return ty; +	assert(ty->op == UNSIGNED); +#define xx(t) if (ty->size == t->size) return t +	xx(inttype); +	xx(longtype); +	xx(longlong); +#undef xx +	assert(0); return NULL; +} +Type compose(Type ty1, Type ty2) { +	if (ty1 == ty2) +		return ty1; +	assert(ty1->op == ty2->op); +	switch (ty1->op) { +	case POINTER: +		return ptr(compose(ty1->type, ty2->type)); +	case CONST+VOLATILE: +		return qual(CONST, qual(VOLATILE, +			compose(ty1->type, ty2->type))); +	case CONST: case VOLATILE: +		return qual(ty1->op, compose(ty1->type, ty2->type)); +	case ARRAY:    { Type ty = compose(ty1->type, ty2->type); +			 if (ty1->size && ((ty1->type->size && ty2->size == 0) || ty1->size == ty2->size)) +			 	return array(ty, ty1->size/ty1->type->size, ty1->align); +			 if (ty2->size && ty2->type->size && ty1->size == 0) +			 	return array(ty, ty2->size/ty2->type->size, ty2->align); +			 return array(ty, 0, 0);    } +	case FUNCTION: { Type *p1  = ty1->u.f.proto, *p2 = ty2->u.f.proto; +			 Type ty   = compose(ty1->type, ty2->type); +			 List tlist = NULL; +			 if (p1 == NULL && p2 == NULL) +			 	return func(ty, NULL, 1); +			 if (p1 && p2 == NULL) +			 	return func(ty, p1, ty1->u.f.oldstyle); +			 if (p2 && p1 == NULL) +			 	return func(ty, p2, ty2->u.f.oldstyle); +			 for ( ; *p1 && *p2; p1++, p2++) { +			 	Type ty = compose(unqual(*p1), unqual(*p2)); +			 	if (isconst(*p1)    || isconst(*p2)) +			 		ty = qual(CONST, ty); +			 	if (isvolatile(*p1) || isvolatile(*p2)) +			 		ty = qual(VOLATILE, ty); +			 	tlist = append(ty, tlist); +			 } +			 assert(*p1 == NULL && *p2 == NULL); +			 return func(ty, ltov(&tlist, PERM), 0); } +	} +	assert(0); return NULL; +} +int ttob(Type ty) { +	switch (ty->op) { +	case CONST: case VOLATILE: case CONST+VOLATILE: +		return ttob(ty->type); +	case VOID: case INT: case UNSIGNED: case FLOAT: +		return ty->op + sizeop(ty->size); +	case POINTER: +		return POINTER + sizeop(voidptype->size); +	case FUNCTION: +		return POINTER + sizeop(funcptype->size); +	case ARRAY: case STRUCT: case UNION: +		return STRUCT; +	case ENUM: +		return INT + sizeop(inttype->size); +	} +	assert(0); return INT; +} +Type btot(int op, int size) { +#define xx(ty) if (size == (ty)->size) return ty; +	switch (optype(op)) { +	case F: +		xx(floattype); +		xx(doubletype); +		xx(longdouble); +		assert(0); return 0; +	case I: +		if (chartype->op == INT) +			xx(chartype); +		xx(signedchar); +		xx(shorttype); +		xx(inttype); +		xx(longtype); +		xx(longlong); +		assert(0); return 0; +	case U: +		if (chartype->op == UNSIGNED) +			xx(chartype); +		xx(unsignedchar); +		xx(unsignedshort); +		xx(unsignedtype); +		xx(unsignedlong); +		xx(unsignedlonglong); +		assert(0); return 0; +	case P: +		xx(voidptype); +		xx(funcptype); +		assert(0); return 0; +	} +#undef xx +	assert(0); return 0; +} +int hasproto(Type ty) { +	if (ty == 0) +		return 1; +	switch (ty->op) { +	case CONST: case VOLATILE: case CONST+VOLATILE: case POINTER: +	case ARRAY: +		return hasproto(ty->type); +	case FUNCTION: +		return hasproto(ty->type) && ty->u.f.proto; +	case STRUCT: case UNION: +	case VOID:   case FLOAT: case ENUM:  case INT: case UNSIGNED: +		return 1; +	} +	assert(0); return 0; +} +/* fieldlist - construct a flat list of fields in type ty */ +Field fieldlist(Type ty) { +	return ty->u.sym->u.s.flist; +} + +/* fieldref - find field name of type ty, return entry */ +Field fieldref(const char *name, Type ty) { +	Field p = isfield(name, unqual(ty)->u.sym->u.s.flist); + +	if (p && xref) { +		Symbol q; +		assert(unqual(ty)->u.sym->u.s.ftab); +		q = lookup(name, unqual(ty)->u.sym->u.s.ftab); +		assert(q); +		use(q, src); +	} +	return p; +} + +/* ftype - return a function type for rty function (ty,...)' */ +Type ftype(Type rty, Type ty) { +	List list = append(ty, NULL); + +	list = append(voidtype, list); +	return func(rty, ltov(&list, PERM), 0); +} + +/* isfield - if name is a field in flist, return pointer to the field structure */ +static Field isfield(const char *name, Field flist) { +	for ( ; flist; flist = flist->link) +		if (flist->name == name) +			break; +	return flist; +} + +/* outtype - output type ty */ +void outtype(Type ty, FILE *f) { +	switch (ty->op) { +	case CONST+VOLATILE: case CONST: case VOLATILE: +		fprint(f, "%k %t", ty->op, ty->type); +		break; +	case STRUCT: case UNION: case ENUM: +		assert(ty->u.sym); +		if (ty->size == 0) +			fprint(f, "incomplete "); +		assert(ty->u.sym->name); +		if (*ty->u.sym->name >= '1' && *ty->u.sym->name <= '9') { +			Symbol p = findtype(ty); +			if (p == 0) +				fprint(f, "%k defined at %w", ty->op, &ty->u.sym->src); +			else +				fprint(f, p->name); +		} else { +			fprint(f, "%k %s", ty->op, ty->u.sym->name); +			if (ty->size == 0) +				fprint(f, " defined at %w", &ty->u.sym->src); +		} +		break; +	case VOID: case FLOAT: case INT: case UNSIGNED: +		fprint(f, ty->u.sym->name); +		break; +	case POINTER: +		fprint(f, "pointer to %t", ty->type); +		break; +	case FUNCTION: +		fprint(f, "%t function", ty->type); +		if (ty->u.f.proto && ty->u.f.proto[0]) { +			int i; +			fprint(f, "(%t", ty->u.f.proto[0]); +			for (i = 1; ty->u.f.proto[i]; i++) +				if (ty->u.f.proto[i] == voidtype) +					fprint(f, ",..."); +				else +					fprint(f, ",%t", ty->u.f.proto[i]); +			fprint(f, ")"); +		} else if (ty->u.f.proto && ty->u.f.proto[0] == 0) +			fprint(f, "(void)"); + +		break; +	case ARRAY: +		if (ty->size > 0 && ty->type && ty->type->size > 0) { +			fprint(f, "array %d", ty->size/ty->type->size); +			while (ty->type && isarray(ty->type) && ty->type->type->size > 0) { +				ty = ty->type; +				fprint(f, ",%d", ty->size/ty->type->size); +			} +		} else +			fprint(f, "incomplete array"); +		if (ty->type) +			fprint(f, " of %t", ty->type); +		break; +	default: assert(0); +	} +} + +/* printdecl - output a C declaration for symbol p of type ty */ +void printdecl(Symbol p, Type ty) { +	switch (p->sclass) { +	case AUTO: +		fprint(stderr, "%s;\n", typestring(ty, p->name)); +		break; +	case STATIC: case EXTERN: +		fprint(stderr, "%k %s;\n", p->sclass, typestring(ty, p->name)); +		break; +	case TYPEDEF: case ENUM: +		break; +	default: assert(0); +	} +} + +/* printproto - output a prototype declaration for function p */ +void printproto(Symbol p, Symbol callee[]) { +	if (p->type->u.f.proto) +		printdecl(p, p->type); +	else { +		int i; +		List list = 0; +		if (callee[0] == 0) +			list = append(voidtype, list); +		else +			for (i = 0; callee[i]; i++) +				list = append(callee[i]->type, list); +		printdecl(p, func(freturn(p->type), ltov(&list, PERM), 0)); +	} +} + +/* prtype - print details of type ty on f with given indent */ +static void prtype(Type ty, FILE *f, int indent, unsigned mark) { +	switch (ty->op) { +	default: +		fprint(f, "(%d %d %d [%p])", ty->op, ty->size, ty->align, ty->u.sym); +		break; +	case FLOAT: case INT: case UNSIGNED: case VOID: +		fprint(f, "(%k %d %d [\"%s\"])", ty->op, ty->size, ty->align, ty->u.sym->name); +		break; +	case CONST+VOLATILE: case CONST: case VOLATILE: case POINTER: case ARRAY: +		fprint(f, "(%k %d %d ", ty->op, ty->size, ty->align); +		prtype(ty->type, f, indent+1, mark); +		fprint(f, ")"); +		break; +	case STRUCT: case UNION: +		fprint(f, "(%k %d %d [\"%s\"]", ty->op, ty->size, ty->align, ty->u.sym->name); +		if (ty->x.marked != mark) { +			Field p; +			ty->x.marked = mark; +			for (p = ty->u.sym->u.s.flist; p; p = p->link) { +				fprint(f, "\n%I", indent+1); +				prtype(p->type, f, indent+1, mark); +				fprint(f, " %s@%d", p->name, p->offset); +				if (p->lsb) +					fprint(f, ":%d..%d", +						fieldsize(p) + fieldright(p), fieldright(p)); +			} +			fprint(f, "\n%I", indent); +		} +		fprint(f, ")"); +		break; +	case ENUM: +		fprint(f, "(%k %d %d [\"%s\"]", ty->op, ty->size, ty->align, ty->u.sym->name); +		if (ty->x.marked != mark) { +			int i; +			Symbol *p = ty->u.sym->u.idlist; +			ty->x.marked = mark; +			for (i = 0; p[i] != NULL; i++) +				fprint(f, "%I%s=%d\n", indent+1, p[i]->name, p[i]->u.value); +		} +		fprint(f, ")"); +		break; +	case FUNCTION: +		fprint(f, "(%k %d %d ", ty->op, ty->size, ty->align); +		prtype(ty->type, f, indent+1, mark); +		if (ty->u.f.proto) { +			int i; +			fprint(f, "\n%I{", indent+1); +			for (i = 0; ty->u.f.proto[i]; i++) { +				if (i > 0) +					fprint(f, "%I", indent+2); +				prtype(ty->u.f.proto[i], f, indent+2, mark); +				fprint(f, "\n"); +			} +			fprint(f, "%I}", indent+1); +		} +		fprint(f, ")"); +		break; +	} +} + +/* printtype - print details of type ty on fd */ +void printtype(Type ty, int fd) { +	static unsigned mark; +	prtype(ty, fd == 1 ? stdout : stderr, 0, ++mark); +	fprint(fd == 1 ? stdout : stderr, "\n"); +} + +/* typestring - return ty as C declaration for str, which may be "" */ +char *typestring(Type ty, char *str) { +	for ( ; ty; ty = ty->type) { +		Symbol p; +		switch (ty->op) { +		case CONST+VOLATILE: case CONST: case VOLATILE: +			if (isptr(ty->type)) +				str = stringf("%k %s", ty->op, str); +			else +				return stringf("%k %s", ty->op, typestring(ty->type, str)); +			break; +		case STRUCT: case UNION: case ENUM: +			assert(ty->u.sym); +			if ((p = findtype(ty)) != NULL) +				return *str ? stringf("%s %s", p->name, str) : p->name; +			if (*ty->u.sym->name >= '1' && *ty->u.sym->name <= '9') +				warning("unnamed %k in prototype\n", ty->op); +			if (*str) +				return stringf("%k %s %s", ty->op, ty->u.sym->name, str); +			else +				return stringf("%k %s", ty->op, ty->u.sym->name); +		case VOID: case FLOAT: case INT: case UNSIGNED: +			return *str ? stringf("%s %s", ty->u.sym->name, str) : ty->u.sym->name; +		case POINTER: +			if (!ischar(ty->type) && (p = findtype(ty)) != NULL) +				return *str ? stringf("%s %s", p->name, str) : p->name; +			str = stringf(isarray(ty->type) || isfunc(ty->type) ? "(*%s)" : "*%s", str); +			break; +		case FUNCTION: +			if ((p = findtype(ty)) != NULL) +				return *str ? stringf("%s %s", p->name, str) : p->name; +			if (ty->u.f.proto == 0) +				str = stringf("%s()", str); +			else if (ty->u.f.proto[0]) { +				int i; +				str = stringf("%s(%s", str, typestring(ty->u.f.proto[0], "")); +				for (i = 1; ty->u.f.proto[i]; i++) +					if (ty->u.f.proto[i] == voidtype) +						str = stringf("%s, ...", str); +					else +						str = stringf("%s, %s", str, typestring(ty->u.f.proto[i], "")); +				str = stringf("%s)", str); +			} else +				str = stringf("%s(void)", str); +			break; +		case ARRAY: +			if ((p = findtype(ty)) != NULL) +				return *str ? stringf("%s %s", p->name, str) : p->name; +			if (ty->type && ty->type->size > 0) +				str = stringf("%s[%d]", str, ty->size/ty->type->size); +			else +				str = stringf("%s[]", str); +			break; +		default: assert(0); +		} +	} +	assert(0); return 0; +} +  | 
